/****************************************************************************** * * ip_VLANInit - initialize "port-based VLANs" for the specified enet unit. */ static void ip_VLANInit(int ethUnit) { int phyUnit; uint32_t phyBase; uint32_t phyReg; phyBase = IP_GLOBALREGBASE; for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) { if (IP_ETHUNIT(phyUnit) != ethUnit) { continue; } phy_reg_write(phyBase, IP_GLOBAL_PHY29_ADDR, IP_GLOBAL_PHY29_24_REG + ((phyUnit == 5) ? (phyUnit + 1) : phyUnit), IP_VLAN_TABLE_SETTING(phyUnit)); /* Send all packets to all ports */ phyReg = phy_reg_read(phyBase, IP_GLOBAL_PHY30_ADDR, IP_GLOBAL_PHY30_1_REG); phyReg = phyReg | ((1 << phyUnit) << IP_VLAN1_OUTPUT_PORT_MASK_S); phy_reg_write(phyBase, IP_GLOBAL_PHY30_ADDR, IP_GLOBAL_PHY30_1_REG, phyReg); } phyReg = phy_reg_read(phyBase, IP_GLOBAL_PHY30_ADDR, IP_GLOBAL_PHY30_9_REG); phyReg = phyReg | TAG_VLAN_ENABLE; phyReg = phyReg & ~VID_INDX_SEL_M; phy_reg_write(phyBase, IP_GLOBAL_PHY30_ADDR, IP_GLOBAL_PHY30_9_REG, phyReg); }
BOOL adm_phySpeed(int ethUnit) { int phyUnit; uint16_t phyHwStatus; uint32_t phyBase; uint32_t phyAddr; for (phyUnit=0; phyUnit < ADM_PHY_MAX; phyUnit++) { if (!ADM_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } if (adm_phyIsLinkAlive(phyUnit)) { phyBase = ADM_PHYBASE(phyUnit); phyAddr = ADM_PHYADDR(phyUnit); phyHwStatus = phy_reg_read(phyBase, phyAddr, ADM_LINK_PARTNER_ABILITY); if (phyHwStatus & ADM_LINK_100BASETX) { return AG7100_PHY_SPEED_100TX; } } } return AG7100_PHY_SPEED_10T; }
/****************************************************************************** * * adm_phyIsDuplexFull - Determines whether the phy ports associated with the * specified device are FULL or HALF duplex. * * RETURNS: * 1 --> FULL * 0 --> HALF */ int adm_phyIsFullDuplex(int ethUnit) { int phyUnit; uint32_t phyBase; uint32_t phyAddr; uint16_t phyHwStatus; for (phyUnit=0; phyUnit < ADM_PHY_MAX; phyUnit++) { if (!ADM_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } if (adm_phyIsLinkAlive(phyUnit)) { phyBase = ADM_PHYBASE(phyUnit); phyAddr = ADM_PHYADDR(phyUnit); phyHwStatus = phy_reg_read(phyBase, phyAddr, ADM_LINK_PARTNER_ABILITY); if ((phyHwStatus & ADM_LINK_100BASETX_FULL_DUPLEX) || (phyHwStatus & ADM_LINK_10BASETX_FULL_DUPLEX)) { return TRUE; } } return -1; } return FALSE; }
unsigned int athrs_ar8033_phy_read(int ethUnit, unsigned int phy_addr, unsigned int reg_addr) { return phy_reg_read(0x1,phy_addr,reg_addr); }
/****************************************************************************** * * ip_phyIsDuplexFull - Determines whether the phy ports associated with the * specified device are FULL or HALF duplex. * * RETURNS: * 1 --> FULL * 0 --> HALF */ int ip_phyIsFullDuplex(int ethUnit) { int phyUnit; uint32_t phyBase; uint32_t phyAddr; uint16_t phyHwStatus; for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) { if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } if (ip_phyIsLinkAlive(phyUnit)) { phyBase = IP_PHYBASE(phyUnit); phyAddr = IP_PHYADDR(phyUnit); phyHwStatus = phy_reg_read(phyBase, phyAddr, IP_LINK_PARTNER_ABILITY); printk("ipPhy.c: phyHwStatus 0x%x\n",phyHwStatus); if ((phyHwStatus & IP_LINK_100BASETX_FULL_DUPLEX) || (phyHwStatus & IP_LINK_10BASETX_FULL_DUPLEX)) { return TRUE; } } return -1; } return FALSE; }
/****************************************************************************** * * adm_phyIsLinkAlive - test to see if the specified link is alive * * RETURNS: * TRUE --> link is alive * FALSE --> link is down */ BOOL adm_phyIsLinkAlive(int phyUnit) { uint16_t phyHwStatus; uint32_t phyBase; uint32_t phyAddr; phyBase = ADM_PHYBASE(phyUnit); phyAddr = ADM_PHYADDR(phyUnit); phyHwStatus = phy_reg_read(phyBase, phyAddr, ADM_PHY_STATUS); if (phyHwStatus & ADM_STATUS_LINK_PASS) { return TRUE; } else { return FALSE; } }
int ethernetext_chk_link_mode(void) { int32_t link; uint16_t data; if ((phy_id & M_PHY_ID) == PHY_ID_LAN8710A) { data = phy_reg_read(PHY_SP_CTL_STS_REG); switch (((uint32_t)data >> 2) & 0x00000007) { case 0x0001: link = HALF_10M; break; case 0x0005: link = FULL_10M; break; case 0x0002: link = HALF_TX; break; case 0x0006: link = FULL_TX; break; default: link = NEGO_FAIL; break; } } else {
int adm_phyIsUp(int ethUnit) { int phyUnit; uint16_t phyHwStatus; admPhyInfo_t *lastStatus; int linkCount = 0; int lostLinks = 0; int gainedLinks = 0; uint32_t phyBase; uint32_t phyAddr; for (phyUnit=0; phyUnit < ADM_PHY_MAX; phyUnit++) { if (!ADM_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } phyBase = ADM_PHYBASE(phyUnit); phyAddr = ADM_PHYADDR(phyUnit); lastStatus = &admPhyInfo[phyUnit]; phyHwStatus = phy_reg_read(phyBase, phyAddr, ADM_PHY_STATUS); if (lastStatus->isPhyAlive) { /* last known link status was ALIVE */ /* See if we've lost link */ if (phyHwStatus & ADM_STATUS_LINK_PASS) { linkCount++; } else { lostLinks++; #ifdef COBRA_TODO mv_flushATUDB(phyUnit); #endif DRV_PRINT(DRV_DEBUG_PHYCHANGE,("\nenet%d port%d down\n", ethUnit, phyUnit)); lastStatus->isPhyAlive = FALSE; } } else { /* last known link status was DEAD */ /* Check for AutoNegotiation complete */ if (ADM_AUTONEG_DONE(phyHwStatus)) { //printk("autoneg done\n"); gainedLinks++; linkCount++; DRV_PRINT(DRV_DEBUG_PHYCHANGE,("\nenet%d port%d up\n", ethUnit, phyUnit)); lastStatus->isPhyAlive = TRUE; } } } return (linkCount); #if 0 if (linkCount == 0) { if (lostLinks) { /* We just lost the last link for this MAC */ phyLinkLost(ethUnit); } } else { if (gainedLinks == linkCount) { /* We just gained our first link(s) for this MAC */ phyLinkGained(ethUnit); } } #endif }
BOOL adm_phySetup(int ethUnit) { int phyUnit, global; uint16_t phyHwStatus; uint16_t timeout; int liveLinks = 0; uint32_t phyBase = 0; BOOL foundPhy = FALSE; uint32_t phyAddr; static int inited = 0; /* Reset PHYs*/ for (phyUnit=0; phyUnit < ADM_PHY_MAX; phyUnit++) { if (!ADM_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } phyBase = ADM_PHYBASE(phyUnit); phyAddr = ADM_PHYADDR(phyUnit); phy_reg_write(phyBase, phyAddr, ADM_PHY_CONTROL, ADM_CTRL_SOFTWARE_RESET); } /* * After the phy is reset, it takes a little while before * it can respond properly. */ sysMsDelay(300); /* See if there's any configuration data for this enet */ for (phyUnit=0; phyUnit < ADM_PHY_MAX; phyUnit++) { if (!ADM_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } phyBase = ADM_PHYBASE(phyUnit); foundPhy = TRUE; break; } if (!foundPhy) { return FALSE; /* No PHY's configured for this ethUnit */ } /* start auto negogiation on each phy */ for (phyUnit=0; phyUnit < ADM_PHY_MAX; phyUnit++) { if (!ADM_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } phyBase = ADM_PHYBASE(phyUnit); phyAddr = ADM_PHYADDR(phyUnit); phy_reg_write(phyBase, phyAddr, ADM_AUTONEG_ADVERT, ADM_ADVERTISE_ALL); phy_reg_write(phyBase, phyAddr, ADM_PHY_CONTROL, ADM_CTRL_AUTONEGOTIATION_ENABLE | ADM_CTRL_START_AUTONEGOTIATION); } /* * Wait up to .75 seconds for ALL associated PHYs to finish * autonegotiation. The only way we get out of here sooner is * if ALL PHYs are connected AND finish autonegotiation. */ timeout=5; for (phyUnit=0; (phyUnit < ADM_PHY_MAX) /*&& (timeout > 0) */; phyUnit++) { if (!ADM_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } for (;;) { phyBase = ADM_PHYBASE(phyUnit); phyAddr = ADM_PHYADDR(phyUnit); phyHwStatus = phy_reg_read(phyBase, phyAddr, ADM_PHY_STATUS); if (ADM_AUTONEG_DONE(phyHwStatus)) { DRV_PRINT(DRV_DEBUG_PHYSETUP, ("Port %d, Neg Success\n", phyUnit)); break; } if (timeout == 0) { DRV_PRINT(DRV_DEBUG_PHYSETUP, ("Port %d, Negogiation timeout\n", phyUnit)); break; } if (--timeout == 0) { DRV_PRINT(DRV_DEBUG_PHYSETUP, ("Port %d, Negogiation timeout\n", phyUnit)); break; } sysMsDelay(150); } } /* * All PHYs have had adequate time to autonegotiate. * Now initialize software status. * * It's possible that some ports may take a bit longer * to autonegotiate; but we can't wait forever. They'll * get noticed by mv_phyCheckStatusChange during regular * polling activities. */ for (phyUnit=0; phyUnit < ADM_PHY_MAX; phyUnit++) { if (!ADM_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } if (adm_phyIsLinkAlive(phyUnit)) { liveLinks++; ADM_IS_PHY_ALIVE(phyUnit) = TRUE; } else { ADM_IS_PHY_ALIVE(phyUnit) = FALSE; } DRV_PRINT(DRV_DEBUG_PHYSETUP, ("eth%d: Phy Status=%4.4x\n", ethUnit, phy_reg_read(ADM_PHYBASE(phyUnit), ADM_PHYADDR(phyUnit), ADM_PHY_STATUS))); } /* * XXX */ phy_reg_write(0, 0, 0x10, 0x50); return (liveLinks > 0); }
BOOL adm_phySetup(int ethUnit) { int phyUnit; uint16_t phyHwStatus; uint16_t timeout; int liveLinks = 0; uint32_t phyBase = 0; BOOL foundPhy = FALSE; uint32_t phyAddr; /* Reset PHYs*/ for (phyUnit=0; phyUnit < ADM_PHY_MAX; phyUnit++) { if (!ADM_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } phyBase = ADM_PHYBASE(phyUnit); phyAddr = ADM_PHYADDR(phyUnit); phy_reg_write(phyBase, phyAddr, ADM_PHY_CONTROL, ADM_CTRL_SOFTWARE_RESET); } /* * After the phy is reset, it takes a little while before * it can respond properly. */ mdelay(300); /* See if there's any configuration data for this enet */ for (phyUnit=0; phyUnit < ADM_PHY_MAX; phyUnit++) { if (!ADM_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } phyBase = ADM_PHYBASE(phyUnit); foundPhy = TRUE; break; } if (!foundPhy) { return FALSE; /* No PHY's configured for this ethUnit */ } /* start auto negogiation on each phy */ for (phyUnit=0; phyUnit < ADM_PHY_MAX; phyUnit++) { if (!ADM_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } phyBase = ADM_PHYBASE(phyUnit); phyAddr = ADM_PHYADDR(phyUnit); phy_reg_write(phyBase, phyAddr, ADM_AUTONEG_ADVERT, ADM_ADVERTISE_ALL); phy_reg_write(phyBase, phyAddr, ADM_PHY_CONTROL, ADM_CTRL_AUTONEGOTIATION_ENABLE | ADM_CTRL_START_AUTONEGOTIATION); } /* * Wait up to .75 seconds for ALL associated PHYs to finish * autonegotiation. The only way we get out of here sooner is * if ALL PHYs are connected AND finish autonegotiation. */ timeout=5; for (phyUnit=0; (phyUnit < ADM_PHY_MAX) /*&& (timeout > 0) */; phyUnit++) { if (!ADM_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } for (;;) { phyBase = ADM_PHYBASE(phyUnit); phyAddr = ADM_PHYADDR(phyUnit); phyHwStatus = phy_reg_read(phyBase, phyAddr, ADM_PHY_STATUS); if (ADM_AUTONEG_DONE(phyHwStatus)) { DRV_PRINT(DRV_DEBUG_PHYSETUP, ("Port %d, Neg Success\n", phyUnit)); break; } if (timeout == 0) { DRV_PRINT(DRV_DEBUG_PHYSETUP, ("Port %d, Negogiation timeout\n", phyUnit)); break; } if (--timeout == 0) { DRV_PRINT(DRV_DEBUG_PHYSETUP, ("Port %d, Negogiation timeout\n", phyUnit)); break; } mdelay(150); } } /* * All PHYs have had adequate time to autonegotiate. * Now initialize software status. * * It's possible that some ports may take a bit longer * to autonegotiate; but we can't wait forever. They'll * get noticed by mv_phyCheckStatusChange during regular * polling activities. */ for (phyUnit=0; phyUnit < ADM_PHY_MAX; phyUnit++) { if (!ADM_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } if (adm_phyIsLinkAlive(phyUnit)) { liveLinks++; ADM_IS_PHY_ALIVE(phyUnit) = TRUE; } else { ADM_IS_PHY_ALIVE(phyUnit) = FALSE; } DRV_PRINT(DRV_DEBUG_PHYSETUP, ("eth%d: Phy Status=%4.4x\n", ethUnit, phy_reg_read(ADM_PHYBASE(phyUnit), ADM_PHYADDR(phyUnit), ADM_PHY_STATUS))); } #ifdef CONFIG_MV6060 /* added by lsz 30Apri07 to configure port vlan registers */ /**************************************************************************** Port VLan: --------------------------------------------------------------- | | Port6 | Port5 | Port4 | Port3 | Port2 | Port1 | Port0 | --------------------------------------------------------------- | Port0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------- | Port1 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | --------------------------------------------------------------- | Port2 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | --------------------------------------------------------------- | Port3 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | --------------------------------------------------------------- | Port4 | 0 | 1 | 0 | 1 | 1 | 1 | 0 | --------------------------------------------------------------- | Port5 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | --------------------------------------------------------------- | Port6 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------- Port 0: Wan Port 1~4: Lan e.g. Port 0 is 010 0000, i.e. 0x20. ****************************************************************************/ #define PORT_VALN_MAP_REG 0x06 uint32_t portAddr[7] = {0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE}; phy_reg_write(0, portAddr[0], PORT_VALN_MAP_REG, 0x103E); phy_reg_write(0, portAddr[1], PORT_VALN_MAP_REG, 0x103D); phy_reg_write(0, portAddr[2], PORT_VALN_MAP_REG, 0x103B); phy_reg_write(0, portAddr[3], PORT_VALN_MAP_REG, 0x1037); phy_reg_write(0, portAddr[4], PORT_VALN_MAP_REG, 0x102F); phy_reg_write(0, portAddr[5], PORT_VALN_MAP_REG, 0x101F); /* phy_reg_write(0, portAddr[0], PORT_VALN_MAP_REG, 0x1020); phy_reg_write(0, portAddr[1], PORT_VALN_MAP_REG, 0x103C); phy_reg_write(0, portAddr[2], PORT_VALN_MAP_REG, 0x103A); phy_reg_write(0, portAddr[3], PORT_VALN_MAP_REG, 0x1036); phy_reg_write(0, portAddr[4], PORT_VALN_MAP_REG, 0x102E); phy_reg_write(0, portAddr[5], PORT_VALN_MAP_REG, 0x101F);*/ //phy_reg_write(0, portAddr[6], PORT_VALN_MAP_REG, 0x0000); /* added by lsz to configure header mode registers */ #define PORT_CONTROL_REG 0x04 uint16_t reg_data = 0x8803; /* Flow Control | Header Mode | Forwarding */ phy_reg_write(0, portAddr[0], PORT_CONTROL_REG, 0x8003); phy_reg_write(0, portAddr[1], PORT_CONTROL_REG, 0x8003); phy_reg_write(0, portAddr[2], PORT_CONTROL_REG, 0x8003); phy_reg_write(0, portAddr[3], PORT_CONTROL_REG, 0x8003); phy_reg_write(0, portAddr[4], PORT_CONTROL_REG, 0x8003); phy_reg_write(0, portAddr[5], PORT_CONTROL_REG, 0x8003); phy_reg_write(0, 0x1E, PORT_CONTROL_REG, reg_data); #else /* * XXX */ phy_reg_write(0, 0, 0x10, 0x50); #endif return (liveLinks > 0); }
int ethernetext_init(ethernet_cfg_t *p_ethcfg) { int32_t i; uint16_t val; CPGSTBCR7 &= ~(CPG_STBCR7_BIT_MSTP74); /* enable ETHER clock */ /* P4_2(PHY Reset) */ GPIOP4 &= ~0x0004; /* Outputs low level */ GPIOPMC4 &= ~0x0004; /* Port mode */ GPIOPM4 &= ~0x0004; /* Output mode */ /* GPIO P1 P1_14(ET_COL) */ GPIOPMC1 |= 0x4000; GPIOPFCAE1 &= ~0x4000; GPIOPFCE1 |= 0x4000; GPIOPFC1 |= 0x4000; /* P3_0(ET_TXCLK), P3_3(ET_MDIO), P3_4(ET_RXCLK), P3_5(ET_RXER), P3_6(ET_RXDV) */ GPIOPMC3 |= 0x0079; GPIOPFCAE3 &= ~0x0079; GPIOPFCE3 &= ~0x0079; GPIOPFC3 |= 0x0079; GPIOPIPC3 |= 0x0079; /* P5_9(ET_MDC) */ GPIOPMC5 |= 0x0200; GPIOPFCAE5 &= ~0x0200; GPIOPFCE5 &= ~0x0200; GPIOPFC5 |= 0x0200; GPIOPIPC5 |= 0x0200; /* P10_1(ET_TXER), P10_2(ET_TXEN), P10_3(ET_CRS), P10_4(ET_TXD0), P10_5(ET_TXD1) */ /* P10_6(ET_TXD2), P10_7(ET_TXD3), P10_8(ET_RXD0), P10_9(ET_RXD1), P10_10(ET_RXD2), P10_11(ET_RXD3) */ GPIOPMC10 |= 0x0FFE; GPIOPFCAE10 &= ~0x0FFE; GPIOPFCE10 |= 0x0FFE; GPIOPFC10 |= 0x0FFE; GPIOPIPC10 |= 0x0FFE; /* Resets the E-MAC,E-DMAC */ lan_reg_reset(); /* PHY Reset */ GPIOP4 &= ~0x0004; /* P4_2 Outputs low level */ wait_100us(250); /* 25msec */ GPIOP4 |= 0x0004; /* P4_2 Outputs high level */ wait_100us(100); /* 10msec */ /* Resets the PHY-LSI */ phy_reg_write(BASIC_MODE_CONTROL_REG, 0x8000); for (i = 10000; i > 0; i--) { val = phy_reg_read(BASIC_MODE_CONTROL_REG); if (((uint32_t)val & 0x8000uL) == 0) { break; /* Reset complete */ } } phy_id = ((uint32_t)phy_reg_read(PHY_IDENTIFIER1_REG) << 16) | (uint32_t)phy_reg_read(PHY_IDENTIFIER2_REG); Interrupt_priority = p_ethcfg->int_priority; p_recv_cb_fnc = p_ethcfg->recv_cb; start_stop = 1; if (p_ethcfg->ether_mac != NULL) { (void)memcpy(mac_addr, p_ethcfg->ether_mac, sizeof(mac_addr)); } else { ethernet_address(mac_addr); /* Get MAC Address */ } return 0; }
/***************************************************************************** * * ip_phyShow - Dump the state of a PHY. * There are two sets of registers for each phy port: * "phy registers" and * "switch port registers" * We dump 'em all, plus the switch global registers. */ void ip_phyShow(int phyUnit) { int i; uint16_t value; uint32_t phyBase; uint32_t phyAddr; if (!ip_validPhyId(phyUnit)) { return; } phyBase = IP_PHYBASE(phyUnit); phyAddr = IP_PHYADDR(phyUnit); printk("PHY state for PHY%d (enet%d, phyBase 0x%8x, phyAddr 0x%x)\n", phyUnit, IP_ETHUNIT(phyUnit), IP_PHYBASE(phyUnit), IP_PHYADDR(phyUnit)); printk("PHY Registers:\n"); for (i=0; i < ipPhyNumRegs; i++) { value = phy_reg_read(phyBase, phyAddr, ipPhyRegisterTable[i].regNum); printk("Reg %02d (0x%02x) %s = 0x%08x\n", ipPhyRegisterTable[i].regNum, ipPhyRegisterTable[i].regNum, ipPhyRegisterTable[i].regIdString, value); } phyBase = IP_GLOBALREGBASE; printk("Switch Global Registers:\n"); printk("Phy29 Registers:\n"); for (i=0; i < ipPhy29GlobalNumRegs; i++) { value = phy_reg_read(phyBase, IP_GLOBAL_PHY29_ADDR, ipPhy29GlobalRegisterTable[i].regNum); printk("Reg %02d (0x%02x) %s = 0x%08x\n", ipPhy29GlobalRegisterTable[i].regNum, ipPhy29GlobalRegisterTable[i].regNum, ipPhy29GlobalRegisterTable[i].regIdString, value); } printk("Phy30 Registers:\n"); for (i=0; i < ipPhy30GlobalNumRegs; i++) { value = phy_reg_read(phyBase, IP_GLOBAL_PHY30_ADDR, ipPhy30GlobalRegisterTable[i].regNum); printk("Reg %02d (0x%02x) %s = 0x%08x\n", ipPhy30GlobalRegisterTable[i].regNum, ipPhy30GlobalRegisterTable[i].regNum, ipPhy30GlobalRegisterTable[i].regIdString, value); } printk("Phy31 Registers:\n"); for (i=0; i < ipPhy31GlobalNumRegs; i++) { value = phy_reg_read(phyBase, IP_GLOBAL_PHY31_ADDR, ipPhy31GlobalRegisterTable[i].regNum); printk("Reg %02d (0x%02x) %s = 0x%08x\n", ipPhy31GlobalRegisterTable[i].regNum, ipPhy31GlobalRegisterTable[i].regNum, ipPhy31GlobalRegisterTable[i].regIdString, value); } }
BOOL ip_phySetup(int ethUnit) { int phyUnit; uint16_t phyHwStatus; uint16_t timeout; int liveLinks = 0; uint32_t phyBase = 0; BOOL foundPhy = FALSE; uint32_t phyAddr; /* Reset PHYs*/ for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) { if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } phyBase = IP_PHYBASE(phyUnit); phyAddr = IP_PHYADDR(phyUnit); phy_reg_write(phyBase, phyAddr, IP_PHY_CONTROL, IP_CTRL_SOFTWARE_RESET); } /* * After the phy is reset, it takes a little while before * it can respond properly. */ mdelay(300); /* Verify that the switch is what we think it is, and that it's ready */ ip_verifyReady(ethUnit); /* See if there's any configuration data for this enet */ for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) { if (IP_ETHUNIT(phyUnit) != ethUnit) { continue; } phyBase = IP_PHYBASE(phyUnit); foundPhy = TRUE; break; } if (!foundPhy) { return FALSE; /* No PHY's configured for this ethUnit */ } #ifdef COBRA_TODO /* Initialize global switch settings */ /* Initialize the aging time */ /* Set the learning properties */ #endif /* start auto negogiation on each phy */ for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) { if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } phyBase = IP_PHYBASE(phyUnit); phyAddr = IP_PHYADDR(phyUnit); phy_reg_write(phyBase, phyAddr, IP_AUTONEG_ADVERT, IP_ADVERTISE_ALL); phy_reg_write(phyBase, phyAddr, IP_PHY_CONTROL, IP_CTRL_AUTONEGOTIATION_ENABLE | IP_CTRL_START_AUTONEGOTIATION); } /* * Wait up to .75 seconds for ALL associated PHYs to finish * autonegotiation. The only way we get out of here sooner is * if ALL PHYs are connected AND finish autonegotiation. */ timeout=5; for (phyUnit=0; (phyUnit < IP_PHY_MAX) /*&& (timeout > 0) */; phyUnit++) { if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } for (;;) { phyBase = IP_PHYBASE(phyUnit); phyAddr = IP_PHYADDR(phyUnit); phyHwStatus = phy_reg_read(phyBase, phyAddr, IP_PHY_STATUS); if (IP_AUTONEG_DONE(phyHwStatus)) { DRV_PRINT(DRV_DEBUG_PHYSETUP, ("Port %d, Neg Success\n", phyUnit)); break; } if (timeout == 0) { DRV_PRINT(DRV_DEBUG_PHYSETUP, ("Port %d, Negogiation timeout\n", phyUnit)); break; } if (--timeout == 0) { DRV_PRINT(DRV_DEBUG_PHYSETUP, ("Port %d, Negogiation timeout\n", phyUnit)); break; } mdelay(150); } } /* * All PHYs have had adequate time to autonegotiate. * Now initialize software status. * * It's possible that some ports may take a bit longer * to autonegotiate; but we can't wait forever. They'll * get noticed by mv_phyCheckStatusChange during regular * polling activities. */ for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) { if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } if (ip_phyIsLinkAlive(phyUnit)) { liveLinks++; IP_IS_PHY_ALIVE(phyUnit) = TRUE; } else { IP_IS_PHY_ALIVE(phyUnit) = FALSE; } DRV_PRINT(DRV_DEBUG_PHYSETUP, ("eth%d: Phy Status=%4.4x\n", ethUnit, phy_reg_read(IP_PHYBASE(phyUnit), IP_PHYADDR(phyUnit), IP_PHY_STATUS))); } ip_VLANInit(ethUnit); return (liveLinks > 0); }
static void ip_verifyReady(int ethUnit) { int phyUnit; uint32_t phyBase = 0; uint32_t phyAddr; uint16_t phyID1; uint16_t phyID2; /* * The first read to the Phy port registers always fails and * returns 0. So get things started with a bogus read. */ for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) { if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } phyBase = IP_PHYBASE(phyUnit); phyAddr = IP_PHYADDR(phyUnit); phyID1 = phy_reg_read(phyBase, phyAddr, IP_PHY_ID1); /* returns 0 */ break; } for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) { if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } /*******************/ /* Verify phy port */ /*******************/ phyBase = IP_PHYBASE(phyUnit); phyAddr = IP_PHYADDR(phyUnit); phyID1 = phy_reg_read(phyBase, phyAddr, IP_PHY_ID1); if (phyID1 != IP_PHY_ID1_EXPECTATION) { DRV_PRINT(DRV_DEBUG_PHYERROR, ("Invalid PHY ID1 for enet%d port%d. Expected 0x%04x, read 0x%04x\n", ethUnit, phyUnit, IP_PHY_ID1_EXPECTATION, phyID1)); return; } phyID2 = phy_reg_read(phyBase, phyAddr, IP_PHY_ID2); if ((phyID2 & IP_OUI_LSB_MASK) != IP_OUI_LSB_EXPECTATION) { DRV_PRINT(DRV_DEBUG_PHYERROR, ("Invalid PHY ID2 for enet%d port %d. Expected 0x%04x, read 0x%04x\n", ethUnit, phyUnit, IP_OUI_LSB_EXPECTATION, phyID2)); return; } DRV_PRINT(DRV_DEBUG_PHYSETUP, ("Found PHY enet%d port%d: model 0x%x revision 0x%x\n", ethUnit, phyUnit, (phyID2 & IP_MODEL_NUM_MASK) >> IP_MODEL_NUM_SHIFT, (phyID2 & IP_REV_NUM_MASK) >> IP_REV_NUM_SHIFT)); } }