📄 uec_phy.c
字号:
/* * Copyright (C) 2005 Freescale Semiconductor, Inc. * * Author: Shlomi Gridish * * Description: UCC GETH Driver -- PHY handling * Driver for UEC on QE * Based on 8260_io/fcc_enet.c * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * */#include "common.h"#include "net.h"#include "malloc.h"#include "asm/errno.h"#include "asm/immap_qe.h"#include "asm/io.h"#include "qe.h"#include "uccf.h"#include "uec.h"#include "uec_phy.h"#include "miiphy.h"#if defined(CONFIG_QE)#define UEC_VERBOSE_DEBUG#define ugphy_printk(format, arg...) \ printf(format "\n", ## arg)#define ugphy_dbg(format, arg...) \ ugphy_printk(format , ## arg)#define ugphy_err(format, arg...) \ ugphy_printk(format , ## arg)#define ugphy_info(format, arg...) \ ugphy_printk(format , ## arg)#define ugphy_warn(format, arg...) \ ugphy_printk(format , ## arg)#ifdef UEC_VERBOSE_DEBUG#define ugphy_vdbg ugphy_dbg#else#define ugphy_vdbg(ugeth, fmt, args...) do { } while (0)#endif /* UEC_VERBOSE_DEBUG */static void config_genmii_advert (struct uec_mii_info *mii_info);static void genmii_setup_forced (struct uec_mii_info *mii_info);static void genmii_restart_aneg (struct uec_mii_info *mii_info);static int gbit_config_aneg (struct uec_mii_info *mii_info);static int genmii_config_aneg (struct uec_mii_info *mii_info);static int genmii_update_link (struct uec_mii_info *mii_info);static int genmii_read_status (struct uec_mii_info *mii_info);u16 phy_read (struct uec_mii_info *mii_info, u16 regnum);void phy_write (struct uec_mii_info *mii_info, u16 regnum, u16 val);/* Write value to the PHY for this device to the register at regnum, *//* waiting until the write is done before it returns. All PHY *//* configuration has to be done through the TSEC1 MIIM regs */void write_phy_reg (struct eth_device *dev, int mii_id, int regnum, int value){ uec_private_t *ugeth = (uec_private_t *) dev->priv; uec_t *ug_regs; enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum; u32 tmp_reg; ug_regs = ugeth->uec_regs; /* Stop the MII management read cycle */ out_be32 (&ug_regs->miimcom, 0); /* Setting up the MII Mangement Address Register */ tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg; out_be32 (&ug_regs->miimadd, tmp_reg); /* Setting up the MII Mangement Control Register with the value */ out_be32 (&ug_regs->miimcon, (u32) value); /* Wait till MII management write is complete */ while ((in_be32 (&ug_regs->miimind)) & MIIMIND_BUSY); udelay (100000);}/* Reads from register regnum in the PHY for device dev, *//* returning the value. Clears miimcom first. All PHY *//* configuration has to be done through the TSEC1 MIIM regs */int read_phy_reg (struct eth_device *dev, int mii_id, int regnum){ uec_private_t *ugeth = (uec_private_t *) dev->priv; uec_t *ug_regs; enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum; u32 tmp_reg; u16 value; ug_regs = ugeth->uec_regs; /* Setting up the MII Mangement Address Register */ tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg; out_be32 (&ug_regs->miimadd, tmp_reg); /* Perform an MII management read cycle */ out_be32 (&ug_regs->miimcom, 0); out_be32 (&ug_regs->miimcom, MIIMCOM_READ_CYCLE); /* Wait till MII management write is complete */ while ((in_be32 (&ug_regs->miimind)) & (MIIMIND_NOT_VALID | MIIMIND_BUSY)); udelay (100000); /* Read MII management status */ value = (u16) in_be32 (&ug_regs->miimstat); if (value == 0xffff) ugphy_warn ("read wrong value : mii_id %d,mii_reg %d, base %08x", mii_id, mii_reg, (u32) & (ug_regs->miimcfg)); return (value);}void mii_clear_phy_interrupt (struct uec_mii_info *mii_info){ if (mii_info->phyinfo->ack_interrupt) mii_info->phyinfo->ack_interrupt (mii_info);}void mii_configure_phy_interrupt (struct uec_mii_info *mii_info, u32 interrupts){ mii_info->interrupts = interrupts; if (mii_info->phyinfo->config_intr) mii_info->phyinfo->config_intr (mii_info);}/* Writes MII_ADVERTISE with the appropriate values, after * sanitizing advertise to make sure only supported features * are advertised */static void config_genmii_advert (struct uec_mii_info *mii_info){ u32 advertise; u16 adv; /* Only allow advertising what this PHY supports */ mii_info->advertising &= mii_info->phyinfo->features; advertise = mii_info->advertising; /* Setup standard advertisement */ adv = phy_read (mii_info, PHY_ANAR); adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); if (advertise & ADVERTISED_10baseT_Half) adv |= ADVERTISE_10HALF; if (advertise & ADVERTISED_10baseT_Full) adv |= ADVERTISE_10FULL; if (advertise & ADVERTISED_100baseT_Half) adv |= ADVERTISE_100HALF; if (advertise & ADVERTISED_100baseT_Full) adv |= ADVERTISE_100FULL; phy_write (mii_info, PHY_ANAR, adv);}static void genmii_setup_forced (struct uec_mii_info *mii_info){ u16 ctrl; u32 features = mii_info->phyinfo->features; ctrl = phy_read (mii_info, PHY_BMCR); ctrl &= ~(PHY_BMCR_DPLX | PHY_BMCR_100_MBPS | PHY_BMCR_1000_MBPS | PHY_BMCR_AUTON); ctrl |= PHY_BMCR_RESET; switch (mii_info->speed) { case SPEED_1000: if (features & (SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)) { ctrl |= PHY_BMCR_1000_MBPS; break; } mii_info->speed = SPEED_100; case SPEED_100: if (features & (SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full)) { ctrl |= PHY_BMCR_100_MBPS; break; } mii_info->speed = SPEED_10; case SPEED_10: if (features & (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full)) break; default: /* Unsupported speed! */ ugphy_err ("%s: Bad speed!", mii_info->dev->name); break; } phy_write (mii_info, PHY_BMCR, ctrl);}/* Enable and Restart Autonegotiation */static void genmii_restart_aneg (struct uec_mii_info *mii_info){ u16 ctl; ctl = phy_read (mii_info, PHY_BMCR); ctl |= (PHY_BMCR_AUTON | PHY_BMCR_RST_NEG); phy_write (mii_info, PHY_BMCR, ctl);}static int gbit_config_aneg (struct uec_mii_info *mii_info){ u16 adv; u32 advertise; if (mii_info->autoneg) { /* Configure the ADVERTISE register */ config_genmii_advert (mii_info); advertise = mii_info->advertising; adv = phy_read (mii_info, MII_1000BASETCONTROL); adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP | MII_1000BASETCONTROL_HALFDUPLEXCAP); if (advertise & SUPPORTED_1000baseT_Half) adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP; if (advertise & SUPPORTED_1000baseT_Full) adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP; phy_write (mii_info, MII_1000BASETCONTROL, adv); /* Start/Restart aneg */ genmii_restart_aneg (mii_info); } else genmii_setup_forced (mii_info); return 0;}static int marvell_config_aneg (struct uec_mii_info *mii_info){ /* The Marvell PHY has an errata which requires * that certain registers get written in order * to restart autonegotiation */ phy_write (mii_info, PHY_BMCR, PHY_BMCR_RESET); phy_write (mii_info, 0x1d, 0x1f); phy_write (mii_info, 0x1e, 0x200c); phy_write (mii_info, 0x1d, 0x5); phy_write (mii_info, 0x1e, 0); phy_write (mii_info, 0x1e, 0x100); gbit_config_aneg (mii_info); return 0;}static int genmii_config_aneg (struct uec_mii_info *mii_info){ if (mii_info->autoneg) { config_genmii_advert (mii_info); genmii_restart_aneg (mii_info); } else genmii_setup_forced (mii_info); return 0;}static int genmii_update_link (struct uec_mii_info *mii_info){ u16 status; /* Do a fake read */ phy_read (mii_info, PHY_BMSR); /* Read link and autonegotiation status */ status = phy_read (mii_info, PHY_BMSR); if ((status & PHY_BMSR_LS) == 0) mii_info->link = 0; else mii_info->link = 1; /* If we are autonegotiating, and not done, * return an error */ if (mii_info->autoneg && !(status & PHY_BMSR_AUTN_COMP)) return -EAGAIN; return 0;}static int genmii_read_status (struct uec_mii_info *mii_info){ u16 status; int err; /* Update the link, but return if there * was an error */ err = genmii_update_link (mii_info); if (err) return err; if (mii_info->autoneg) { status = phy_read (mii_info, PHY_ANLPAR);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -