📄 fcc_enet.c
字号:
static phy_info_t phy_info_lxt970 = { 0x07810000, "LXT970", (const phy_cmd_t []) { /* config */#if 0// { mk_mii_write(MII_ADVERTISE, 0x0021), NULL }, /* Set default operation of 100-TX....for some reason * some of these bits are set on power up, which is wrong. */ { mk_mii_write(MII_LXT970_CONFIG, 0), NULL },#endif { mk_mii_read(MII_BMCR), mii_parse_cr }, { mk_mii_read(MII_ADVERTISE), mii_parse_anar }, { mk_mii_end, } }, (const phy_cmd_t []) { /* startup - enable interrupts */ { mk_mii_write(MII_LXT970_IER, 0x0002), NULL }, { mk_mii_write(MII_BMCR, 0x1200), NULL }, /* autonegotiate */ { mk_mii_end, } }, (const phy_cmd_t []) { /* ack_int */ /* read SR and ISR to acknowledge */ { mk_mii_read(MII_BMSR), mii_parse_sr }, { mk_mii_read(MII_LXT970_ISR), NULL }, /* find out the current status */ { mk_mii_read(MII_LXT970_CSR), mii_parse_lxt970_csr }, { mk_mii_end, } }, (const phy_cmd_t []) { /* shutdown - disable interrupts */ { mk_mii_write(MII_LXT970_IER, 0x0000), NULL }, { mk_mii_end, } },};#endif /* CONFIG_FEC_LXT970 *//* ------------------------------------------------------------------------- *//* The Level one LXT971 is used on some of my custom boards */#ifdef CONFIG_FCC_LXT971/* register definitions for the 971 */#define MII_LXT971_PCR 16 /* Port Control Register */#define MII_LXT971_SR2 17 /* Status Register 2 */#define MII_LXT971_IER 18 /* Interrupt Enable Register */#define MII_LXT971_ISR 19 /* Interrupt Status Register */#define MII_LXT971_LCR 20 /* LED Control Register */#define MII_LXT971_TCR 30 /* Transmit Control Register *//* * I had some nice ideas of running the MDIO faster... * The 971 should support 8MHz and I tried it, but things acted really * weird, so 2.5 MHz ought to be enough for anyone... */static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev){ volatile struct fcc_enet_private *fep = dev->priv; uint s = fep->phy_status; s &= ~(PHY_STAT_SPMASK); if (mii_reg & 0x4000) { if (mii_reg & 0x0200) s |= PHY_STAT_100FDX; else s |= PHY_STAT_100HDX; } else { if (mii_reg & 0x0200) s |= PHY_STAT_10FDX; else s |= PHY_STAT_10HDX; } if (mii_reg & 0x0008) s |= PHY_STAT_FAULT; fep->phy_status = s;}static phy_info_t phy_info_lxt971 = { 0x0001378e, "LXT971", (const phy_cmd_t []) { /* config */ /* configure link capabilities to advertise */ { mk_mii_write(MII_ADVERTISE, MII_ADVERTISE_DEFAULT), mii_parse_anar }, /* enable auto-negotiation */ { mk_mii_write(MII_BMCR, BMCR_ANENABLE), mii_parse_cr }, { mk_mii_end, } }, (const phy_cmd_t []) { /* startup - enable interrupts */ { mk_mii_write(MII_LXT971_IER, 0x00f2), NULL }, /* restart auto-negotiation */ { mk_mii_write(MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART), NULL }, { mk_mii_end, } }, (const phy_cmd_t []) { /* ack_int */ /* find out the current status */ { mk_mii_read(MII_BMSR), NULL }, { mk_mii_read(MII_BMSR), mii_parse_sr }, { mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 }, /* we only need to read ISR to acknowledge */ { mk_mii_read(MII_LXT971_ISR), NULL }, { mk_mii_end, } }, (const phy_cmd_t []) { /* shutdown - disable interrupts */ { mk_mii_write(MII_LXT971_IER, 0x0000), NULL }, { mk_mii_end, } },};#endif /* CONFIG_FCC_LXT971 *//* ------------------------------------------------------------------------- *//* The Quality Semiconductor QS6612 is used on the RPX CLLF */#ifdef CONFIG_FCC_QS6612/* register definitions */#define MII_QS6612_MCR 17 /* Mode Control Register */#define MII_QS6612_FTR 27 /* Factory Test Register */#define MII_QS6612_MCO 28 /* Misc. Control Register */#define MII_QS6612_ISR 29 /* Interrupt Source Register */#define MII_QS6612_IMR 30 /* Interrupt Mask Register */#define MII_QS6612_PCR 31 /* 100BaseTx PHY Control Reg. */static void mii_parse_qs6612_pcr(uint mii_reg, struct net_device *dev){ volatile struct fcc_enet_private *fep = dev->priv; uint s = fep->phy_status; s &= ~(PHY_STAT_SPMASK); switch((mii_reg >> 2) & 7) { case 1: s |= PHY_STAT_10HDX; break; case 2: s |= PHY_STAT_100HDX; break; case 5: s |= PHY_STAT_10FDX; break; case 6: s |= PHY_STAT_100FDX; break; } fep->phy_status = s;}static phy_info_t phy_info_qs6612 = { 0x00181440, "QS6612", (const phy_cmd_t []) { /* config */// { mk_mii_write(MII_ADVERTISE, 0x061), NULL }, /* 10 Mbps */ /* The PHY powers up isolated on the RPX, * so send a command to allow operation. */ { mk_mii_write(MII_QS6612_PCR, 0x0dc0), NULL }, /* parse cr and anar to get some info */ { mk_mii_read(MII_BMCR), mii_parse_cr }, { mk_mii_read(MII_ADVERTISE), mii_parse_anar }, { mk_mii_end, } }, (const phy_cmd_t []) { /* startup - enable interrupts */ { mk_mii_write(MII_QS6612_IMR, 0x003a), NULL }, { mk_mii_write(MII_BMCR, 0x1200), NULL }, /* autonegotiate */ { mk_mii_end, } }, (const phy_cmd_t []) { /* ack_int */ /* we need to read ISR, SR and ANER to acknowledge */ { mk_mii_read(MII_QS6612_ISR), NULL }, { mk_mii_read(MII_BMSR), mii_parse_sr }, { mk_mii_read(MII_EXPANSION), NULL }, /* read pcr to get info */ { mk_mii_read(MII_QS6612_PCR), mii_parse_qs6612_pcr }, { mk_mii_end, } }, (const phy_cmd_t []) { /* shutdown - disable interrupts */ { mk_mii_write(MII_QS6612_IMR, 0x0000), NULL }, { mk_mii_end, } },};#endif /* CONFIG_FEC_QS6612 *//* ------------------------------------------------------------------------- *//* The Davicom DM9131 is used on the HYMOD board */#ifdef CONFIG_FCC_DM9131/* register definitions */#define MII_DM9131_ACR 16 /* Aux. Config Register */#define MII_DM9131_ACSR 17 /* Aux. Config/Status Register */#define MII_DM9131_10TCSR 18 /* 10BaseT Config/Status Reg. */#define MII_DM9131_INTR 21 /* Interrupt Register */#define MII_DM9131_RECR 22 /* Receive Error Counter Reg. */#define MII_DM9131_DISCR 23 /* Disconnect Counter Register */static void mii_parse_dm9131_acsr(uint mii_reg, struct net_device *dev){ volatile struct fcc_enet_private *fep = dev->priv; uint s = fep->phy_status; s &= ~(PHY_STAT_SPMASK); switch ((mii_reg >> 12) & 0xf) { case 1: s |= PHY_STAT_10HDX; break; case 2: s |= PHY_STAT_10FDX; break; case 4: s |= PHY_STAT_100HDX; break; case 8: s |= PHY_STAT_100FDX; break; } fep->phy_status = s;}static phy_info_t phy_info_dm9131 = { 0x00181b80, "DM9131", (const phy_cmd_t []) { /* config */ /* parse cr and anar to get some info */ { mk_mii_read(MII_BMCR), mii_parse_cr }, { mk_mii_read(MII_ADVERTISE), mii_parse_anar }, { mk_mii_end, } }, (const phy_cmd_t []) { /* startup - enable interrupts */ { mk_mii_write(MII_DM9131_INTR, 0x0002), NULL }, { mk_mii_write(MII_BMCR, 0x1200), NULL }, /* autonegotiate */ { mk_mii_end, } }, (const phy_cmd_t []) { /* ack_int */ /* we need to read INTR, SR and ANER to acknowledge */ { mk_mii_read(MII_DM9131_INTR), NULL }, { mk_mii_read(MII_BMSR), mii_parse_sr }, { mk_mii_read(MII_EXPANSION), NULL }, /* read acsr to get info */ { mk_mii_read(MII_DM9131_ACSR), mii_parse_dm9131_acsr }, { mk_mii_end, } }, (const phy_cmd_t []) { /* shutdown - disable interrupts */ { mk_mii_write(MII_DM9131_INTR, 0x0f00), NULL }, { mk_mii_end, } },};#endif /* CONFIG_FEC_DM9131 */#ifdef CONFIG_FCC_DM9161/* ------------------------------------------------------------------------- *//* DM9161 Control register values */#define MIIM_DM9161_CR_STOP 0x0400#define MIIM_DM9161_CR_RSTAN 0x1200#define MIIM_DM9161_SCR 0x10#define MIIM_DM9161_SCR_INIT 0x0610/* DM9161 Specified Configuration and Status Register */#define MIIM_DM9161_SCSR 0x11#define MIIM_DM9161_SCSR_100F 0x8000#define MIIM_DM9161_SCSR_100H 0x4000#define MIIM_DM9161_SCSR_10F 0x2000#define MIIM_DM9161_SCSR_10H 0x1000/* DM9161 10BT register */#define MIIM_DM9161_10BTCSR 0x12#define MIIM_DM9161_10BTCSR_INIT 0x7800/* DM9161 Interrupt Register */#define MIIM_DM9161_INTR 0x15#define MIIM_DM9161_INTR_PEND 0x8000#define MIIM_DM9161_INTR_DPLX_MASK 0x0800#define MIIM_DM9161_INTR_SPD_MASK 0x0400#define MIIM_DM9161_INTR_LINK_MASK 0x0200#define MIIM_DM9161_INTR_MASK 0x0100#define MIIM_DM9161_INTR_DPLX_CHANGE 0x0010#define MIIM_DM9161_INTR_SPD_CHANGE 0x0008#define MIIM_DM9161_INTR_LINK_CHANGE 0x0004#define MIIM_DM9161_INTR_INIT 0x0000#define MIIM_DM9161_INTR_STOP \(MIIM_DM9161_INTR_DPLX_MASK | MIIM_DM9161_INTR_SPD_MASK \ | MIIM_DM9161_INTR_LINK_MASK | MIIM_DM9161_INTR_MASK)static void mii_parse_dm9161_sr(uint mii_reg, struct net_device * dev){ volatile struct fcc_enet_private *fep = dev->priv; uint regstat, timeout=0xffff; while(!(mii_reg & 0x0020) && timeout--) { regstat=mk_mii_read(MII_BMSR); regstat |= fep->phy_addr <<23; mii_reg = mii_send_receive(fep->fip,regstat); } mii_parse_sr(mii_reg, dev);}static void mii_parse_dm9161_scsr(uint mii_reg, struct net_device * dev){ volatile struct fcc_enet_private *fep = dev->priv; uint s = fep->phy_status; s &= ~(PHY_STAT_SPMASK); switch((mii_reg >>12) & 0xf) { case 1: { s |= PHY_STAT_10HDX; printk("10BaseT Half Duplex\n"); break; } case 2: { s |= PHY_STAT_10FDX; printk("10BaseT Full Duplex\n"); break; } case 4: { s |= PHY_STAT_100HDX; printk("100BaseT Half Duplex\n"); break; } case 8: { s |= PHY_STAT_100FDX; printk("100BaseT Full Duplex\n"); break; } } fep->phy_status = s;}static void mii_dm9161_wait(uint mii_reg, struct net_device *dev){ int timeout = HZ; /* Davicom takes a bit to come up after a reset, * so wait here for a bit */ schedule_timeout_uninterruptible(timeout);}static phy_info_t phy_info_dm9161 = { 0x00181b88, "Davicom DM9161E", (const phy_cmd_t[]) { /* config */ { mk_mii_write(MII_BMCR, MIIM_DM9161_CR_STOP), NULL}, /* Do not bypass the scrambler/descrambler */ { mk_mii_write(MIIM_DM9161_SCR, MIIM_DM9161_SCR_INIT), NULL}, /* Configure 10BTCSR register */ { mk_mii_write(MIIM_DM9161_10BTCSR, MIIM_DM9161_10BTCSR_INIT),NULL}, /* Configure some basic stuff */ { mk_mii_write(MII_BMCR, 0x1000), NULL}, { mk_mii_read(MII_BMCR), mii_parse_cr }, { mk_mii_read(MII_ADVERTISE), mii_parse_anar }, { mk_mii_end,} }, (const phy_cmd_t[]) { /* startup */ /* Restart Auto Negotiation */ { mk_mii_write(MII_BMCR, MIIM_DM9161_CR_RSTAN), NULL}, /* Status is read once to clear old link state */ { mk_mii_read(MII_BMSR), mii_dm9161_wait}, /* Auto-negotiate */ { mk_mii_read(MII_BMSR), mii_parse_dm9161_sr}, /* Read the status */ { mk_mii_read(MIIM_DM9161_SCSR), mii_parse_dm9161_scsr}, /* Clear any pending interrupts */ { mk_mii_read(MIIM_DM9161_INTR), NULL}, /* Enable Interrupts */ { mk_mii_write(MIIM_DM9161_INTR, MIIM_DM9161_INTR_INIT), NULL}, { mk_mii_end,} }, (const phy_cmd_t[]) { /* ack_int */ { mk_mii_read(MIIM_DM9161_INTR), NULL},#if 0 { mk_mii_read(MII_BMSR), NULL}, { mk_mii_read(MII_BMSR), mii_parse_dm9161_sr}, { mk_mii_read(MIIM_DM9161_SCSR), mii_parse_dm9161_scsr},#endif { mk_mii_end,} }, (const phy_cmd_t[]) { /* shutdown */ { mk_mii_read(MIIM_DM9161_INTR),NULL}, { mk_mii_write(MIIM_DM9161_INTR, MIIM_DM9161_INTR_STOP), NULL}, { mk_mii_end,} },};#endif /* CONFIG_FCC_DM9161 */static phy_info_t *phy_info[] = {#ifdef CONFIG_FCC_LXT970 &phy_info_lxt970,#endif /* CONFIG_FEC_LXT970 */#ifdef CONFIG_FCC_LXT971 &phy_info_lxt971,#endif /* CONFIG_FEC_LXT971 */#ifdef CONFIG_FCC_QS6612 &phy_info_qs6612,#endif /* CONFIG_FEC_QS6612 */#ifdef CONFIG_FCC_DM9131 &phy_info_dm9131,#endif /* CONFIG_FEC_DM9131 */#ifdef CONFIG_FCC_DM9161 &phy_info_dm9161,#endif /* CONFIG_FCC_DM9161 */#ifdef CONFIG_FCC_GENERIC_PHY /* Generic PHY support. This must be the last PHY in the table. * It will be used to support any PHY that doesn't match a previous * entry in the table. */ &phy_info_generic,#endif /* CONFIG_FCC_GENERIC_PHY */ NULL};static void mii_display_status(void *data){ struct net_device *dev = data; volatile struct fcc_enet_private *fep = dev->priv; uint s = fep->phy_status; if (!fep->link && !fep->old_link) { /* Link is still down - don't print anything */ return; } printk("%s: status: ", dev->name); if (!fep->link) { printk("link down"); } else { printk("link up"); switch(s & PHY_STAT_SPMASK) { case PHY_STAT_100FDX: printk(", 100 Mbps Full Duplex"); break; case PHY_STAT_100HDX: printk(", 100 Mbps Half Duplex"); break; case PHY_STAT_10FDX: printk(", 10 Mbps Full Duplex"); break; case PHY_STAT_10HDX: printk(", 10 Mbps Half Duplex"); break; default: printk(", Unknown speed/duplex"); } if (s & PHY_STAT_ANC) printk(", auto-negotiation complete"); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -