📄 smc91111.c
字号:
.-------------------------------------------------------------*/static word smc_read_phy_register(byte phyreg){ int oldBank; int i; byte mask; word mii_reg; byte bits[64]; int clk_idx = 0; int input_idx; word phydata; byte phyaddr = SMC_PHY_ADDR; // 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; // Read command <10> bits[clk_idx++] = MII_MDOE | MII_MDO; bits[clk_idx++] = MII_MDOE; // Output the PHY address, msb first mask = (byte)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 = (byte)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; // Input starts at this bit time input_idx = clk_idx; // Will input 16 bits for (i = 0; i < 16; ++i) bits[clk_idx++] = 0; // Final clock bit bits[clk_idx++] = 0; // Save the current bank oldBank = SMC_inw( BANK_SELECT ); // Select bank 3 SMC_SELECT_BANK( 3 ); // Get the current MII register value mii_reg = SMC_inw( MII_REG ); // Turn off all MII Interface bits mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO); // Clock all 64 cycles for (i = 0; i < sizeof bits; ++i) { // Clock Low - output data SMC_outw( mii_reg | bits[i], MII_REG ); udelay(SMC_PHY_CLOCK_DELAY); // Clock Hi - input data SMC_outw( mii_reg | bits[i] | MII_MCLK, MII_REG ); udelay(SMC_PHY_CLOCK_DELAY); bits[i] |= SMC_inw( MII_REG ) & MII_MDI; } // Return to idle state // Set clock to low, data to low, and output tristated SMC_outw( mii_reg, MII_REG ); udelay(SMC_PHY_CLOCK_DELAY); // 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; }#if (SMC_DEBUG > 2 ) printf("smc_read_phy_register(): phyaddr=%x,phyreg=%x,phydata=%x\n", phyaddr, phyreg, phydata); smc_dump_mii_stream(bits, sizeof bits);#endif return(phydata); }/*------------------------------------------------------------ . Writes a register to the MII Management serial interface .-------------------------------------------------------------*/static void smc_write_phy_register(byte phyreg, word phydata){ int oldBank; int i; word mask; word mii_reg; byte bits[65]; int clk_idx = 0; byte phyaddr = SMC_PHY_ADDR; // 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 = (byte)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 = (byte)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_inw( BANK_SELECT ); // Select bank 3 SMC_SELECT_BANK( 3 ); // Get the current MII register value mii_reg = SMC_inw( MII_REG ); // 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_outw( mii_reg | bits[i], MII_REG ); udelay(SMC_PHY_CLOCK_DELAY); // Clock Hi - input data SMC_outw( mii_reg | bits[i] | MII_MCLK, MII_REG ); udelay(SMC_PHY_CLOCK_DELAY); bits[i] |= SMC_inw( MII_REG ) & MII_MDI; } // Return to idle state // Set clock to low, data to low, and output tristated SMC_outw( mii_reg, MII_REG ); udelay(SMC_PHY_CLOCK_DELAY); // Restore original bank select SMC_SELECT_BANK( oldBank );#if (SMC_DEBUG > 2 ) printf("smc_write_phy_register(): phyaddr=%x,phyreg=%x,phydata=%x\n", phyaddr, phyreg, phydata); smc_dump_mii_stream(bits, sizeof bits);#endif}/*------------------------------------------------------------ . Waits the specified number of milliseconds - kernel friendly .-------------------------------------------------------------*/static void smc_wait_ms(unsigned int ms){ udelay(ms*100000);}/*------------------------------------------------------------ . Configures the specified PHY using Autonegotiation. Calls . smc_phy_fixed() if the user has requested a certain config. .-------------------------------------------------------------*/static void smc_phy_configure(){ int timeout; byte phyaddr; word my_phy_caps; // My PHY capabilities word my_ad_caps; // My Advertised capabilities word status = 0; //;my status = 0 int failed = 0; PRINTK3("%s:smc_program_phy()\n", SMC_DEV_NAME); // Get the detected phy address phyaddr = SMC_PHY_ADDR; // Reset the PHY, setting all other bits to zero smc_write_phy_register(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(PHY_CNTL_REG) & PHY_CNTL_RST)) { // reset complete break; } smc_wait_ms(500); // wait 500 millisecs } if (timeout < 1) { printf("%s:PHY reset timed out\n", SMC_DEV_NAME); goto smc_phy_configure_exit; } // Read PHY Register 18, Status Output // lp->lastPhy18 = smc_read_phy_register(PHY_INT_REG); // Enable PHY Interrupts (for register 18) // Interrupts listed here are disabled smc_write_phy_register(PHY_INT_REG, 0xffff); /* Configure the Receive/Phy Control register */ SMC_SELECT_BANK( 0 ); SMC_outw( RPC_DEFAULT, RPC_REG ); // Copy our capabilities from PHY_STAT_REG to PHY_AD_REG my_phy_caps = smc_read_phy_register(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; // Update our Auto-Neg Advertisement Register smc_write_phy_register( PHY_AD_REG, my_ad_caps); PRINTK2("%s:phy caps=%x\n", SMC_DEV_NAME, my_phy_caps); PRINTK2("%s:phy advertised caps=%x\n", SMC_DEV_NAME, my_ad_caps); // Restart auto-negotiation process in order to advertise my caps smc_write_phy_register( 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( PHY_STAT_REG); if (status & PHY_STAT_ANEG_ACK) { // auto-negotiate complete break; } smc_wait_ms(500); // wait 500 millisecs // Restart auto-negotiation if remote fault if (status & PHY_STAT_REM_FLT) { printf("%s:PHY remote fault detected\n", SMC_DEV_NAME); // Restart auto-negotiation printf("%s:PHY restarting auto-negotiation\n", SMC_DEV_NAME); smc_write_phy_register( PHY_CNTL_REG, PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST | PHY_CNTL_SPEED | PHY_CNTL_DPLX); } } if (timeout < 1) { printf("%s:PHY auto-negotiate timed out\n", SMC_DEV_NAME); printf("%s:PHY auto-negotiate timed out\n", SMC_DEV_NAME); failed = 1; } // Fail if we detected an auto-negotiate remote fault if (status & PHY_STAT_REM_FLT) { printf( "%s:PHY remote fault detected\n", SMC_DEV_NAME); printf("%s:PHY remote fault detected\n", SMC_DEV_NAME); failed = 1; } // Re-Configure the Receive/Phy Control register SMC_outw( RPC_DEFAULT, RPC_REG ); smc_phy_configure_exit:}#if SMC_DEBUG > 2static void print_packet( byte * buf, int length ){#if 0 int i; int remainder; int lines; printf("Packet of length %d \n", length );#if SMC_DEBUG > 3 lines = length / 16; remainder = length % 16; for ( i = 0; i < lines ; i ++ ) { int cur; for ( cur = 0; cur < 8; cur ++ ) { byte a, b; a = *(buf ++ ); b = *(buf ++ ); printf("%02x%02x ", a, b ); } printf("\n"); } for ( i = 0; i < remainder/2 ; i++ ) { byte a, b; a = *(buf ++ ); b = *(buf ++ ); printf("%02x%02x ", a, b ); } printf("\n");#endif#endif}#endifint eth_init(bd_t *bd) { smc_open(); return 0;}void eth_halt() { smc_close();}int eth_rx() { return smc_rcv();}int eth_send(volatile void *packet, int length) { return smc_send_packet(packet, length);}#endif /* CONFIG_DRIVER_SMC91111 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -