📄 ether-smc91x.c
字号:
} // Return to idle state // Set clock to low, data to low, and output tristated SMC_SET_MII( mii_reg ); msleep(1); // Restore original bank select SMC_SELECT_BANK( oldBank ); // Recover input data phydata = 0; for (i = 0; i < 16; ++i) { phydata <<= 1; if (bits[input_idx++] & MII_MDI) phydata |= 0x0001; } DBG(3, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n", __FUNCTION__, phyaddr, phyreg, phydata); PRINT_MII_STREAM(bits, sizeof(bits)); return phydata;}/*------------------------------------------------------------ . Writes a register to the MII Management serial interface .-------------------------------------------------------------*/static voidsmc_write_phy_register( unsigned long ioaddr, int phyaddr, int phyreg, int phydata ){ int oldBank; int i, mask, mii_reg; u8 bits[65]; int clk_idx = 0; // 32 consecutive ones on MDO to establish sync for (i = 0; i < 32; ++i) bits[clk_idx++] = MII_MDOE | MII_MDO; // Start code <01> bits[clk_idx++] = MII_MDOE; bits[clk_idx++] = MII_MDOE | MII_MDO; // Write command <01> bits[clk_idx++] = MII_MDOE; bits[clk_idx++] = MII_MDOE | MII_MDO; // Output the PHY address, msb first mask = 0x10; for (i = 0; i < 5; ++i) { if (phyaddr & mask) bits[clk_idx++] = MII_MDOE | MII_MDO; else bits[clk_idx++] = MII_MDOE; // Shift to next lowest bit mask >>= 1; } // Output the phy register number, msb first mask = 0x10; for (i = 0; i < 5; ++i) { if (phyreg & mask) bits[clk_idx++] = MII_MDOE | MII_MDO; else bits[clk_idx++] = MII_MDOE; // Shift to next lowest bit mask >>= 1; } // Tristate and turnaround (2 bit times) bits[clk_idx++] = 0; bits[clk_idx++] = 0; // Write out 16 bits of data, msb first mask = 0x8000; for (i = 0; i < 16; ++i) { if (phydata & mask) bits[clk_idx++] = MII_MDOE | MII_MDO; else bits[clk_idx++] = MII_MDOE; // Shift to next lowest bit mask >>= 1; } // Final clock bit (tristate) bits[clk_idx++] = 0; // Save the current bank oldBank = SMC_CURRENT_BANK(); // Select bank 3 SMC_SELECT_BANK( 3 ); // Get the current MII register value mii_reg = SMC_GET_MII(); // Turn off all MII Interface bits mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO); // Clock all cycles for (i = 0; i < sizeof bits; ++i) { // Clock Low - output data SMC_SET_MII( mii_reg | bits[i] ); msleep(1); // Clock Hi - input data SMC_SET_MII( mii_reg | bits[i] | MII_MCLK ); msleep(1); bits[i] |= SMC_GET_MII() & MII_MDI; } // Return to idle state // Set clock to low, data to low, and output tristated SMC_SET_MII( mii_reg ); msleep(1); // Restore original bank select SMC_SELECT_BANK( oldBank ); DBG(3, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n", __FUNCTION__, phyaddr, phyreg, phydata); PRINT_MII_STREAM(bits, sizeof(bits));}/*------------------------------------------------------------ . Finds and reports the PHY address .-------------------------------------------------------------*/static int smc_detect_phy(u32 ioaddr, u32 *pphyaddr){ int phy_id1, phy_id2; int phyaddr; int found = 0; DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__); // Scan all 32 PHY addresses if necessary for (phyaddr = 0; phyaddr < 32; ++phyaddr) { // Read the PHY identifiers phy_id1 = smc_read_phy_register(ioaddr, phyaddr, PHY_ID1_REG); phy_id2 = smc_read_phy_register(ioaddr, phyaddr, PHY_ID2_REG); DBG(3, "%s: phy_id1=0x%x, phy_id2=0x%x\n", CARDNAME, phy_id1, phy_id2); // Make sure it is a valid identifier if ((phy_id2 > 0x0000) && (phy_id2 < 0xffff) && (phy_id1 > 0x0000) && (phy_id1 < 0xffff)) { if ((phy_id1 != 0x8000) && (phy_id2 != 0x8000)) { // Save the PHY's address *pphyaddr = phyaddr; found = 1; break; } } } if (!found) { DBG(1, "%s: No PHY found\n", CARDNAME); return(0); } // Set the PHY type if ( (phy_id1 == 0x0016) && ((phy_id2 & 0xFFF0) == 0xF840 ) ) { DBG(1, "%s: PHY=LAN83C183 (LAN91C111 Internal)\n", CARDNAME); } if ( (phy_id1 == 0x0282) && ((phy_id2 & 0xFFF0) == 0x1C50) ) { DBG(1, "%s: PHY=LAN83C180\n", CARDNAME); } return 1;}/*------------------------------------------------------------ . Configures the specified PHY through the MII management interface . using Autonegotiation. . Calls smc_phy_fixed() if the user has requested a certain config. .-------------------------------------------------------------*/static voidsmc_phy_configure(u32 ioaddr){ int timeout; int phyaddr; int my_phy_caps; // My PHY capabilities int my_ad_caps; // My Advertised capabilities int status; int failed = 0; int rpc_cur_mode = RPC_DEFAULT; DBG(3, "%s:smc_program_phy()\n", CARDNAME); // Set the blocking flag //lp->autoneg_active = 1; // Find the address and type of our phy if (!smc_detect_phy(ioaddr, (u32 *)&phyaddr)) goto smc_phy_configure_exit; // Reset the PHY, setting all other bits to zero smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG, PHY_CNTL_RST); // Wait for the reset to complete, or time out timeout = 6; // Wait up to 3 seconds while (timeout--) { if (!(smc_read_phy_register(ioaddr, phyaddr, PHY_CNTL_REG) & PHY_CNTL_RST)) // reset complete break; msleep(500); // wait 500 millisecs } if (timeout < 1) { printf("%s: PHY reset timed out\n", CARDNAME); goto smc_phy_configure_exit; } // Read PHY Register 18, Status Output //lp->lastPhy18 = smc_read_phy_register(ioaddr, phyaddr, PHY_INT_REG); // Enable PHY Interrupts (for register 18) // Interrupts listed here are disabled smc_write_phy_register(ioaddr, phyaddr, PHY_MASK_REG, PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD | PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB | PHY_INT_SPDDET | PHY_INT_DPLXDET); /* Configure the Receive/Phy Control register */ SMC_SELECT_BANK( 0 ); SMC_SET_RPC( rpc_cur_mode ); // Copy our capabilities from PHY_STAT_REG to PHY_AD_REG my_phy_caps = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG); my_ad_caps = PHY_AD_CSMA; // I am CSMA capable if (my_phy_caps & PHY_STAT_CAP_T4) my_ad_caps |= PHY_AD_T4; if (my_phy_caps & PHY_STAT_CAP_TXF) my_ad_caps |= PHY_AD_TX_FDX; if (my_phy_caps & PHY_STAT_CAP_TXH) my_ad_caps |= PHY_AD_TX_HDX; if (my_phy_caps & PHY_STAT_CAP_TF) my_ad_caps |= PHY_AD_10_FDX; if (my_phy_caps & PHY_STAT_CAP_TH) my_ad_caps |= PHY_AD_10_HDX; // Disable capabilities not selected by our user //if (lp->ctl_rspeed != 100) // my_ad_caps &= ~(PHY_AD_T4|PHY_AD_TX_FDX|PHY_AD_TX_HDX); //if (!lp->ctl_rfduplx) // my_ad_caps &= ~(PHY_AD_TX_FDX|PHY_AD_10_FDX); // Update our Auto-Neg Advertisement Register smc_write_phy_register(ioaddr, phyaddr, PHY_AD_REG, my_ad_caps); // Read the register back. Without this, it appears that when // auto-negotiation is restarted, sometimes it isn't ready and // the link does not come up. status = smc_read_phy_register(ioaddr, phyaddr, PHY_AD_REG); DBG(2, "%s: phy caps=%x\n", CARDNAME, my_phy_caps); DBG(2, "%s: phy advertised caps=%x\n", CARDNAME, my_ad_caps); // Restart auto-negotiation process in order to advertise my caps smc_write_phy_register( ioaddr, phyaddr, PHY_CNTL_REG, PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST ); // Wait for the auto-negotiation to complete. This may take from // 2 to 3 seconds. // Wait for the reset to complete, or time out timeout = 20; // Wait up to 10 seconds while (timeout--) { status = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG); if (status & PHY_STAT_ANEG_ACK) // auto-negotiate complete break; msleep(500); // wait 500 millisecs // Restart auto-negotiation if remote fault if (status & PHY_STAT_REM_FLT) { DBG(1, "%s: PHY remote fault detected\n", CARDNAME); // Restart auto-negotiation DBG(1, "%s: PHY restarting auto-negotiation\n", CARDNAME); smc_write_phy_register( ioaddr, phyaddr, PHY_CNTL_REG, PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST | PHY_CNTL_SPEED | PHY_CNTL_DPLX); } } if (timeout < 1) { DBG(1, "%s: PHY auto-negotiate timed out\n", CARDNAME); failed = 1; } // Fail if we detected an auto-negotiate remote fault if (status & PHY_STAT_REM_FLT) { DBG(1, "%s: PHY remote fault detected\n", CARDNAME); failed = 1; } // Re-Configure the Receive/Phy Control register SMC_SET_RPC( rpc_cur_mode );smc_phy_configure_exit: // Exit auto-negotiation return;}/*---------------------------------------------------------------------- . Function: smc_probe( unsigned long ioaddr ) . . Purpose: . Tests to see if a given ioaddr points to an SMC91x chip. . Returns a 0 on success . . Algorithm: . (1) see if the high byte of BANK_SELECT is 0x33 . (2) compare the ioaddr with the base register's address . (3) see if I recognize the chip ID in the appropriate register . .--------------------------------------------------------------------- *//*--------------------------------------------------------------- . Here I do typical initialization tasks. . . o Initialize the structure if needed . o print out my vanity message if not done so already . o print out what type of hardware is detected . o print out the ethernet address . o find the IRQ . o set up my private data . o configure the dev structure with my subroutines . o actually GRAB the irq. . o GRAB the region .-----------------------------------------------------------------*/static int smc_probe(u32 ioaddr){ unsigned int val; DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__); /* First, see if the high byte is 0x33 */ val = SMC_CURRENT_BANK(); DBG(2, "%s: bank signature probe returned 0x%04x\n", CARDNAME, val); if ( (val & 0xFF00) != 0x3300 ) return -1; /* The above MIGHT indicate a device, but I need to write to further test this. */ SMC_SELECT_BANK(0); val = SMC_CURRENT_BANK(); if ( (val & 0xFF00 ) != 0x3300 ) return -1; /* Get the MAC address */ SMC_SELECT_BANK( 1 ); SMC_GET_MAC_ADDR(hwaddress); /* now, reset the chip, and put it into a known state */ smc_reset( ioaddr ); return 0;}static int smc_hw_reset(u32 ioaddr){#if defined(LUBBOCK) { volatile int *attaddr = (int*)(ioaddr + 1<<25); long flags; /* first reset, then enable the device. Sequence is critical */ attaddr[ECOR] |= ECOR_RESET; msleep(1); attaddr[ECOR] &= ~ECOR_RESET; attaddr[ECOR] |= ECOR_ENABLE; /* force 16-bit mode */ attaddr[ECSR] &= ~ECSR_IOIS8; msleep(1); }#endif return 0;}/********************************************************************** * ethernet driver interfaces */static int smc_init(u32 ioaddr){ int err=0; u8 version; DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__); err = smc_hw_reset(ioaddr); if (err) return err; err = smc_probe(ioaddr); if (err) return err; SMC_SELECT_BANK(3); version = SMC_GET_REV() & 0xff; /* reset the hardware */ smc_reset(ioaddr); smc_enable(ioaddr); SMC_SELECT_BANK( 1 ); hwaddress[0] = 0x00; hwaddress[1] = 0x80; hwaddress[2] = 0x48; hwaddress[3] = 0x12; hwaddress[4] = 0x34; hwaddress[5] = 0x56; SMC_SET_MAC_ADDR(hwaddress); smc_chip_base = ioaddr; if (version > 0x70) smc_phy_configure(ioaddr); return err;}static int readether( u8 *buf, int size ){ int ret = 0; u8 status, mask = 0xff; u16 saved_bank; u32 ioaddr = smc_chip_base; if ( !smc_chip_base ) return -EINVAL; saved_bank = SMC_CURRENT_BANK(); SMC_SELECT_BANK(2); mask = SMC_GET_INT_MASK(); /* clear all interrupts */ SMC_SET_INT_MASK(0); /* read the status flag, and mask it */ status = SMC_GET_INT() & mask; if (!status) { ret = 0; } else if ( status & IM_RCV_INT ) { ret = smc_rcv( smc_chip_base, buf, size ); } SMC_SET_INT_MASK(mask); SMC_SELECT_BANK(saved_bank); return ret;}static int writeether( u8 *buf, int size ){ if ( !smc_chip_base ) return -EINVAL; memcpy( buf+6, hwaddress, 6 ); return smc_send( smc_chip_base, buf, size);}static int get_ethaddr( u8 dev_addr[6] ){ u32 ioaddr = smc_chip_base; if (!ioaddr) return -EINVAL; SMC_GET_MAC_ADDR(dev_addr); return 0;}static int set_ethaddr( u8 dev_addr[6] ){ u32 ioaddr = smc_chip_base; if (!ioaddr) return -EINVAL; SMC_SET_MAC_ADDR(dev_addr); return 0;}/********************************************************************** * export ethernet driver */ether_driver_t smc91x_ether_driver = { smc_init, readether, writeether, set_ethaddr, get_ethaddr, SMC_BASE,};int board_eth_init(void){ if(smc_init(smc91x_ether_driver.base)) { puts("initialize ethernet card fail!\n"); return -1; } puts("initialize ethernet card OK!\n"); return 0;}int board_eth_lnk_stat(void){ return 0;}int board_eth_send(unsigned char *data, unsigned int len){ return writeether(data, len);}int board_eth_rcv(unsigned char *data, unsigned int *len){ int ret; ret = readether(data, 1532); if(ret>0) { *len = ret; return 0; } return -1;}int board_eth_get_addr(unsigned char *addr){ memcpy(addr, hwaddress, 6); return 0;}void smc91x_read(void){ ether_driver_t *pEthDrv; int ret; u8 data[2000]; pEthDrv = &smc91x_ether_driver; while(1) { ret = pEthDrv->rcv(data, sizeof(data)); if(ret) { printf("read result = %d\n", ret); if(ret>0 && ret<=60) { int i; for(i=0; i<ret; i++) printf("%02x%c", data[i], ((i+1)%16)?',':'\n'); putchar('\n'); } } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -