⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 phy.c

📁 完整的Bell实验室的嵌入式文件系统TFS
💻 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 + -