📄 ethernet_smsc91c111.c
字号:
/***************************************************************************** * Copyright (c) 2002, Intrinsyc Software Inc * * FILE: ethernet_smsc91c111.c * * PURPOSE: * The purpose of this driver is to be the Ethernet driver for this * bootloader. * * REQUIRES: * 24LC64 EEPROM Driver * * CREATED BY: * Brad Remedios * * SPECIAL NOTES: * The original Hardware that this was being used / tested on had a small * defect in that only 32-bit accesses would work. Since then, that * defect has been fixed. The appropriate way to access the SMSC * registers is the REG8/16/32. * * The hardware that this was initially used and tested on was slightly * broken. All accesses to the SMSC have to be 32-bit aligned, even * though 8 and 16 bit accesses are totally valid. * * Additionally, the autoincrement functionality of the SMSC LAN91C111 * was seen to work correctly only in the 32-bit accesses case. If * the auto-increment is fixed, immediate performance increases can be * relized by modifing read_mmu_data and write_mmu_data as the * performance will increase in the unaligned cases (no performance * change for 32-bit aligned accesses). ****************************************************************************/#include <string.h>#include <ethernet_smsc91c111.h>#include <ethernet.h>#include <arp.h>#include <timer.h>#include <debug.h>#ifdef TAGGED_EEPROM#include <eeprom.h>#include <eeprom_24lc64.h>#else#warning You are using obsolete EEPROM code#include <eeprom_24lc64.h>#endif#define ERROR(x...) itc_printf("ERROR: "x)#if DEBUG_LEVEL >= 3// Print the Ethernet registers for debuggingstatic voidprint_registers(void){ int bank,reg; u16 _temp; itc_printf("91C111 registers:\r\n"); for (bank=0; bank <= 3; ++bank) { SETUP_BANK(bank); itc_printf("%x-\r\n", bank); for (reg=0; reg < 0xe; reg += 2) { READ_REG16(reg, _temp); itc_printf("%x: %x\r\n", reg, _temp); } itc_printf("\r\n"); }}// Print the phy registers for debuggingstatic voidprint_phy_registers(void){ int reg; u16 _temp; itc_printf("PHY registers:\r\n"); for (reg=0; reg < 5; ++reg) { read_phy_register (reg, &_temp); itc_printf("%x: %x\r\n", reg, _temp); } itc_printf("\r\n");}#endif/* * These are debugging calls and aren't needed in normal operation *static int print_data (unsigned char *data, unsigned short size); */int init_ethernet(u16 *macaddr){ int retval; int counter; unsigned short _temp; unsigned short rpc_mode = 0; unsigned short phy_data; unsigned short phy_stat; /* * Can we find a SMSC 91C111? */ retval = probe_smsc91c111 ((unsigned int *)SMSC91C111_WINDOW_ADDR);#if DEBUG_LEVEL >= 4 print_registers(); print_phy_registers();#endif if (retval == 0) { ERROR("No SMSC LAN91C111 was detected at %x\r\n", SMSC91C111_WINDOW_ADDR); return 0; } /* * Reset the SMSC Ethernet Chip MAC. Cases like Watchdog or Software * Reset could leave it in a bad state otherwise. */ SETUP_BANK(BANK_RCR); WRITE_REG16(OFFSET_RCR, BIT_RCR_SOFTRST); WRITE_REG16(OFFSET_RCR, 0); SETUP_BANK(BANK_CNFGR); WRITE_REG16(OFFSET_CNFGR, BIT_CNFGR_EPH_PWR_EN); /* * Promiscuous Mode - This is only here for testing. *//* SETUP_BANK(BANK_RCR); READ_REG16(OFFSET_RCR, _temp); _temp |= BIT_RCR_PRMS; WRITE_REG16(OFFSET_RCR, _temp);*/ /* * Turn off the transmitter and set the TCR to a known state */ SETUP_BANK(BANK_TCR); WRITE_REG16(OFFSET_TCR, 0); /* * Automatically deallocate memory for TX packets so we don't have to * NOTE: if this is enabled, then the 91C111 doesn't generate * BIT_ISR_TX_INT, which is undocumented behaviour and messes up * the TX completion check in tx_packet_ethernet. *//* SETUP_BANK(BANK_CR); READ_REG16(OFFSET_CR, _temp); _temp |= BIT_CR_AUTO_RELEASE; WRITE_REG16(OFFSET_CR, _temp);*/ /* * Busy wait for MMU to become free, then Reset the MMU. */ flush_ethernet(); /* * Disable All Interrupts. IBoot has no knowledge of them * so we can't use them */ SETUP_BANK(BANK_IMR); WRITE_REG16(OFFSET_IMR, 0); /* * We set up the Receiver to Strip CRC's off but DO NOT turn on * the Receive Enable. Because we poll the card, the SMSC's Memory * will fill up quickly if we turn on RX Enable (only can store 4 * packets and will read broadcast.) * Enable collision abort so we don't get half packets. */ SETUP_BANK(BANK_RCR); REG16(OFFSET_RCR) |= (BIT_RCR_STRIP_CRC | BIT_RCR_ABORT_ENB); /* * Enable TXEN so that we may send out packets */ SETUP_BANK(BANK_TCR); READ_REG16(OFFSET_TCR, _temp); _temp |= BIT_TCR_TXENA | BIT_TCR_PAD_EN; WRITE_REG16(OFFSET_TCR, _temp); /* * Reset the PHY and wait for it to complete. */ SETUP_BANK(BANK_MI); write_phy_register (PHY_CR, PHY_CR_RST); counter = PHY_RESET_WAIT; do { read_phy_register (PHY_CR, &phy_data); } while ((phy_data & PHY_CR_RST) && --counter); if (!counter) { ERROR ("PHY Failed to Reset\r\n"); }#ifdef SECOND_ETHERNET if ((retval = read_mac_ethernet (macaddr,1)) == 0)#else if ((retval = read_mac_ethernet (macaddr,0)) == 0)#endif { ERROR("Unable to read MAC address\r\n"); return retval; } /* * Sometimes (~1 in 6 times) the PHY appears to ignore the first * write after a reset, so do a sacrificial write by writing the * default values. */ write_phy_register (PHY_CR, PHY_CR_SPEED | PHY_CR_ANEG_EN | PHY_CR_MII_DIS); /* enable auto neg */ SETUP_BANK(BANK_RPCR); WRITE_REG16(OFFSET_RPCR, (RPCR_TX_RX_LED << 5) | (RPCR_LINK_LED << 2) | BIT_RPCR_ANEG); /* is auto neg supported? */ read_phy_register( PHY_SR, &phy_stat); if( phy_stat & PHY_SR_CAP_ANEG) { int autoneg_ok = 0; u16 ad_caps = PHY_ANAR_CSMA; u16 phy_int; u16 phy_aneg; /* Gather the capabilities we want to advertise */ if( phy_stat & PHY_SR_CAP_T4) ad_caps |= PHY_ANAR_T4; if( phy_stat & PHY_SR_CAP_TXF) ad_caps |= PHY_ANAR_TX_FDX; if( phy_stat & PHY_SR_CAP_TXH) ad_caps |= PHY_ANAR_TX_HDX; if( phy_stat & PHY_SR_CAP_TF) ad_caps |= PHY_ANAR_10_FDX; if( phy_stat & PHY_SR_CAP_TH) ad_caps |= PHY_ANAR_10_HDX; DEBUG_2 ("PHY phy stat %x\r\n", phy_stat); DEBUG_2 ("PHY ad caps %x\r\n", ad_caps); /* advertise our capabilities */ write_phy_register( PHY_ANAR, ad_caps); /* reset the auto-negotiation sequence */ write_phy_register (PHY_CR, PHY_CR_ANEG_EN | PHY_CR_ANEG_RST); /* wait for auto neg ack or timeout */ counter = MAX_ANEG_WAIT; do { udelay(200); read_phy_register (PHY_ANAR, &phy_aneg); } while ( ((phy_aneg & PHY_ANAR_ACK)==0) && --counter); if (!counter) { itc_printf ("PHY auto-negotiation timed out\r\n"); } else { DEBUG_2 ("PHY auto-negotiation ack'd\r\n"); autoneg_ok = 1; }#if DEBUG_LEVEL >= 3 read_phy_register (PHY_SR, &phy_stat); read_phy_register (PHY_ANAR, &phy_aneg); itc_printf ("phy_stat %x\r\n", phy_stat); itc_printf ("phy_aneg %x\r\n", phy_aneg);#endif read_phy_register (PHY_SR, &phy_stat); if( phy_stat & PHY_SR_REM_FLT) { itc_printf ("PHY auto-negotiation remote fault detected.\r\n"); } if( autoneg_ok) { /* wait a bit for status output to be updated */ delay(1); read_phy_register (PHY_INT, &phy_int); DEBUG_2 ("PHY phy_int %x\r\n", phy_int); itc_printf ("Auto-negotiation result: "); if( phy_int & PHY_INT_SPDDET) { itc_printf ("100BaseT"); rpc_mode |= BIT_RPCR_SPEED; } else { itc_printf ("10BaseT"); } if( phy_int & PHY_INT_DPLXDET) { itc_printf (" Full-Duplex"); rpc_mode |= BIT_RPCR_DPLX; SETUP_BANK(BANK_TCR); READ_REG16(OFFSET_TCR, _temp); _temp |= BIT_TCR_SWFDUP; WRITE_REG16(OFFSET_TCR, _temp); } else { itc_printf (" Half-Duplex"); } itc_printf ("\r\n"); } else { itc_printf ("Auto-negotiation result: failed (using 10BaseT Half-Duplex)\r\n"); } } /* * Setup MAC Address in SMSC LAN91C111 */ SETUP_BANK(BANK_IAR); WRITE_REG16(OFFSET_IAR01, macaddr[0]); WRITE_REG16(OFFSET_IAR23, macaddr[1]); WRITE_REG16(OFFSET_IAR45, macaddr[2]); /* * Setup Transmit Protocol Options: * LEDA = TX/RX, LEDB = 100MBit Link */ SETUP_BANK(BANK_RPCR); _temp = ((RPCR_TX_RX_LED << 5) | (RPCR_LINK_LED << 2) | rpc_mode); WRITE_REG16(OFFSET_RPCR, _temp); /* * It takes upwards of a second for the chip to detect whether a link * is available. Problems ensue if you try to use the link * before it's detected, so we'd better wait. */ counter = MAX_LINK_WAIT; do { udelay(200); read_phy_register (PHY_SR, &_temp); } while ( ((_temp & PHY_SR_LINK)==0) && --counter); if (_temp & PHY_SR_LINK) { itc_printf ("Ethernet Link Detected\r\n"); } else { itc_printf ("No Ethernet Link Detected\r\n"); }#if DEBUG_LEVEL >= 3 print_registers(); print_phy_registers();#endif return 1;} // End of init_ethernetint tx_packet_ethernet(u8 *data, u16 size){ unsigned char packet_number; unsigned int _temp; unsigned char _temp8; int retry=0,counter; DEBUG_4 ("Tx...");retransmit: /* * Both RXEN and TXEN should be on, I will double check though */ SETUP_BANK(BANK_TCR); if (!(REG16(OFFSET_TCR) & BIT_TCR_TXENA)) { REG16(OFFSET_TCR) |= BIT_TCR_TXENA; } SETUP_BANK(BANK_RCR); if (!(REG16(OFFSET_RCR) & BIT_RCR_RXEN)) { //ERROR ("RXEN was off\r\n"); REG16(OFFSET_RCR) |= BIT_RCR_RXEN; }#if DEBUG_LEVEL >= 5 SETUP_BANK(BANK_ISR); READ_REG8(OFFSET_ISR, _temp8); if (_temp8 & BIT_ISR_TX_INT) { ERROR("Hey--TX_INT is set! %x\r\n", _temp8); // Clear the TX interrupt bit //SETUP_BANK (BANK_ISR); //WRITE_REG8 (OFFSET_IRQAR, BIT_ISR_TX_INT); }#endif /* * Try to Allocate Memory for a packet in the MMU. If this fails * we cannot continue. * * If this fails we most likely have no more memory left. */ if (!allocate_tx (&packet_number)) { ERROR("%s: Could not allocate packet for TX\r\n", __FUNCTION__); return 0; } SETUP_BANK(BANK_PNR); WRITE_REG8(OFFSET_PNR, packet_number); if (!write_mmu_data (packet_number, data, size)) { ERROR("%s: Error Writing Data to MMU\r\n", __FUNCTION__); return 0; } SETUP_BANK(BANK_MMUCR); WRITE_REG16(OFFSET_MMUCR, OPCODE_MMUCR_ENQUEUE_TX);#if DEBUG_LEVEL >= 5 SETUP_BANK(BANK_ISR); READ_REG8(OFFSET_ISR, _temp8); if (_temp8 & BIT_ISR_TX_INT) { ERROR("TX_INT is already set! %x\r\n", _temp8); // Clear the TX interrupt bit //SETUP_BANK (BANK_ISR); //WRITE_REG8 (OFFSET_IRQAR, BIT_ISR_TX_INT); }#endif /* * Wait for packet to be done transmitting * This is not possible if BIT_CR_AUTO_RELEASE is set. */ SETUP_BANK(BANK_ISR); counter=MAX_ISR_COUNTER; do { READ_REG8(OFFSET_ISR, _temp8); } while (!(_temp8 & BIT_ISR_TX_INT) && --counter); if (!counter) { SETUP_BANK(BANK_EPHSR); READ_REG16(OFFSET_EPHSR, _temp); ERROR ("Timeout on TX\r\n"); DEBUG_2("EPHSR %x\r\n", _temp); if (_temp & BIT_EPHSR_TXUNRUN) { ERROR ("Tx Under Run Occurred\r\n"); } DEBUG_2("ISR is %x\r\n", _temp8); if (!(_temp & BIT_EPHSR_TX_SUC)) ERROR ("No Tx Success\r\n"); SETUP_BANK(BANK_TCR); READ_REG16(OFFSET_TCR, _temp); if (!(_temp & BIT_TCR_TXENA)) { ERROR ("Transmit Enabled not set\r\n"); } return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -