📄 fec.c
字号:
if (mii_reg & 0x0800) { if (mii_reg & 0x1000) *s |= PHY_STAT_100FDX; else *s |= PHY_STAT_100HDX; } else { if (mii_reg & 0x1000) *s |= PHY_STAT_10FDX; else *s |= PHY_STAT_10HDX; }}static phy_info_t phy_info_lxt970 = { 0x07810000, "LXT970", (const phy_cmd_t []) { /* config */#if 0// { mk_mii_write(MII_REG_ANAR, 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_REG_CR), mii_parse_cr }, { mk_mii_read(MII_REG_ANAR), 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_REG_CR, 0x1200), NULL }, /* autonegotiate */ { mk_mii_end, } }, (const phy_cmd_t []) { /* ack_int */ /* read SR and ISR to acknowledge */ { mk_mii_read(MII_REG_SR), 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_FEC_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){ struct fec_enet_private *fep = dev->priv; volatile 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;}static phy_info_t phy_info_lxt971 = { 0x0001378e, "LXT971", (const phy_cmd_t []) { /* config */// { mk_mii_write(MII_REG_ANAR, 0x021), NULL }, /* 10 Mbps, HD */ { mk_mii_read(MII_REG_CR), mii_parse_cr }, { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, { mk_mii_end, } }, (const phy_cmd_t []) { /* startup - enable interrupts */ { mk_mii_write(MII_LXT971_IER, 0x00f2), NULL }, { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ /* Somehow does the 971 tell me that the link is down * the first read after power-up. * read here to get a valid value in ack_int */ { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_end, } }, (const phy_cmd_t []) { /* ack_int */ /* find out the current status */ { mk_mii_read(MII_REG_SR), 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_FEC_LXT970 *//* ------------------------------------------------------------------------- *//* The Quality Semiconductor QS6612 is used on the RPX CLLF */#ifdef CONFIG_FEC_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){ struct fec_enet_private *fep = dev->priv; volatile 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; }}static phy_info_t phy_info_qs6612 = { 0x00181440, "QS6612", (const phy_cmd_t []) { /* config */// { mk_mii_write(MII_REG_ANAR, 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_REG_CR), mii_parse_cr }, { mk_mii_read(MII_REG_ANAR), 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_REG_CR, 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_REG_SR), mii_parse_sr }, { mk_mii_read(MII_REG_ANER), 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 */static phy_info_t *phy_info[] = {#ifdef CONFIG_FEC_LXT970 &phy_info_lxt970,#endif /* CONFIG_FEC_LXT970 */#ifdef CONFIG_FEC_LXT971 &phy_info_lxt971,#endif /* CONFIG_FEC_LXT971 */#ifdef CONFIG_FEC_QS6612 &phy_info_qs6612,#endif /* CONFIG_FEC_LXT971 */ NULL};static void mii_display_status(struct net_device *dev){ struct fec_enet_private *fep = dev->priv; volatile 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"); } if (*s & PHY_STAT_FAULT) printk(", remote fault"); printk(".\n");}static void mii_display_config(struct net_device *dev){ struct fec_enet_private *fep = dev->priv; volatile uint *s = &(fep->phy_status); printk("%s: config: auto-negotiation ", dev->name); if (*s & PHY_CONF_ANE) printk("on"); else printk("off"); if (*s & PHY_CONF_100FDX) printk(", 100FDX"); if (*s & PHY_CONF_100HDX) printk(", 100HDX"); if (*s & PHY_CONF_10FDX) printk(", 10FDX"); if (*s & PHY_CONF_10HDX) printk(", 10HDX"); if (!(*s & PHY_CONF_SPMASK)) printk(", No speed/duplex selected?"); if (*s & PHY_CONF_LOOP) printk(", loopback enabled"); printk(".\n"); fep->sequence_done = 1;}static void mii_relink(struct net_device *dev){ struct fec_enet_private *fep = dev->priv; int duplex; fep->link = (fep->phy_status & PHY_STAT_LINK) ? 1 : 0; mii_display_status(dev); fep->old_link = fep->link; if (fep->link) { duplex = 0; if (fep->phy_status & (PHY_STAT_100FDX | PHY_STAT_10FDX)) duplex = 1; fec_restart(dev, duplex); } else fec_stop(dev);#if 0 enable_irq(fep->mii_irq);#endif}static void mii_queue_relink(uint mii_reg, struct net_device *dev){ struct fec_enet_private *fep = dev->priv; fep->phy_task.routine = (void *)mii_relink; fep->phy_task.data = dev; schedule_task(&fep->phy_task);}static void mii_queue_config(uint mii_reg, struct net_device *dev){ struct fec_enet_private *fep = dev->priv; fep->phy_task.routine = (void *)mii_display_config; fep->phy_task.data = dev; schedule_task(&fep->phy_task);}phy_cmd_t phy_cmd_relink[] = { { mk_mii_read(MII_REG_CR), mii_queue_relink }, { mk_mii_end, } };phy_cmd_t phy_cmd_config[] = { { mk_mii_read(MII_REG_CR), mii_queue_config }, { mk_mii_end, } };/* Read remainder of PHY ID.*/static voidmii_discover_phy3(uint mii_reg, struct net_device *dev){ struct fec_enet_private *fep; int i; fep = dev->priv; fep->phy_id |= (mii_reg & 0xffff); for(i = 0; phy_info[i]; i++) if(phy_info[i]->id == (fep->phy_id >> 4)) break; if(!phy_info[i]) panic("%s: PHY id 0x%08x is not supported!\n", dev->name, fep->phy_id); fep->phy = phy_info[i]; fep->phy_id_done = 1; printk("%s: Phy @ 0x%x, type %s (0x%08x)\n", dev->name, fep->phy_addr, fep->phy->name, fep->phy_id);}/* Scan all of the MII PHY addresses looking for someone to respond * with a valid ID. This usually happens quickly. */static voidmii_discover_phy(uint mii_reg, struct net_device *dev){ struct fec_enet_private *fep; uint phytype; fep = dev->priv; if ((phytype = (mii_reg & 0xffff)) != 0xffff) { /* Got first part of ID, now get remainder. */ fep->phy_id = phytype << 16; mii_queue(dev, mk_mii_read(MII_REG_PHYIR2), mii_discover_phy3); } else { fep->phy_addr++; if (fep->phy_addr < 32) { mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy); } else { printk("fec: No PHY device found.\n"); } }}#endif /* CONFIG_USE_MDIO *//* This interrupt occurs when the PHY detects a link change.*/static void#ifdef CONFIG_RPXCLASSICmii_link_interrupt(void *dev_id)#elsemii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs)#endif{#ifdef CONFIG_USE_MDIO struct net_device *dev = dev_id; struct fec_enet_private *fep = dev->priv; volatile immap_t *immap = (immap_t *)IMAP_ADDR; volatile fec_t *fecp = &(immap->im_cpm.cp_fec); unsigned int ecntrl = fecp->fec_ecntrl; /* We need the FEC enabled to access the MII */ if ((ecntrl & FEC_ECNTRL_ETHER_EN) == 0) { fecp->fec_ecntrl |= FEC_ECNTRL_ETHER_EN; }#endif /* CONFIG_USE_MDIO */#if 0 disable_irq(fep->mii_irq); /* disable now, enable later */#endif#ifdef CONFIG_USE_MDIO mii_do_cmd(dev, fep->phy->ack_int); mii_do_cmd(dev, phy_cmd_relink); /* restart and display status */ if ((ecntrl & FEC_ECNTRL_ETHER_EN) == 0) { fecp->fec_ecntrl = ecntrl; /* restore old settings */ }#elseprintk("%s[%d] %s: unexpected Link interrupt\n", __FILE__,__LINE__,__FUNCTION__);#endif /* CONFIG_USE_MDIO */}static intfec_enet_open(struct net_device *dev){ struct fec_enet_private *fep = dev->priv; /* I should reset the ring buffers here, but I don't yet know * a simple way to do that. */#ifdef CONFIG_USE_MDIO fep->sequence_done = 0; fep->link = 0; if (fep->phy) { mii_do_cmd(dev, fep->phy->ack_int); mii_do_cmd(dev, fep->phy->config); mii_do_cmd(dev, phy_cmd_config); /* display configuration */ while(!fep->sequence_done) schedule(); mii_do_cmd(dev, fep->phy->startup); netif_start_queue(dev); return 0; /* Success */ } return -ENODEV; /* No PHY we understand */#else fep->link = 1; netif_start_queue(dev); return 0; /* Success */#endif /* CONFIG_USE_MDIO */}static intfec_enet_close(struct net_device *dev){ /* Don't know what to do yet. */ netif_stop_queue(dev); fec_stop(dev); return 0;}static struct net_device_stats *fec_enet_get_stats(struct net_device *dev){ struct fec_enet_private *fep = (struct fec_enet_private *)dev->priv; return &fep->stats;}/* Set or clear the multicast filter for this adaptor.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -