?? smc9118.c
字號:
__inline void smsc9118_init_irqs(void){ *SMSC9118_INT_EN = 0; *SMSC9118_INT_STS = 0xFFFFFFFF; *SMSC9118_IRQ_CFG = 0x22000100; //irq deassertion at 220 usecs.}/* * If ethaddr environment variable has a valid values, set the MAC address to it, * otherwise check that the MAC address loaded in the smc9118 is valid * Note that we do not change the value of the MAC address stored in the smc9118 EEPROM (the auto-loaded MAC) * * Datasheet has 12:34:56:78:9A:BC stored as ADDRH 0xBC9A * ADDRH 0x....BC9A * ADDRL 0x12345678 * 0x12 transmitted first * This code gets them in the same order in the TX buffer as the smc91111 * * Returns 1 on success */int smc9118_set_valid_ethaddr(void){ unsigned int mac_low; unsigned int mac_high; uchar mac[6]; int env_size = 0, env_present = 0, reg; char *s = NULL, *endp, dummy_mac[] = "11:22:33:44:55:66"; char s_env_mac[0x18]; /* Try for ethadd from environment */ env_size = getenv_r ("ethaddr", s_env_mac, sizeof (s_env_mac)); if ((env_size > 0) && (env_size != sizeof (dummy_mac))) { /* exit if env is bad */ printf ("\n*** ERROR: ethaddr is not set properly!!\n"); } else { env_present = 1; } if (env_present) { s = s_env_mac; /* Environment string to mac numbers */ for (reg = 0; reg < 6; ++reg) { mac[reg] = s ? simple_strtoul (s, &endp, 16) : 0; if (s) s = (*endp) ? endp + 1 : endp; } mac_high = (mac[5] * 0x100) + mac[4]; mac_low = (mac[3] * 0x1000000) + (mac[2] * 0x10000) + (mac[1] * 0x100) + mac[0]; } else { /* read from smc9118 */ if(*SMSC9118_E2P_CMD & 1) { // Read current auto-loaded mac address. smsc9118_mac_regread(SMSC9118_MAC_ADDRH, &mac_high); smsc9118_mac_regread(SMSC9118_MAC_ADDRL, &mac_low); env_present = 1; } } if(env_present){ /* Set the MAC address int the smc9118 registers */ debug("MAC address is about to be set to high 0x%08x low 0x%08x\n", mac_high, mac_low); smsc9118_mac_regwrite(SMSC9118_MAC_ADDRH, mac_high); smsc9118_mac_regwrite(SMSC9118_MAC_ADDRL, mac_low); } return env_present; }static __inline int smsc9118_check_phy(void){ unsigned short phyid1, phyid2; smsc9118_phy_regread(SMSC9118_PHY_ID1,&phyid1); smsc9118_phy_regread(SMSC9118_PHY_ID2,&phyid2); debug("PHY ID1: 0x%08x, PHY ID2: 0x%08x\n\n",phyid1, phyid2); return ((phyid1 == 0xFFFF && phyid2 == 0xFFFF) || (phyid1 == 0x0 && phyid2 == 0x0));}static __inline int smsc9118_reset_phy(void){ unsigned short read; int error; debug("smsc9118_reset_phy()\n"); error = 0; if(smsc9118_phy_regread(SMSC9118_PHY_BCONTROL, &read)) { printf("Error: PHY BCONTROL read failed.\n"); error = 1; } else { read |= (1 << 15); if(smsc9118_phy_regwrite(SMSC9118_PHY_BCONTROL, read)) { printf("Error: PHY BCONTROL write failed.\n"); error = 1; } } return error;}/* Advertise all speeds and pause capabilities */static __inline void smsc9118_advertise_cap(void){ unsigned short aneg_adv; aneg_adv = 0; smsc9118_phy_regread(SMSC9118_PHY_ANEG_ADV, &aneg_adv); debug("advertise_cap: PHY_ANEG_ADV before write: 0x%08x\n",aneg_adv); aneg_adv |= 0xDE0; smsc9118_phy_regwrite(SMSC9118_PHY_ANEG_ADV, aneg_adv); smsc9118_phy_regread(SMSC9118_PHY_ANEG_ADV, &aneg_adv); debug("advertise_cap: PHY_ANEG_ADV: after write: 0x%08x\n",aneg_adv); return;}static __inline void smsc9118_establish_link(void){ unsigned short bcr; smsc9118_phy_regread(SMSC9118_PHY_BCONTROL, &bcr); debug("establish link: PHY_BCONTROL before write: 0x%08x\n",bcr); bcr |= (1 << 12) | (1 << 9); smsc9118_phy_regwrite(SMSC9118_PHY_BCONTROL, bcr); smsc9118_phy_regread(SMSC9118_PHY_BCONTROL, &bcr); debug("establish link: PHY_BCONTROL after write: 0x%08x\n", bcr); { unsigned int hw_cfg; hw_cfg = 0; hw_cfg = *SMSC9118_HW_CFG; hw_cfg &= 0xF0000; hw_cfg |= (1 << 20); *SMSC9118_HW_CFG = hw_cfg; } return;}static __inline void smsc9118_enable_xmit(void){ *SMSC9118_TX_CFG = 0x2; // Enable transmission return;}static __inline void smsc9118_enable_mac_xmit(void){ unsigned int mac_cr; mac_cr = 0; smsc9118_mac_regread(SMSC9118_MAC_CR, &mac_cr); mac_cr |= (1 << 3); // xmit enable mac_cr |= (1 << 28); // Heartbeat disable smsc9118_mac_regwrite(SMSC9118_MAC_CR, mac_cr); return;}static __inline void smsc9118_enable_mac_recv(void){ unsigned int mac_cr; mac_cr = 0; smsc9118_mac_regread(SMSC9118_MAC_CR, &mac_cr); mac_cr |= (1 << 2); // Recv enable smsc9118_mac_regwrite(SMSC9118_MAC_CR, mac_cr); return;}static __inline void smsc9118_disable_mac_xmit(void){ unsigned int mac_cr; mac_cr = 0; smsc9118_mac_regread(SMSC9118_MAC_CR, &mac_cr); mac_cr &= ~(1 << 3); // xmit enable mac_cr &= ~(1 << 28); // Heartbeat disable smsc9118_mac_regwrite(SMSC9118_MAC_CR, mac_cr); return;}static __inline void smsc9118_disable_xmit(void){ *SMSC9118_TX_CFG = 0; // Disable trasmission return;}static __inline void smsc9118_disable_mac_recv(void){ unsigned int mac_cr; mac_cr = 0; smsc9118_mac_regread(SMSC9118_MAC_CR, &mac_cr); mac_cr &= ~(1 << 2); // Recv enable smsc9118_mac_regwrite(SMSC9118_MAC_CR, mac_cr); return;}#define SMC9118_DEFAULT_TXFIFO_KB 5/* * Note that the datasheet states that an interrupt status bits is set regardless * of the setting of the interrupt enable bit for that interrupt. * i.e. we don't have to enable interrupts for a polled driver. */static int smsc9118_initialise(void){ int error = 1; ulong start; if(smsc9118_check_id()) { printf("Reading the Ethernet ID register failed.\n" "Check that a SMSC9118 device is present on the system @ %p.\n", (void*)CONFIG_SMC9118_BASE); } else if(smsc9118_soft_reset()) { printf("Error: SMSC9118 soft reset failed to complete.\n"); } else { smsc9118_set_txfifo(SMC9118_DEFAULT_TXFIFO_KB); // Sets automatic flow control thresholds, and backpressure // threshold to defaults specified. *SMSC9118_AFC_CFG = 0x006E3740; if(smsc9118_wait_eeprom()) { printf("Error: EEPROM failed to finish initialisation.\n"); } else { // Configure GPIOs as LED outputs. *SMSC9118_GPIO_CFG = 0x70070000; smsc9118_init_irqs(); /* Configure MAC addresses */ // Set from environment if present // else check valid if(smc9118_set_valid_ethaddr()){ if(smsc9118_check_phy()) { printf("Error: SMSC9118 PHY not present.\n"); } else { if(smsc9118_reset_phy()) { printf("Error: SMSC9118 PHY reset failed.\n"); } else { unsigned short phyreset = 0; // Wait start = get_timer(0); while (get_timer(start) < MS100){ ; } // Checking whether phy reset completed successfully. smsc9118_phy_regread(SMSC9118_PHY_BCONTROL, &phyreset); if(phyreset & (1 << 15)) { printf("Error: SMSC9118 PHY reset stage failed to complete.\n"); } else { /* Advertise capabilities */ smsc9118_advertise_cap(); /* Begin to establish link */ smsc9118_establish_link(); // bit [12] of BCONTROL seems self-clearing. // Although it's not so in the manual. /* Interrupt threshold */ *SMSC9118_FIFO_INT = 0xFF000000; smsc9118_enable_mac_xmit(); smsc9118_enable_xmit(); *SMSC9118_RX_CFG = 0; smsc9118_enable_mac_recv(); // Rx status FIFO level irq threshold *SMSC9118_FIFO_INT &= ~(0xFF); // Clear 2 bottom nibbles // This spin is compulsory otherwise txmit/receive will fail. start = get_timer(0); while (get_timer(start) < MS2000){ ; } error = 0; } } } } } } return error;}int smsc9118_recv_packet(unsigned int *recvbuf, int *index){ unsigned int rxfifo_inf; // Tells us the status of rx payload and status fifos. unsigned int rxfifo_stat; unsigned int pktsize; unsigned int dwords_to_read; debug("recv_packet start: recvbuf: 0x%08x index: %d\n", (unsigned int)recvbuf,*index); rxfifo_inf = *SMSC9118_RX_FIFO_INF; if(rxfifo_inf & 0xFFFF) { // If there's data rxfifo_stat = *SMSC9118_RX_STAT_PORT; if(rxfifo_stat != 0) { // Fetch status of this packet pktsize = ((rxfifo_stat >> 16) & 0x3FFF); // debug("recv_packet: rxfifo_stat: 0x%08x, pktsize (bytes): %u\n",rxfifo_stat, pktsize); if(*SMSC9118_INT_STS & 0x4000){ printf("Status read RXE is %d\n", *SMSC9118_INT_STS & 0x4000 ? 1 : 0); *SMSC9118_INT_STS = 0xFFFFFFFF; } if(rxfifo_stat & (1 << 15)) { printf("Error occured during receiving of packets on the bus.\n"); return 1; } else { /* Below formula (recommended by SMSC9118 code) * gives 1 more than required. This is because * a last word is needed for not word aligned packets. */ dwords_to_read = (pktsize + sizeof(unsigned int) - 1) >> 2; debug("recv_packet: dwords_to_read: %u\n",dwords_to_read); // PIO copy of data received: while((*SMSC9118_RX_FIFO_INF & 0x0000FFFF) && (dwords_to_read > 0)) { recvbuf[*index] = *SMSC9118_RX_DATA_PORT; // debug("recv_packet: Received word[%d]: 0x%08x\n",*index,recvbuf[*index]); (*index)++; dwords_to_read--; } if(*SMSC9118_INT_STS & 0x4000){ printf("Data read RXE is %d\n", *SMSC9118_INT_STS & 0x4000 ? 1 : 0); *SMSC9118_INT_STS = 0xFFFFFFFF; } } } else { printf("Error: rx fifo status reads zero where data is available.\n"); return 1; } } else { // printf("Error: No data available in rx FIFO\n"); return 1; } return 0;}// Does the actual transfer of data to FIFO, note it does no// fifo availability checking. This should be done by caller.// ASSUMES the whole frame is transferred at once as a single segment// ASSUMES chip auto pads to minimum ethernet packet lengthvoid smsc9118_xfer_to_txFIFO(unsigned char * pkt, unsigned int length){ unsigned int txcmd_a, txcmd_b; unsigned int dwords_to_write; volatile unsigned int dwritten; unsigned int *pktptr; pktptr = (unsigned int *) pkt; txcmd_a = 0; txcmd_b = 0; txcmd_a |= (1 << 12) | (1 << 13); // First and last segments txcmd_a |= length & 0x7FF; // [10:0] contains length txcmd_b |= ((length & 0xFFFF) << 16); // [31:16] contains length, rather than tag txcmd_b |= length & 0x7FF; // [10:0] also contains length debug("txcmd_a: 0x%08x\n", txcmd_a); debug("txcmd_b: 0x%08x\n", txcmd_b); *SMSC9118_TX_DATA_PORT = txcmd_a; *SMSC9118_TX_DATA_PORT = txcmd_b; dwritten = dwords_to_write = (length + sizeof(unsigned int) - 1) >> 2; // PIO Copy to FIFO. Could replace this with DMA. while(dwords_to_write > 0) { *SMSC9118_TX_DATA_PORT = *pktptr; debug("Transmitting word[%d]: 0x%08x\n",dwritten-dwords_to_write,*pktptr); pktptr++; dwords_to_write--; } { /* * Note that the read after read timings from table 6.2 are not used */ volatile unsigned int xmit_stat, xmit_stat2, xmit_inf; int i; xmit_stat = *SMSC9118_TX_STAT_PORT; debug("Finished transfer. TX_STATUS_WORD: 0x%08x\n",xmit_stat); xmit_stat2 = *SMSC9118_TX_STAT_PORT; xmit_inf = *SMSC9118_TX_FIFO_INF; debug("After popping TX_STAT: %08x, TX_INF: 0x%08x\n\n",xmit_stat2, xmit_inf); // ASSUMES that the register is emptied // - doesn't seem to do so in real life....... if(xmit_stat2 != 0 ) { debug("The second read of TX_STAT is non-zero. Retry reading a few more times.\n"); for(i = 0; i < 6; i++) { xmit_stat2 = *SMSC9118_TX_STAT_PORT; debug("Retry %d: TX_STAT: 0x%08x\n",i+1,xmit_stat2); } } }}int smsc9118_xmit_packet(unsigned char * pktbuf, int pktsize){ unsigned int txfifo_inf; txfifo_inf = *SMSC9118_TX_FIFO_INF; debug("TX_FIFO_INF: 0x%08x\n", txfifo_inf); if((txfifo_inf & 0xFFFF) >= pktsize) { smsc9118_xfer_to_txFIFO(pktbuf, pktsize); } else { printf("Insufficient tx fifo space for packet size %d\n",pktsize); return 1; } return 0;}/* * Ethernet API */int eth_init(bd_t *bd) {#ifdef SHARED_RESOURCES swap_to(ETHERNET);#endif return smsc9118_initialise();}void eth_halt() { PRINTK2("%s: eth_halt\n", SMC9118_DEV_NAME); smsc9118_disable_xmit(); smsc9118_disable_mac_xmit(); smsc9118_disable_mac_recv();}int eth_rx() { int index = 0; int rxfifo_inf = *SMSC9118_RX_FIFO_INF; /* * Any status info??? */ if(rxfifo_inf & 0x00FF0000){ smsc9118_recv_packet((unsigned int *)NetRxPackets[0], &index); if(index) { NetReceive(NetRxPackets[0], index * 4); } } return 4 * index;}int eth_send(volatile void *packet, int length) { int result = 0; int i; debug("Raw packet as %d decimal bytes:\n", length); for(i= 0; i < length; i++){ debug(" %02x ", ((char*)packet)[i]); if(!((i+1)%8)){ debug("\n"); } } debug("\n"); if(!smsc9118_xmit_packet((unsigned char *)packet, length)){ result = length; } return result;}#endif /* CONFIG_DRIVER_SMC9118 */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -