📄 ipphy.c
字号:
/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved. *//* * Manage the ICPLUS ethernet PHY. * * All definitions in this file are operating system independent! */#include <config.h>#include <linux/types.h>#include <common.h>#include <miiphy.h>#include "phy.h"#include "ipPhy.h"#define mdelay(_x) udelay((_x) * 1000)/* PHY selections and access functions */typedef enum { PHY_SRCPORT_INFO, PHY_PORTINFO_SIZE,} PHY_CAP_TYPE;typedef enum { PHY_SRCPORT_NONE, PHY_SRCPORT_VLANTAG, PHY_SRCPORT_TRAILER,} PHY_SRCPORT_TYPE;#ifdef DEBUG#define DRV_DEBUG 1#endif#define DRV_DEBUG 1#if DRV_DEBUG#define DRV_DEBUG_PHYERROR 0x00000001#define DRV_DEBUG_PHYCHANGE 0x00000002#define DRV_DEBUG_PHYSETUP 0x00000004int ipPhyDebug = DRV_DEBUG_PHYERROR;#define DRV_LOG(FLG, X0, X1, X2, X3, X4, X5, X6) \{ \ if (ipPhyDebug & (FLG)) { \ logMsg(X0, X1, X2, X3, X4, X5, X6); \ } \}#define DRV_MSG(x,a,b,c,d,e,f) \ logMsg(x,a,b,c,d,e,f)#define DRV_PRINT(FLG, X) \{ \ if (ipPhyDebug & (FLG)) { \ printf X; \ } \}#else /* !DRV_DEBUG */#define DRV_LOG(DBG_SW, X0, X1, X2, X3, X4, X5, X6)#define DRV_MSG(x,a,b,c,d,e,f)#define DRV_PRINT(DBG_SW,X)#endif#define IP_LAN_PORT_VLAN 1#define IP_WAN_PORT_VLAN 2#define ENET_UNIT_DEFAULT 0#define BOOL uint32_t#define TRUE 1#define FALSE 0/* * Track per-PHY port information. */typedef struct { BOOL isEnetPort; /* normal enet port */ BOOL isPhyAlive; /* last known state of link */ int ethUnit; /* MAC associated with this phy port */ uint32_t phyBase; uint32_t phyAddr; /* PHY registers associated with this phy port */ uint32_t VLANTableSetting; /* Value to be written to VLAN table */} ipPhyInfo_t;/* * Per-PHY information, indexed by PHY unit number. */ipPhyInfo_t ipPhyInfo[] = { /* * On AP30/AR5312, all PHYs are associated with MAC0. * AP30/AR5312's MAC1 isn't used for anything. * CONFIG_VENETDEV==1 (router) configuration: * Ports 0,1,2, and 3 are "LAN ports" * Port 4 is a WAN port * Port 5 connects to MAC0 in the AR5312 * CONFIG_VENETDEV==0 (bridge) configuration: * Ports 0,1,2,3,4 are "LAN ports" * Port 5 connects to the MAC0 in the AR5312 */ {TRUE, /* phy port 0 -- LAN port 0 */ FALSE, ENET_UNIT_DEFAULT, 0, IP_PHY0_ADDR, IP_LAN_PORT_VLAN }, {TRUE, /* phy port 1 -- LAN port 1 */ FALSE, ENET_UNIT_DEFAULT, 0, IP_PHY1_ADDR, IP_LAN_PORT_VLAN }, {TRUE, /* phy port 2 -- LAN port 2 */ FALSE, ENET_UNIT_DEFAULT, 0, IP_PHY2_ADDR, IP_LAN_PORT_VLAN }, {TRUE, /* phy port 3 -- LAN port 3 */ FALSE, ENET_UNIT_DEFAULT, 0, IP_PHY3_ADDR, IP_LAN_PORT_VLAN }, {TRUE, /* phy port 4 -- WAN port or LAN port 4 */ FALSE, ENET_UNIT_DEFAULT, 0, IP_PHY4_ADDR, IP_LAN_PORT_VLAN /* Send to all ports */ }, {FALSE, /* phy port 5 -- CPU port (no RJ45 connector) */ TRUE, ENET_UNIT_DEFAULT, 0, 0x00, IP_LAN_PORT_VLAN /* Send to all ports */ },};#define IP_GLOBALREGBASE 0#define IP_PHY_MAX (sizeof(ipPhyInfo) / sizeof(ipPhyInfo[0]))/* Range of valid PHY IDs is [MIN..MAX] */#define IP_ID_MIN 0#define IP_ID_MAX (IP_PHY_MAX-1)/* Convenience macros to access myPhyInfo */#define IP_IS_ENET_PORT(phyUnit) (ipPhyInfo[phyUnit].isEnetPort)#define IP_IS_PHY_ALIVE(phyUnit) (ipPhyInfo[phyUnit].isPhyAlive)#define IP_ETHUNIT(phyUnit) (ipPhyInfo[phyUnit].ethUnit)#define IP_PHYBASE(phyUnit) (ipPhyInfo[phyUnit].phyBase)#define IP_PHYADDR(phyUnit) (ipPhyInfo[phyUnit].phyAddr)#define IP_VLAN_TABLE_SETTING(phyUnit) (ipPhyInfo[phyUnit].VLANTableSetting)#define IP_IS_ETHUNIT(phyUnit, ethUnit) \ (IP_IS_ENET_PORT(phyUnit) && \ IP_ETHUNIT(phyUnit) == (ethUnit))/* Forward references */BOOL ip_phyIsLinkAlive(int phyUnit);static void ip_VLANInit(int ethUnit);static void ip_verifyReady(int ethUnit);#ifdef DEBUGvoid ip_phyShow(int phyUnit);void ip_phySet(int phyUnit, uint32_t regnum, uint32_t value);void ip_globalSet(uint32_t phyAddr, uint32_t regnum, uint32_t value);#endifuint16_tphyRegRead(uint32_t phybase, uint16_t phyaddr, uint16_t reg){ uint16_t val; phy_reg_read(phybase, phyaddr, reg, &val); return val;}voidphyRegWrite(uint32_t phybase, uint16_t phyaddr, uint16_t reg, uint32_t val){ phy_reg_write(phybase, phyaddr, reg, val);}/******************************************************************************** ip_phyIsLinkAlive - test to see if the specified link is alive** RETURNS:* TRUE --> link is alive* FALSE --> link is down*/BOOLip_phyIsLinkAlive(int phyUnit){ uint16_t phyHwStatus; uint32_t phyBase; uint32_t phyAddr; phyBase = IP_PHYBASE(phyUnit); phyAddr = IP_PHYADDR(phyUnit); phyHwStatus = phyRegRead(phyBase, phyAddr, IP_PHY_STATUS); if (phyHwStatus & IP_STATUS_LINK_PASS) { return TRUE; } else { return FALSE; }}/******************************************************************************** ip_VLANInit - initialize "port-based VLANs" for the specified enet unit.*/static voidip_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; } phyRegWrite(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 = phyRegRead(phyBase, IP_GLOBAL_PHY30_ADDR, IP_GLOBAL_PHY30_1_REG); phyReg = phyReg | ((1 << phyUnit) << IP_VLAN1_OUTPUT_PORT_MASK_S); phyRegWrite(phyBase, IP_GLOBAL_PHY30_ADDR, IP_GLOBAL_PHY30_1_REG, phyReg); } phyReg = phyRegRead(phyBase, IP_GLOBAL_PHY30_ADDR, IP_GLOBAL_PHY30_9_REG); phyReg = phyReg | TAG_VLAN_ENABLE; phyReg = phyReg & ~VID_INDX_SEL_M; phyRegWrite(phyBase, IP_GLOBAL_PHY30_ADDR, IP_GLOBAL_PHY30_9_REG, phyReg);}static voidip_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 = phyRegRead(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 = phyRegRead(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 = phyRegRead(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)); }}/******************************************************************************** ip_phySetup - reset and setup the PHY associated with* the specified MAC unit number.** Resets the associated PHY port.** RETURNS:* TRUE --> associated PHY is alive* FALSE --> no LINKs on this ethernet unit*/BOOLip_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); phyRegWrite(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); phyRegWrite(phyBase, phyAddr, IP_AUTONEG_ADVERT, IP_ADVERTISE_ALL); phyRegWrite(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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -