📄 smc911x.c
字号:
#define MII_DATA 0x07 /* R/W mask 0x0000FFFFUL */#define FLOW 0x08 /* R/W */#define FLOW_FCPT 0xFFFF0000#define FLOW_FCPASS 0x00000004#define FLOW_FCEN 0x00000002#define FLOW_FCBSY 0x00000001#define VLAN1 0x09 /* R/W mask 0x0000FFFFUL */#define VLAN1_VTI1 0x0000ffff#define VLAN2 0x0A /* R/W mask 0x0000FFFFUL */#define VLAN2_VTI2 0x0000ffff#define WUFF 0x0B /* WO */#define WUCSR 0x0C /* R/W */#define WUCSR_GUE 0x00000200#define WUCSR_WUFR 0x00000040#define WUCSR_MPR 0x00000020#define WUCSR_WAKE_EN 0x00000004#define WUCSR_MPEN 0x00000002/* Chip ID values */#define CHIP_9115 0x115#define CHIP_9116 0x116#define CHIP_9117 0x117#define CHIP_9118 0x118#define CHIP_9215 0x115a#define CHIP_9216 0x116a#define CHIP_9217 0x117a#define CHIP_9218 0x118astruct chip_id { u16 id; char *name;};static const struct chip_id chip_ids[] = { { CHIP_9115, "LAN9115" }, { CHIP_9116, "LAN9116" }, { CHIP_9117, "LAN9117" }, { CHIP_9118, "LAN9118" }, { CHIP_9215, "LAN9215" }, { CHIP_9216, "LAN9216" }, { CHIP_9217, "LAN9217" }, { CHIP_9218, "LAN9218" }, { 0, NULL },};#define DRIVERNAME "smc911x"u32 smc911x_get_mac_csr(u8 reg){ while (reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) ; reg_write(MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | MAC_CSR_CMD_R_NOT_W | reg); while (reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) ; return reg_read(MAC_CSR_DATA);}void smc911x_set_mac_csr(u8 reg, u32 data){ while (reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) ; reg_write(MAC_CSR_DATA, data); reg_write(MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | reg); while (reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) ;}static int smx911x_handle_mac_address(bd_t *bd){ unsigned long addrh, addrl; unsigned char *m = bd->bi_enetaddr; /* if the environment has a valid mac address then use it */ if ((m[0] | m[1] | m[2] | m[3] | m[4] | m[5])) { addrl = m[0] | m[1] << 8 | m[2] << 16 | m[3] << 24; addrh = m[4] | m[5] << 8; smc911x_set_mac_csr(ADDRH, addrh); smc911x_set_mac_csr(ADDRL, addrl); } else { /* if not, try to get one from the eeprom */ addrh = smc911x_get_mac_csr(ADDRH); addrl = smc911x_get_mac_csr(ADDRL); m[0] = (addrl ) & 0xff; m[1] = (addrl >> 8 ) & 0xff; m[2] = (addrl >> 16 ) & 0xff; m[3] = (addrl >> 24 ) & 0xff; m[4] = (addrh ) & 0xff; m[5] = (addrh >> 8 ) & 0xff; /* we get 0xff when there is no eeprom connected */ if ((m[0] & m[1] & m[2] & m[3] & m[4] & m[5]) == 0xff) { printf(DRIVERNAME ": no valid mac address in environment " "and no eeprom found\n"); return -1; } } printf(DRIVERNAME ": MAC %02x:%02x:%02x:%02x:%02x:%02x\n", m[0], m[1], m[2], m[3], m[4], m[5]); return 0;}static int smc911x_miiphy_read(u8 phy, u8 reg, u16 *val){ while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY) ; smc911x_set_mac_csr(MII_ACC, phy << 11 | reg << 6 | MII_ACC_MII_BUSY); while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY) ; *val = smc911x_get_mac_csr(MII_DATA); return 0;}static int smc911x_miiphy_write(u8 phy, u8 reg, u16 val){ while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY) ; smc911x_set_mac_csr(MII_DATA, val); smc911x_set_mac_csr(MII_ACC, phy << 11 | reg << 6 | MII_ACC_MII_BUSY | MII_ACC_MII_WRITE); while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY) ; return 0;}static int smc911x_phy_reset(void){ u32 reg; reg = reg_read(PMT_CTRL); reg &= ~0xfffff030; reg |= PMT_CTRL_PHY_RST; reg_write(PMT_CTRL, reg); mdelay(100); return 0;}static void smc911x_phy_configure(void){ int timeout; u16 status; smc911x_phy_reset(); smc911x_miiphy_write(1, PHY_BMCR, PHY_BMCR_RESET); mdelay(1); smc911x_miiphy_write(1, PHY_ANAR, 0x01e1); smc911x_miiphy_write(1, PHY_BMCR, PHY_BMCR_AUTON | PHY_BMCR_RST_NEG); timeout = 5000; do { mdelay(1); if ((timeout--) == 0) goto err_out; if (smc911x_miiphy_read(1, PHY_BMSR, &status) != 0) goto err_out; } while (!(status & PHY_BMSR_LS)); printf(DRIVERNAME ": phy initialized\n"); return;err_out: printf(DRIVERNAME ": autonegotiation timed out\n");}static void smc911x_reset(void){ int timeout; /* Take out of PM setting first */ if (reg_read(PMT_CTRL) & PMT_CTRL_READY) { /* Write to the bytetest will take out of powerdown */ reg_write(BYTE_TEST, 0x0); timeout = 10; while (timeout-- && !(reg_read(PMT_CTRL) & PMT_CTRL_READY)) udelay(10); if (!timeout) { printf(DRIVERNAME ": timeout waiting for PM restore\n"); return; } } /* Disable interrupts */ reg_write(INT_EN, 0); reg_write(HW_CFG, HW_CFG_SRST); timeout = 1000; while (timeout-- && reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY) udelay(10); if (!timeout) { printf(DRIVERNAME ": reset timeout\n"); return; } /* Reset the FIFO level and flow control settings */ smc911x_set_mac_csr(FLOW, FLOW_FCPT | FLOW_FCEN); reg_write(AFC_CFG, 0x0050287F); /* Set to LED outputs */ reg_write(GPIO_CFG, 0x70070000);}static void smc911x_enable(void){ /* Enable TX */ reg_write(HW_CFG, 8 << 16 | HW_CFG_SF); reg_write(GPT_CFG, GPT_CFG_TIMER_EN | 10000); reg_write(TX_CFG, TX_CFG_TX_ON); /* no padding to start of packets */ reg_write(RX_CFG, 0); smc911x_set_mac_csr(MAC_CR, MAC_CR_TXEN | MAC_CR_RXEN | MAC_CR_HBDIS);}int eth_init(bd_t *bd){ unsigned long val, i; printf(DRIVERNAME ": initializing\n"); val = reg_read(BYTE_TEST); if (val != 0x87654321) { printf(DRIVERNAME ": Invalid chip endian 0x%08lx\n", val); goto err_out; } val = reg_read(ID_REV) >> 16; for (i = 0; chip_ids[i].id != 0; i++) { if (chip_ids[i].id == val) break; } if (!chip_ids[i].id) { printf(DRIVERNAME ": Unknown chip ID %04lx\n", val); goto err_out; } printf(DRIVERNAME ": detected %s controller\n", chip_ids[i].name); smc911x_reset(); /* Configure the PHY, initialize the link state */ smc911x_phy_configure(); if (smx911x_handle_mac_address(bd)) goto err_out; /* Turn on Tx + Rx */ smc911x_enable(); return 0;err_out: return -1;}int eth_send(volatile void *packet, int length){ u32 *data = (u32*)packet; u32 tmplen; u32 status; reg_write(TX_DATA_FIFO, TX_CMD_A_INT_FIRST_SEG | TX_CMD_A_INT_LAST_SEG | length); reg_write(TX_DATA_FIFO, length); tmplen = (length + 3) / 4; while (tmplen--) reg_write(TX_DATA_FIFO, *data++); /* wait for transmission */ while (!((reg_read(TX_FIFO_INF) & TX_FIFO_INF_TSUSED) >> 16)); /* get status. Ignore 'no carrier' error, it has no meaning for * full duplex operation */ status = reg_read(TX_STATUS_FIFO) & (TX_STS_LOC | TX_STS_LATE_COLL | TX_STS_MANY_COLL | TX_STS_MANY_DEFER | TX_STS_UNDERRUN); if (!status) return 0; printf(DRIVERNAME ": failed to send packet: %s%s%s%s%s\n", status & TX_STS_LOC ? "TX_STS_LOC " : "", status & TX_STS_LATE_COLL ? "TX_STS_LATE_COLL " : "", status & TX_STS_MANY_COLL ? "TX_STS_MANY_COLL " : "", status & TX_STS_MANY_DEFER ? "TX_STS_MANY_DEFER " : "", status & TX_STS_UNDERRUN ? "TX_STS_UNDERRUN" : ""); return -1;}void eth_halt(void){ smc911x_reset();}int eth_rx(void){ u32 *data = (u32 *)NetRxPackets[0]; u32 pktlen, tmplen; u32 status; if ((reg_read(RX_FIFO_INF) & RX_FIFO_INF_RXSUSED) >> 16) { status = reg_read(RX_STATUS_FIFO); pktlen = (status & RX_STS_PKT_LEN) >> 16; reg_write(RX_CFG, 0); tmplen = (pktlen + 2+ 3) / 4; while (tmplen--) *data++ = reg_read(RX_DATA_FIFO); if (status & RX_STS_ES) printf(DRIVERNAME ": dropped bad packet. Status: 0x%08x\n", status); else NetReceive(NetRxPackets[0], pktlen); } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -