📄 mvphy.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 ethernet PHY switch, Marvell 88E6060.* * This module is intended to be largely OS and platform-independent.*/#if defined(linux)#include <linux/config.h>#include <linux/types.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/delay.h>#include "ar531xlnx.h"#endif#if defined(__ECOS)#include "ae531xecos.h"#endif#include "ae531xmac.h"#include "ae531xreg.h"#include "mvPhy.h"#if /* DEBUG */ 1#define MV_DEBUG_ERROR 0x00000001#define MV_DEBUG_PHYSETUP 0x00000002#define MV_DEBUG_PHYCHANGE 0x00000004int mvPhyDebug = MV_DEBUG_ERROR;#define MV_PRINT(FLG, X) \{ \ if (mvPhyDebug & (FLG)) { \ DEBUG_PRINTF X; \ } \}#else#define MV_PRINT(FLG, X)#endif#ifdef CONFIG_VENETDEV_ATH/* * On AR5312 with CONFIG_VENETDEV==1, * ports 0..3 are LAN ports (accessed through ae0) * port 4 is the WAN port. (accessed through ae1) * * The phy switch settings in the mvPhyInfo table are set accordingly. */#define MV_WAN_PORT 4#define MV_IS_LAN_PORT(port) ((port) < MV_WAN_PORT)#define MV_IS_WAN_PORT(port) ((port) == MV_WAN_PORT)#endif/* * 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 phyBase; UINT32 phyAddr; /* PHY registers associated with this phy port */ UINT32 switchPortAddr; /* switch port regs assoc'ed with this phy port */ UINT32 VLANTableSetting; /* Value to be written to VLAN table */} mvPhyInfo_t;/****************************************************************************** * Per-PHY information, indexed by PHY unit number. * * This table is board-dependent. It includes information * about which enet MAC controls which PHY port. */mvPhyInfo_t mvPhyInfo[] = { /* * 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 */ {isEnetPort: TRUE, /* phy port 0 -- LAN port 0 */ isPhyAlive: FALSE, ethUnit: 0, phyBase: 0, phyAddr: 0x10, switchPortAddr: 0x18,#ifdef CONFIG_VENETDEV_ATH VLANTableSetting: 0x2e#else VLANTableSetting: 0x3e#endif }, {isEnetPort: TRUE, /* phy port 1 -- LAN port 1 */ isPhyAlive: FALSE, ethUnit: 0, phyBase: 0, phyAddr: 0x11, switchPortAddr: 0x19,#ifdef CONFIG_VENETDEV_ATH VLANTableSetting: 0x2d#else VLANTableSetting: 0x3d#endif }, {isEnetPort: TRUE, /* phy port 2 -- LAN port 2 */ isPhyAlive: FALSE, ethUnit: 0, phyBase: 0, phyAddr: 0x12, switchPortAddr: 0x1a,#ifdef CONFIG_VENETDEV_ATH VLANTableSetting: 0x2b#else VLANTableSetting: 0x3b#endif }, {isEnetPort: TRUE, /* phy port 3 -- LAN port 3 */ isPhyAlive: FALSE, ethUnit: 0, phyBase: 0, phyAddr: 0x13, switchPortAddr: 0x1b,#ifdef CONFIG_VENETDEV_ATH VLANTableSetting: 0x27#else VLANTableSetting: 0x37#endif }, {isEnetPort: TRUE, /* phy port 4 -- WAN port or LAN port 4 */ isPhyAlive: FALSE, ethUnit: 0, phyBase: 0, phyAddr: 0x14, switchPortAddr: 0x1c,#ifdef CONFIG_VENETDEV_ATH VLANTableSetting: 0x1020 /* WAN port */#else VLANTableSetting: 0x2f /* LAN port 4 */#endif }, {isEnetPort: FALSE, /* phy port 5 -- CPU port (no RJ45 connector) */ isPhyAlive: TRUE, ethUnit: 0, phyBase: 0, phyAddr: 0x15, switchPortAddr: 0x1d,#ifdef CONFIG_VENETDEV_ATH VLANTableSetting: 0x0f /* Send only to LAN ports */#else VLANTableSetting: 0x1f /* Send to all ports */#endif },};#define MV_PHY_MAX (sizeof(mvPhyInfo) / sizeof(mvPhyInfo[0]))/* Range of valid PHY IDs is [MIN..MAX] */#define MV_ID_MIN 0#define MV_ID_MAX (MV_PHY_MAX-1)/* Convenience macros to access myPhyInfo */#define MV_IS_ENET_PORT(phyUnit) (mvPhyInfo[phyUnit].isEnetPort)#define MV_IS_PHY_ALIVE(phyUnit) (mvPhyInfo[phyUnit].isPhyAlive)#define MV_ETHUNIT(phyUnit) (mvPhyInfo[phyUnit].ethUnit)#define MV_PHYBASE(phyUnit) (mvPhyInfo[phyUnit].phyBase)#define MV_PHYADDR(phyUnit) (mvPhyInfo[phyUnit].phyAddr)#define MV_SWITCH_PORT_ADDR(phyUnit) (mvPhyInfo[phyUnit].switchPortAddr)#define MV_VLAN_TABLE_SETTING(phyUnit) (mvPhyInfo[phyUnit].VLANTableSetting)#define MV_IS_ETHUNIT(phyUnit, ethUnit) \ (MV_IS_ENET_PORT(phyUnit) && \ MV_ETHUNIT(phyUnit) == (ethUnit))/* Forward references */BOOL mv_phyIsLinkAlive(int phyUnit);LOCAL void mv_VLANInit(int ethUnit);LOCAL void mv_enableConfiguredPorts(int ethUnit);LOCAL void mv_verifyReady(int ethUnit);BOOL mv_phySetup(int ethUnit, UINT32 phyBase);int mv_phyIsFullDuplex(int ethUnit);BOOL mv_phyIsSpeed100(int phyUnit);LOCAL BOOL mv_validPhyId(int phyUnit);void mv_flushATUDB(int phyUnit);void mv_phyCheckStatusChange(int ethUnit);void mv_phySet(int phyUnit, UINT32 regnum, UINT32 value);#if DEBUGvoid mv_phyShow(int phyUnit);void mv_switchPortSet(int phyUnit, UINT32 regnum, UINT32 value);void mv_switchGlobalSet(int phyUnit, UINT32 regnum, UINT32 value);void mv_showATUDB(int phyUnit);void mv_setATUDB(int phyUnit, char *mac, int dbNum);void mv_countGoodFrames(int phyUnit);void mv_countBadFrames(int phyUnit);void mv_showFrameCounts(int phyUnit);#endif/******************************************************************************** mv_phyIsLinkAlive - test to see if the specified link is alive** RETURNS:* TRUE --> link is alive* FALSE --> link is down*/BOOLmv_phyIsLinkAlive(int phyUnit){ UINT16 phyHwStatus; UINT32 phyBase; UINT32 phyAddr; phyBase = MV_PHYBASE(phyUnit); phyAddr = MV_PHYADDR(phyUnit); phyHwStatus = phyRegRead(phyBase, phyAddr, MV_PHY_SPECIFIC_STATUS); if (phyHwStatus & MV_STATUS_REAL_TIME_LINK_UP) { return TRUE; } else { return FALSE; }}/******************************************************************************** mv_VLANInit - initialize "port-based VLANs" for the specified enet unit.*/LOCAL voidmv_VLANInit(int ethUnit){ int phyUnit; UINT32 phyBase; UINT32 switchPortAddr; for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { if (MV_ETHUNIT(phyUnit) != ethUnit) { continue; } phyBase = MV_PHYBASE(phyUnit); switchPortAddr = MV_SWITCH_PORT_ADDR(phyUnit); phyRegWrite(phyBase, switchPortAddr, MV_PORT_BASED_VLAN_MAP, MV_VLAN_TABLE_SETTING(phyUnit)); MV_PRINT(MV_DEBUG_PHYSETUP,("phyBase =%x unit = %d MV_VLAN_TABLE_SETTING = %x \n",phyBase, phyUnit, MV_VLAN_TABLE_SETTING(phyUnit) )); }}#define phyPortConfigured(phyUnit) TRUE /* TBDFREEDOM2 *//******************************************************************************** mv_enableConfiguredPorts - enable whichever PHY ports are supposed* to be enabled according to administrative configuration.*/LOCAL voidmv_enableConfiguredPorts(int ethUnit){ int phyUnit; UINT32 phyBase; UINT32 switchPortAddr; UINT16 portControl = 0; UINT16 portAssociationVector; for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { if (MV_ETHUNIT(phyUnit) != ethUnit) { continue; } phyBase = MV_PHYBASE(phyUnit); switchPortAddr = MV_SWITCH_PORT_ADDR(phyUnit); if (phyPortConfigured(phyUnit)) { portControl |= MV_PORT_CONTROL_PORT_STATE_FORWARDING | MV_PORT_CONTROL_FORCE_FLOW_CTRL; #ifdef CONFIG_VENETDEV_ATH if (!MV_IS_ENET_PORT(phyUnit)) { /* CPU port */#ifndef HEADER_MODE portControl |= MV_PORT_CONTROL_INGRESS_TRAILER_MODE | MV_PORT_CONTROL_EGRESS_TRAILER_MODE;#else portControl |= MV_PORT_CONTROL_HEADER_MODE;#endif }#endif phyRegWrite(phyBase, switchPortAddr, MV_PORT_CONTROL, portControl); portAssociationVector = 1 << phyUnit; phyRegWrite(phyBase, switchPortAddr, MV_PORT_ASSOCIATION_VECTOR, portAssociationVector); } }}/******************************************************************************** mv_verifyReady - validates that we're dealing with the device* we think we're dealing with, and that it's ready.*/LOCAL voidmv_verifyReady(int ethUnit){ int phyUnit; UINT16 globalStatus; UINT32 phyBase = 0; UINT32 phyAddr; UINT32 switchPortAddr; UINT16 phyID1; UINT16 phyID2; UINT16 switchID; /* * 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 < MV_PHY_MAX; phyUnit++) { if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } phyBase = MV_PHYBASE(phyUnit); phyAddr = MV_PHYADDR(phyUnit); (void)phyRegRead(phyBase, phyAddr, MV_PHY_ID1); /* returns 0 */ break; } for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } /*******************/ /* Verify phy port */ /*******************/ phyBase = MV_PHYBASE(phyUnit); phyAddr = MV_PHYADDR(phyUnit); phyID1 = phyRegRead(phyBase, phyAddr, MV_PHY_ID1); if (phyID1 != MV_PHY_ID1_EXPECTATION) { MV_PRINT(MV_DEBUG_PHYSETUP, ("Invalid PHY ID1 for ethmac%d port%d. Expected 0x%04x, read 0x%04x\n", ethUnit, phyUnit, MV_PHY_ID1_EXPECTATION, phyID1)); return; } phyID2 = phyRegRead(phyBase, phyAddr, MV_PHY_ID2); if ((phyID2 & MV_OUI_LSB_MASK) != MV_OUI_LSB_EXPECTATION) { MV_PRINT(MV_DEBUG_PHYSETUP, ("Invalid PHY ID2 for ethmac%d port %d. Expected 0x%04x, read 0x%04x\n", ethUnit, phyUnit, MV_OUI_LSB_EXPECTATION, phyID2)); return; } MV_PRINT(MV_DEBUG_PHYSETUP, ("Found PHY ethmac%d port%d: model 0x%x revision 0x%x\n", ethUnit, phyUnit, (phyID2 & MV_MODEL_NUM_MASK) >> MV_MODEL_NUM_SHIFT, (phyID2 & MV_REV_NUM_MASK) >> MV_REV_NUM_SHIFT)); /**********************/ /* Verify switch port */ /**********************/ switchPortAddr = MV_SWITCH_PORT_ADDR(phyUnit); switchID = phyRegRead(phyBase, switchPortAddr, MV_SWITCH_ID); if ((switchID & MV_SWITCH_ID_DEV_MASK) != MV_SWITCH_ID_DEV_EXPECTATION) { MV_PRINT(MV_DEBUG_PHYSETUP, ("Invalid switch ID for ethmac%d port %d. Expected 0x%04x, read 0x%04x\n", ethUnit, phyUnit, MV_SWITCH_ID_DEV_EXPECTATION, switchID)); return; } MV_PRINT(MV_DEBUG_PHYSETUP, ("Found PHY switch for enet %d port %d deviceID 0x%x revision 0x%x\n", ethUnit, phyUnit, (switchID & MV_SWITCH_ID_DEV_MASK) >> MV_SWITCH_ID_DEV_SHIFT, (switchID & MV_SWITCH_ID_REV_MASK) >> MV_SWITCH_ID_REV_SHIFT)) } /*******************************/ /* Verify that switch is ready */ /*******************************/ if (phyBase) { globalStatus = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_SWITCH_GLOBAL_STATUS); if (!(globalStatus & MV_SWITCH_STATUS_READY_MASK)) { MV_PRINT(MV_DEBUG_PHYSETUP, ("PHY switch for ethmac%d NOT ready!\n", ethUnit)); } } else { MV_PRINT(MV_DEBUG_PHYSETUP, ("No ports configured for ethmac%d\n", ethUnit)); }#if DEBUG my_mvPhyShow(ethUnit); #endif }/******************************************************************************** mv_phySetup - reset and setup the PHY switch.** Resets each PHY port.*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -