mxc_fec_reg_write(hw_reg, paur, value << 16);
}
-/*!
- * This function enables the FEC for reception of packets
- */
-static void
-mxc_fec_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
-{
- mxc_fec_priv_t *priv = sc ? sc->driver_private : NULL;
- volatile mxc_fec_reg_t *hw_reg = priv ? priv->hw_reg : NULL;
-
- if (!(priv && hw_reg)) {
- diag_printf("BUG[start]: FEC driver not initialized\n");
- return;
- }
- if (enaddr == NULL) {
- diag_printf("BUG[start]: no MAC address supplied\n");
- return;
- }
- mxc_fec_set_mac_address(hw_reg, enaddr);
-
- priv->tx_busy = 0;
- mxc_fec_reg_write(hw_reg, rdar, mxc_fec_reg_read(hw_reg, rdar) | FEC_RX_TX_ACTIVE);
- mxc_fec_reg_write(hw_reg, ecr, mxc_fec_reg_read(hw_reg, ecr) | FEC_ETHER_EN);
#ifdef CYGPKG_HAL_ARM_MX25
+static int mxc_fec_mii_setup(mxc_fec_priv_t *priv)
+{
+ volatile mxc_fec_reg_t *hw_reg = priv->hw_reg;
/*
* setup the MII gasket for RMII mode
*/
hal_delay_us(FEC_COMMON_TICK);
/* configure gasket for RMII, 50 MHz, no loopback, and no echo */
- mxc_fec_reg_write16(hw_reg, miigsk_cfgr, MIIGSK_CFGR_IF_MODE_RMII);
+ mxc_fec_reg_write16(hw_reg, miigsk_cfgr, MIIGSK_CFGR_IF_MODE_RMII |
+ ((!priv || (priv->status & FEC_STATUS_100M)) ?
+ 0 : MIIGSK_CFGR_FRCONT));
/* re-enable the gasket */
mxc_fec_reg_write16(hw_reg, miigsk_enr, MIIGSK_ENR_EN);
while ((mxc_fec_reg_read16(hw_reg, miigsk_enr) & MIIGSK_ENR_READY) == 0) {
if (--max_loops <= 0) {
diag_printf("WAIT for MII Gasket ready timed out\n");
- break;
+ return -1;
}
}
+ return 0;
+}
+#else
+static inline int mxc_fec_mii_setup(mxc_fec_priv_t *priv)
+{
+ return 0;
+}
#endif
+
+/*!
+ * This function enables the FEC for reception of packets
+ */
+static void
+mxc_fec_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
+{
+ mxc_fec_priv_t *priv = sc ? sc->driver_private : NULL;
+ volatile mxc_fec_reg_t *hw_reg = priv ? priv->hw_reg : NULL;
+
+ if (!(priv && hw_reg)) {
+ diag_printf("BUG[start]: FEC driver not initialized\n");
+ return;
+ }
+ if (enaddr == NULL) {
+ diag_printf("BUG[start]: no MAC address supplied\n");
+ return;
+ }
+ mxc_fec_set_mac_address(hw_reg, enaddr);
+
+ priv->tx_busy = 0;
+ mxc_fec_reg_write(hw_reg, rdar, mxc_fec_reg_read(hw_reg, rdar) | FEC_RX_TX_ACTIVE);
+ mxc_fec_reg_write(hw_reg, ecr, mxc_fec_reg_read(hw_reg, ecr) | FEC_ETHER_EN);
}
/*!
volatile mxc_fec_reg_t *hw_reg = priv ? priv->hw_reg : NULL;
unsigned long value;
int dbg = net_debug;
+ static unsigned long last_poll;
+ int poll_intvl = (priv->status & FEC_STATUS_LINK_ON) ? 100 : 10;
if (priv == NULL || hw_reg == NULL) {
diag_printf("BUG[POLL]: FEC driver not initialized\n");
priv->tx_busy = 0;
} else {
if (value & FEC_EVENT_TX) {
+ last_poll = 0;
sc->funs->eth_drv->tx_done(sc, priv->tx_key, 0);
priv->tx_busy = 0;
}
}
-
if (value & FEC_EVENT_RX) {
+ last_poll = 0;
mxc_fec_check_rx_bd(sc);
}
if (value & FEC_EVENT_HBERR) {
- diag_printf("WARNGING[POLL]: Hearbeat error!\n");
+ diag_printf("WARNGING[POLL]: Heartbeat error!\n");
}
if (value & FEC_EVENT_EBERR) {
diag_printf("WARNING[POLL]: Ethernet Bus Error!\n");
}
+
+ if (value & (FEC_EVENT_TX_ERR | FEC_EVENT_HBERR | FEC_EVENT_EBERR) ||
+ last_poll++ > poll_intvl) {
+#ifdef CYGPKG_DEVS_ETH_PHY
+ unsigned short value;
+ value = _eth_phy_state(priv->phy);
+#else
+ unsigned short value;
+ mxc_fec_mii_read(hw_reg, priv->phy_addr, 1, &value);
+#endif
+ last_poll = 0;
+ if (value & PHY_STATUS_LINK_ST) {
+ if (!(priv->status & FEC_STATUS_LINK_ON)) {
+ mxc_fec_phy_status(priv, value, true);
+ }
+ } else {
+ if (priv->status & FEC_STATUS_LINK_ON) {
+ mxc_fec_phy_status(priv, value, true);
+ }
+ }
+ }
}
static int
{
#ifdef CYGPKG_DEVS_ETH_PHY
if (value & ETH_PHY_STAT_LINK) {
+ int changed = !(dev->status & FEC_STATUS_LINK_ON);
+
dev->status |= FEC_STATUS_LINK_ON;
if (value & ETH_PHY_STAT_FDX) {
dev->status |= FEC_STATUS_FULL_DPLX;
dev->status &= ~FEC_STATUS_FULL_DPLX;
}
if (value & ETH_PHY_STAT_100MB) {
+ changed |= !(dev->status & ETH_PHY_STAT_100MB);
dev->status |= FEC_STATUS_100M;
} else {
+ changed |= !!(dev->status & ETH_PHY_STAT_100MB);
dev->status &= ~FEC_STATUS_100M;
}
+ if (changed) {
+ mxc_fec_mii_setup(dev);
+ }
} else {
dev->status &= ~FEC_STATUS_LINK_ON;
}
#else
+ int changed = 0;
mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_STATUS_REG, &value);
if (value & PHY_STATUS_LINK_ST) {
+ changed |= !(dev->status & FEC_STATUS_LINK_ON);
dev->status |= FEC_STATUS_LINK_ON;
} else {
+ changed |= dev->status & FEC_STATUS_LINK_ON;
dev->status &= ~FEC_STATUS_LINK_ON;
}
dev->status &= ~FEC_STATUS_FULL_DPLX;
}
if (value & PHY_DIAG_RATE) {
+ changed |= !(dev->status & FEC_STATUS_100M);
dev->status |= FEC_STATUS_100M;
} else {
+ changed |= dev->status & FEC_STATUS_100M;
dev->status &= ~FEC_STATUS_100M;
}
+ if (changed) {
+ mxc_fec_mii_setup(dev);
+ }
#endif
if (!show) {
return;