4xx_enet.c
来自「最新版的u-boot,2008-10-18发布」· C语言 代码 · 共 2,136 行 · 第 1/5 页
C
2,136 行
#endif /* CONFIG_460EX || CONFIG_460GT */static inline void *malloc_aligned(u32 size, u32 align){ return (void *)(((u32)malloc(size + align) + align - 1) & ~(align - 1));}static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis){ int i; unsigned long reg = 0; unsigned long msr; unsigned long speed; unsigned long duplex; unsigned long failsafe; unsigned mode_reg; unsigned short devnum; unsigned short reg_short;#if defined(CONFIG_440GX) || \ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \ defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \ defined(CONFIG_405EX) sys_info_t sysinfo;#if defined(CONFIG_440GX) || defined(CONFIG_440SPE) || \ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \ defined(CONFIG_405EX) int ethgroup = -1;#endif#endif u32 bd_cached; u32 bd_uncached = 0;#ifdef CONFIG_4xx_DCACHE static u32 last_used_ea = 0;#endif#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \ defined(CONFIG_405EX) int rgmii_channel;#endif EMAC_4XX_HW_PST hw_p = dev->priv; /* before doing anything, figure out if we have a MAC address */ /* if not, bail */ if (memcmp (dev->enetaddr, "\0\0\0\0\0\0", 6) == 0) { printf("ERROR: ethaddr not set!\n"); return -1; }#if defined(CONFIG_440GX) || \ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \ defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \ defined(CONFIG_405EX) /* Need to get the OPB frequency so we can access the PHY */ get_sys_info (&sysinfo);#endif msr = mfmsr (); mtmsr (msr & ~(MSR_EE)); /* disable interrupts */ devnum = hw_p->devnum;#ifdef INFO_4XX_ENET /* AS.HARNOIS * We should have : * hw_p->stats.pkts_handled <= hw_p->stats.pkts_rx <= hw_p->stats.pkts_handled+PKTBUFSRX * In the most cases hw_p->stats.pkts_handled = hw_p->stats.pkts_rx, but it * is possible that new packets (without relationship with * current transfer) have got the time to arrived before * netloop calls eth_halt */ printf ("About preceeding transfer (eth%d):\n" "- Sent packet number %d\n" "- Received packet number %d\n" "- Handled packet number %d\n", hw_p->devnum, hw_p->stats.pkts_tx, hw_p->stats.pkts_rx, hw_p->stats.pkts_handled); hw_p->stats.pkts_tx = 0; hw_p->stats.pkts_rx = 0; hw_p->stats.pkts_handled = 0; hw_p->print_speed = 1; /* print speed message again next time */#endif hw_p->tx_err_index = 0; /* Transmit Error Index for tx_err_log */ hw_p->rx_err_index = 0; /* Receive Error Index for rx_err_log */ hw_p->rx_slot = 0; /* MAL Receive Slot */ hw_p->rx_i_index = 0; /* Receive Interrupt Queue Index */ hw_p->rx_u_index = 0; /* Receive User Queue Index */ hw_p->tx_slot = 0; /* MAL Transmit Slot */ hw_p->tx_i_index = 0; /* Transmit Interrupt Queue Index */ hw_p->tx_u_index = 0; /* Transmit User Queue Index */#if defined(CONFIG_440) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) /* set RMII mode */ /* NOTE: 440GX spec states that mode is mutually exclusive */ /* NOTE: Therefore, disable all other EMACS, since we handle */ /* NOTE: only one emac at a time */ reg = 0; out_be32((void *)ZMII_FER, 0); udelay (100);#if defined(CONFIG_440GP) || defined(CONFIG_440EP) || defined(CONFIG_440GR) out_be32((void *)ZMII_FER, (ZMII_FER_RMII | ZMII_FER_MDI) << ZMII_FER_V (devnum));#elif defined(CONFIG_440GX) || \ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \ defined(CONFIG_460EX) || defined(CONFIG_460GT) ethgroup = ppc_4xx_eth_setup_bridge(devnum, bis);#endif out_be32((void *)ZMII_SSR, ZMII_SSR_SP << ZMII_SSR_V(devnum));#endif /* defined(CONFIG_440) && !defined(CONFIG_440SP) */#if defined(CONFIG_405EX) ethgroup = ppc_4xx_eth_setup_bridge(devnum, bis);#endif sync(); /* provide clocks for EMAC internal loopback */ emac_loopback_enable(hw_p); /* EMAC RESET */ out_be32((void *)EMAC_M0 + hw_p->hw_addr, EMAC_M0_SRST); /* remove clocks for EMAC internal loopback */ emac_loopback_disable(hw_p); failsafe = 1000; while ((in_be32((void *)EMAC_M0 + hw_p->hw_addr) & (EMAC_M0_SRST)) && failsafe) { udelay (1000); failsafe--; } if (failsafe <= 0) printf("\nProblem resetting EMAC!\n");#if defined(CONFIG_440GX) || \ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \ defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \ defined(CONFIG_405EX) /* Whack the M1 register */ mode_reg = 0x0; mode_reg &= ~0x00000038; if (sysinfo.freqOPB <= 50000000); else if (sysinfo.freqOPB <= 66666667) mode_reg |= EMAC_M1_OBCI_66; else if (sysinfo.freqOPB <= 83333333) mode_reg |= EMAC_M1_OBCI_83; else if (sysinfo.freqOPB <= 100000000) mode_reg |= EMAC_M1_OBCI_100; else mode_reg |= EMAC_M1_OBCI_GT100; out_be32((void *)EMAC_M1 + hw_p->hw_addr, mode_reg);#endif /* defined(CONFIG_440GX) || defined(CONFIG_440SP) */#if defined(CONFIG_GPCS_PHY_ADDR) || defined(CONFIG_GPCS_PHY1_ADDR) || \ defined(CONFIG_GPCS_PHY2_ADDR) || defined(CONFIG_GPCS_PHY3_ADDR) if (bis->bi_phymode[devnum] == BI_PHYMODE_SGMII) { /* * In SGMII mode, GPCS access is needed for * communication with the internal SGMII SerDes. */ switch (devnum) {#if defined(CONFIG_GPCS_PHY_ADDR) case 0: reg = CONFIG_GPCS_PHY_ADDR; break;#endif#if defined(CONFIG_GPCS_PHY1_ADDR) case 1: reg = CONFIG_GPCS_PHY1_ADDR; break;#endif#if defined(CONFIG_GPCS_PHY2_ADDR) case 2: reg = CONFIG_GPCS_PHY2_ADDR; break;#endif#if defined(CONFIG_GPCS_PHY3_ADDR) case 3: reg = CONFIG_GPCS_PHY3_ADDR; break;#endif } mode_reg = in_be32((void *)EMAC_M1 + hw_p->hw_addr); mode_reg |= EMAC_M1_MF_1000GPCS | EMAC_M1_IPPA_SET(reg); out_be32((void *)EMAC_M1 + hw_p->hw_addr, mode_reg); /* Configure GPCS interface to recommended setting for SGMII */ miiphy_reset(dev->name, reg); miiphy_write(dev->name, reg, 0x04, 0x8120); /* AsymPause, FDX */ miiphy_write(dev->name, reg, 0x07, 0x2801); /* msg_pg, toggle */ miiphy_write(dev->name, reg, 0x00, 0x0140); /* 1Gbps, FDX */ }#endif /* defined(CONFIG_GPCS_PHY_ADDR) */ /* wait for PHY to complete auto negotiation */ reg_short = 0; switch (devnum) { case 0: reg = CONFIG_PHY_ADDR; break;#if defined (CONFIG_PHY1_ADDR) case 1: reg = CONFIG_PHY1_ADDR; break;#endif#if defined (CONFIG_PHY2_ADDR) case 2: reg = CONFIG_PHY2_ADDR; break;#endif#if defined (CONFIG_PHY3_ADDR) case 3: reg = CONFIG_PHY3_ADDR; break;#endif default: reg = CONFIG_PHY_ADDR; break; } bis->bi_phynum[devnum] = reg; if (reg == CONFIG_FIXED_PHY) goto get_speed;#if defined(CONFIG_PHY_RESET) /* * Reset the phy, only if its the first time through * otherwise, just check the speeds & feeds */ if (hw_p->first_init == 0) {#if defined(CONFIG_M88E1111_PHY) miiphy_write (dev->name, reg, 0x14, 0x0ce3); miiphy_write (dev->name, reg, 0x18, 0x4101); miiphy_write (dev->name, reg, 0x09, 0x0e00); miiphy_write (dev->name, reg, 0x04, 0x01e1);#endif#if defined(CONFIG_M88E1112_PHY) if (bis->bi_phymode[devnum] == BI_PHYMODE_SGMII) { /* * Marvell 88E1112 PHY needs to have the SGMII MAC * interace (page 2) properly configured to * communicate with the 460EX/GT GPCS interface. */ /* Set access to Page 2 */ miiphy_write(dev->name, reg, 0x16, 0x0002); miiphy_write(dev->name, reg, 0x00, 0x0040); /* 1Gbps */ miiphy_read(dev->name, reg, 0x1a, ®_short); reg_short |= 0x8000; /* bypass Auto-Negotiation */ miiphy_write(dev->name, reg, 0x1a, reg_short); miiphy_reset(dev->name, reg); /* reset MAC interface */ /* Reset access to Page 0 */ miiphy_write(dev->name, reg, 0x16, 0x0000); }#endif /* defined(CONFIG_M88E1112_PHY) */ miiphy_reset (dev->name, reg);#if defined(CONFIG_440GX) || \ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \ defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \ defined(CONFIG_405EX)#if defined(CONFIG_CIS8201_PHY) /* * Cicada 8201 PHY needs to have an extended register whacked * for RGMII mode. */ if (((devnum == 2) || (devnum == 3)) && (4 == ethgroup)) {#if defined(CONFIG_CIS8201_SHORT_ETCH) miiphy_write (dev->name, reg, 23, 0x1300);#else miiphy_write (dev->name, reg, 23, 0x1000);#endif /* * Vitesse VSC8201/Cicada CIS8201 errata: * Interoperability problem with Intel 82547EI phys * This work around (provided by Vitesse) changes * the default timer convergence from 8ms to 12ms */ miiphy_write (dev->name, reg, 0x1f, 0x2a30); miiphy_write (dev->name, reg, 0x08, 0x0200); miiphy_write (dev->name, reg, 0x1f, 0x52b5); miiphy_write (dev->name, reg, 0x02, 0x0004); miiphy_write (dev->name, reg, 0x01, 0x0671); miiphy_write (dev->name, reg, 0x00, 0x8fae); miiphy_write (dev->name, reg, 0x1f, 0x2a30); miiphy_write (dev->name, reg, 0x08, 0x0000); miiphy_write (dev->name, reg, 0x1f, 0x0000); /* end Vitesse/Cicada errata */ }#endif /* defined(CONFIG_CIS8201_PHY) */#if defined(CONFIG_ET1011C_PHY) /* * Agere ET1011c PHY needs to have an extended register whacked * for RGMII mode. */ if (((devnum == 2) || (devnum ==3)) && (4 == ethgroup)) { miiphy_read (dev->name, reg, 0x16, ®_short); reg_short &= ~(0x7); reg_short |= 0x6; /* RGMII DLL Delay*/ miiphy_write (dev->name, reg, 0x16, reg_short); miiphy_read (dev->name, reg, 0x17, ®_short); reg_short &= ~(0x40); miiphy_write (dev->name, reg, 0x17, reg_short); miiphy_write(dev->name, reg, 0x1c, 0x74f0); }#endif /* defined(CONFIG_ET1011C_PHY) */#endif /* defined(CONFIG_440GX) ... */ /* Start/Restart autonegotiation */ phy_setup_aneg (dev->name, reg); udelay (1000); }#endif /* defined(CONFIG_PHY_RESET) */ miiphy_read (dev->name, reg, PHY_BMSR, ®_short); /* * Wait if PHY is capable of autonegotiation and autonegotiation is not complete */ if ((reg_short & PHY_BMSR_AUTN_ABLE) && !(reg_short & PHY_BMSR_AUTN_COMP)) { puts ("Waiting for PHY auto negotiation to complete"); i = 0; while (!(reg_short & PHY_BMSR_AUTN_COMP)) { /* * Timeout reached ? */ if (i > PHY_AUTONEGOTIATE_TIMEOUT) { puts (" TIMEOUT !\n"); break; } if ((i++ % 1000) == 0) { putc ('.'); } udelay (1000); /* 1 ms */ miiphy_read (dev->name, reg, PHY_BMSR, ®_short); } puts (" done\n"); udelay (500000); /* another 500 ms (results in faster booting) */ }get_speed: if (reg == CONFIG_FIXED_PHY) { for (i = 0; i < ARRAY_SIZE(fixed_phy_port); i++) { if (devnum == fixed_phy_port[i].devnum) { speed = fixed_phy_port[i].speed; duplex = fixed_phy_port[i].duplex; break; } } if (i == ARRAY_SIZE(fixed_phy_port)) { printf("ERROR: PHY (%s) not configured correctly!\n", dev->name); return -1; } } else { speed = miiphy_speed(dev->name, reg); duplex = miiphy_duplex(dev->name, reg); } if (hw_p->print_speed) { hw_p->print_speed = 0; printf ("ENET Speed is %d Mbps - %s duplex connection (EMAC%d)\n", (int) speed, (duplex == HALF) ? "HALF" : "FULL", hw_p->devnum); }#if defined(CONFIG_440) && \ !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) && \ !defined(CONFIG_440EPX) && !defined(CONFIG_440GRX) && \ !defined(CONFIG_460EX) && !defined(CONFIG_460GT)#if defined(CONFIG_440EP) || defined(CONFIG_440GR) mfsdr(sdr_mfr, reg); if (speed == 100) { reg = (reg & ~SDR0_MFR_ZMII_MODE_MASK) | SDR0_MFR_ZMII_MODE_RMII_100M; } else { reg = (reg & ~SDR0_MFR_ZMII_MODE_MASK) | SDR0_MFR_ZMII_MODE_RMII_10M; } mtsdr(sdr_mfr, reg);#endif /* Set ZMII/RGMII speed according to the phy link speed */ reg = in_be32((void *)ZMII_SSR); if ( (speed == 100) || (speed == 1000) ) out_be32((void *)ZMII_SSR, reg | (ZMII_SSR_SP << ZMII_SSR_V (devnum))); else out_be32((void *)ZMII_SSR, reg & (~(ZMII_SSR_SP << ZMII_SSR_V (devnum)))); if ((devnum == 2) || (devnum == 3)) { if (speed == 1000) reg = (RGMII_SSR_SP_1000MBPS << RGMII_SSR_V (devnum)); else if (speed == 100) reg = (RGMII_SSR_SP_100MBPS << RGMII_SSR_V (devnum)); else if (speed == 10) reg = (RGMII_SSR_SP_10MBPS << RGMII_SSR_V (devnum)); else { printf("Error in RGMII Speed\n"); return -1; } out_be32((void *)RGMII_SSR, reg); }#endif /* defined(CONFIG_440) && !defined(CONFIG_440SP) */#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \ defined(CONFIG_405EX) if (devnum >= 2)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?