📄 phy.c
字号:
/* * This source code has been made available to you by IBM on an AS-IS * basis. Anyone receiving this source is licensed under IBM * copyrights to use it in any way he or she deems fit, including * copying it, modifying it, compiling it, and redistributing it either * with or without modifications. No license under IBM patents or * patent applications is to be implied by the copyright license. * * Any user of this software should understand that IBM cannot provide * technical support for this software and will not be responsible for * any consequences resulting from the use of this software. * * Any person who transfers this source code or any derivative work * must include the IBM copyright notice, this paragraph, and the * preceding two paragraphs in the transferred software. * * COPYRIGHT I B M CORPORATION 1995 * LICENSED MATERIAL - PROGRAM PROPERTY OF I B M * * File Name: phy.c * * Function: This module has utilities for accessing the DP83843 PHY * through the EMAC3 macro. * * Author: Mark Wisner * * Change Activity- * * Date Description of Change BY * --------- --------------------- --- * 05-May-99 Created MKW * 01-Jul-99 Changed clock setting of sta_reg from 66Mhz to 50Mhz to * better match OPB speed. Also modified delay times. JWB * 29-Jul-99 Added Full duplex support MKW * 24-Aug-99 Removed s1printf from dp83843_duplex() JWB * 20-Apr-00 Integrated into the MicroMonitor platform. ELS * 22-Sep-00 Converted to generic "phy_" (from dp83843_) names. ELS * * General notice: * This code is part of a boot-monitor package developed as a generic base * platform for embedded system designs. As such, it is likely to be * distributed to various projects beyond the control of the original * author. Please notify the author of any enhancements made or bugs found * so that all may benefit from the changes. In addition, notification back * to the author will allow the new user to pick up changes that may have * been made by other users after this version of the code was distributed. * * Author: Ed Sutter * email: esutter@lucent.com (home: lesutter@worldnet.att.net) * phone: 908-582-2351 (home: 908-889-5161) */#include "genlib.h"#include "stddefs.h"#include "cpuio.h"#include "phy.h"#include "enetemac.h"#ifndef TRUE#define TRUE 1#endif#ifndef FALSE#define FALSE 0#endif#define EMAC_STACR_CLK_FREQ EMAC_STACR_CLK_100MHZ/* local wait routine to burn some time */static void local_wait(void){ volatile int i; for(i=0;i<10000;i++);}/* * Dump out to the screen PHY regs */intphy_dump(){ ulong i; ushort data; for(i=0; i<0x1A; i++) { if(phy_read(i, &data)) { printf("read error for reg %lx\n",i); return -1; } printf("Phy reg 0x%lx ==> 0x%x\n",i,data); /* jump to the next set of regs */ if(i == 0x07) i = 0x0f; } return(0);}/* * phy_read(): * Read a PHY reg and return the value and a return code. */intphy_read(ulong reg, ushort *value){ ulong sta_reg; volatile int timeout; /* Wait for "Operation Complete" flag... */ for(timeout=50000;timeout>0;timeout--) { if (*(ulong *)(EMAC_STACR) & EMAC_STACR_OC) break; } if(timeout == 0) { printf("phy_read err1\n"); return -1; } /* set clock and read flags */ sta_reg = EMAC_STACR_READ | EMAC_STACR_CLK_FREQ | reg | (PHY_ADDR << 5); *(ulong *)(EMAC_STACR) = sta_reg; sta_reg = *(ulong *)(EMAC_STACR); timeout=0; while((sta_reg & EMAC_STACR_OC) == 0) { local_wait(); if(timeout > 5) { printf("phy_read err2\n"); return -1; } timeout++; sta_reg = *(ulong *)(EMAC_STACR); } if ((sta_reg & EMAC_STACR_PHYE) != 0) { printf("phy_read err3\n"); return -1; } *value = (short)(sta_reg >> 16); return 0; } /* * write a phy reg and return the value with a rc */intphy_write(uchar reg, ushort value){ ulong sta_reg; /* STA scratch area */ ulong i; /* see if it is ready for 1000 nsec */ i=0; while((*(ulong *)(EMAC_STACR) & EMAC_STACR_OC) == 0) { if(i>5) { printf("phy_write err1\n"); return(-1); } local_wait(); i++; } sta_reg=0; sta_reg = reg; /* reg address */ /* set clock and read flags */ sta_reg = (sta_reg | EMAC_STACR_WRITE | EMAC_STACR_CLK_FREQ); sta_reg = sta_reg | ((ulong)PHY_ADDR << 5); /* Phy address */ memcpy((char *)&sta_reg,(char *)&value,2); /* put in data */ *(ulong *)(EMAC_STACR) = sta_reg; /* wait for completion */ i=0; sta_reg = *(ulong *)(EMAC_STACR); while((sta_reg & EMAC_STACR_OC) == 0) { local_wait(); if(i > 5) { printf("phy_write err1\n"); return -1; } i++; sta_reg = *(ulong *)(EMAC_STACR); } if ((sta_reg & EMAC_STACR_PHYE) != 0) { printf("phy_write err3\n"); return -1; } return 0; }/* * phy_reset(): * Issue a soft reset to the PHY: */voidphy_reset(void){ /* Set the reset bit to reset. This is a self-clearing * bit and causes a partial reset of the device. */ phy_write(PHY_BMCR,PHY_BMCR_RESET);}/* * phy_linkup(): * Return 1 if link is up, else 0. */intphy_linkup(void){ ushort stat; phy_read(PHY_BMSR,&stat); if (stat & PHY_BMSR_LS) return(1); else return(0);}/* * phy_autoneg(): * Go through the auto-negotiation process... */intphy_autoneg(int retries,int* is100MbpsP,int *isFullDuplexP){ ushort ctrl, stat, autoneg; if (retries == 0) retries = 1000; autoneg = PHY_ANAR_802_3; phy_read(PHY_BMCR,&ctrl); ctrl |= PHY_BMCR_RESET; phy_write((ulong)PHY_BMCR, (ulong)ctrl); while(1) { phy_read(PHY_BMCR,&ctrl); if ((ctrl & PHY_BMCR_RESET) == 0) break; } ctrl &= ~(PHY_BMCR_LOOP | PHY_BMCR_POWD | PHY_BMCR_ISO | PHY_BMCR_COL_TST); ctrl |= (PHY_BMCR_AUTON); phy_write(PHY_BMCR, ctrl); phy_read(PHY_BMSR,&stat); /* This driver relies on PHY being capable of auto-negotiation */ if((stat & PHY_BMSR_AUTN_ABLE) == 0) { printf("AutoNegotiate: PHY does not support AUTO Negotiation\n"); return (-1); } /* Determine PHY capabilities to be advertised during auto-negotiation */ if((stat & PHY_BMSR_100HDX) && (*is100MbpsP == TRUE)) { autoneg |= PHY_ANAR_100HDX; if((stat & PHY_BMSR_100FDX) && (*isFullDuplexP == TRUE)) autoneg |= PHY_ANAR_100FDX; } if(stat & PHY_BMSR_10HDX) { autoneg |= PHY_ANAR_10HDX; if((stat & PHY_BMSR_10FDX) && (*isFullDuplexP == TRUE)) autoneg |= PHY_ANAR_10FDX; } phy_write(PHY_ANAR, autoneg); /* Restart auto-negotiation process */ phy_read(PHY_BMCR,&ctrl); ctrl |= PHY_BMCR_RESTART; phy_write(PHY_BMCR, ctrl); do { phy_read(PHY_BMSR,&stat); if((stat & PHY_BMSR_RFAULT) != 0) { printf("Autonegotiate: remote fault\n"); return -1; } retries -= 1; /* Decrement retry count */ } while((retries != 0) && ((stat & PHY_BMSR_AUTN_COMP) == 0)); phy_read(PHY_ANLPAR,&autoneg); if((autoneg & PHY_ANLPAR_RFAULT) != 0) { printf("Autonegotiate: remote fault\n"); return -1; } phy_read(PHY_BMCR,&ctrl); /* Select 100 Mbps if this PHY is 100Base-TX capable, the driver asked for 100Mbps and not only 10Mbps, and the link partner responded with 100Base-TX or did not respond at all. The "no response" behavior is done to allow a wire to be plugged in later and have the PHY negotiate the best speed. */ if((stat & PHY_BMSR_100HDX) && (*is100MbpsP == TRUE) && ((autoneg & PHY_ANLPAR_100HDX) || (!(autoneg & PHY_ANLPAR_ACK)))) { ctrl |= PHY_BMCR_100MB; *is100MbpsP = TRUE; } else /* Use only 10Mbps, because of options or link partner */ { ctrl &= (~(PHY_BMCR_100MB)); *is100MbpsP = FALSE; } if ((autoneg & PHY_ANLPAR_ACK) && (*isFullDuplexP == TRUE) && (((*is100MbpsP == TRUE) && (stat & PHY_BMSR_100FDX) && (autoneg & PHY_ANLPAR_100FDX)) || ((*is100MbpsP == FALSE) && (stat & PHY_BMSR_10FDX) && (autoneg & PHY_ANLPAR_10FDX)))) { /* Select full duplex if link partner responded and both the link partner and this PHY are full duplex capable */ ctrl |= PHY_BMCR_FDPLX; *isFullDuplexP = TRUE; } else /* Use only half duplex, because of options or link partner */ { ctrl &= (~(PHY_BMCR_FDPLX)); *isFullDuplexP = FALSE; } phy_write(PHY_BMCR, ctrl); if(retries == 0) { printf("Autonegotiate: Timeout\n"); return -1; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -