/* initialize the interface */ static rt_err_t rt_dm9161_init(rt_device_t dev) { unsigned int phyid1, phyid2; int detected = -1; unsigned long phy_id; unsigned short phy_address = 0; while ((detected != 0) && (phy_address < 32)) { /* Read the PHY ID registers */ enable_mdi(); read_phy(phy_address, MII_PHYSID1, &phyid1); read_phy(phy_address, MII_PHYSID2, &phyid2); disable_mdi(); phy_id = (phyid1 << 16) | (phyid2 & 0xfff0); switch (phy_id) { case MII_DM9161_ID: /* Davicom 9161: PHY_ID1 = 0x181, PHY_ID2 = B881 */ case MII_DM9161A_ID: /* Davicom 9161A: PHY_ID1 = 0x181, PHY_ID2 = B8A0 */ case MII_RTL8201_ID: /* Realtek RTL8201: PHY_ID1 = 0, PHY_ID2 = 0x8201 */ case MII_BCM5221_ID: /* Broadcom BCM5221: PHY_ID1 = 0x40, PHY_ID2 = 0x61e0 */ case MII_DP83847_ID: /* National Semiconductor DP83847: */ case MII_AC101L_ID: /* Altima AC101L: PHY_ID1 = 0x22, PHY_ID2 = 0x5520 */ case MII_KS8721_ID: /* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */ { enable_mdi(); #warning SHOULD SET MAC ADDR //get_mac_address(dev); /* Get ethernet address and store it in dev->dev_addr */ update_mac_address(); /* Program ethernet address into MAC */ //用哈希寄存器比较当前群播地址,全双工,添加CRC校验,短数据帧进行填充 sep_emac_write(MAC_CTRL, 0xa413); #warning SHOULD DETERMIN LINK SPEED update_link_speed(phy_address); dm9161_device.phy_addr = phy_address; disable_mdi(); break; } } phy_address++; } rt_dm9161_open(dev,0); return RT_EOK; }
/* * Initialize and enable the PHY interrupt for link-state changes */ static void enable_phyirq(struct net_device *dev) { struct at91_private *lp = netdev_priv(dev); unsigned int dsintr, irq_number; int status; irq_number = lp->board_data.phy_irq_pin; if (!irq_number) { /* * PHY doesn't have an IRQ pin (RTL8201, DP83847, AC101L), * or board does not have it connected. */ mod_timer(&lp->check_timer, jiffies + LINK_POLL_INTERVAL); return; } status = request_irq(irq_number, at91ether_phy_interrupt, 0, dev->name, dev); if (status) { printk(KERN_ERR "at91_ether: PHY IRQ %d request failed - status %d!\n", irq_number, status); return; } spin_lock_irq(&lp->lock); enable_mdi(); if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) { /* for Davicom PHY */ read_phy(lp->phy_address, MII_DSINTR_REG, &dsintr); dsintr = dsintr & ~0xf00; /* clear bits 8..11 */ write_phy(lp->phy_address, MII_DSINTR_REG, dsintr); } else if (lp->phy_type == MII_LXT971A_ID) { /* for Intel PHY */ read_phy(lp->phy_address, MII_ISINTE_REG, &dsintr); dsintr = dsintr | 0xf2; /* set bits 1, 4..7 */ write_phy(lp->phy_address, MII_ISINTE_REG, dsintr); } else if (lp->phy_type == MII_BCM5221_ID) { /* for Broadcom PHY */ dsintr = (1 << 15) | ( 1 << 14); write_phy(lp->phy_address, MII_BCMINTR_REG, dsintr); } else if (lp->phy_type == MII_KS8721_ID) { /* for Micrel PHY */ dsintr = (1 << 10) | ( 1 << 8); write_phy(lp->phy_address, MII_TPISTATUS, dsintr); } else if (lp->phy_type == MII_T78Q21x3_ID) { /* for Teridian PHY */ read_phy(lp->phy_address, MII_T78Q21INT_REG, &dsintr); dsintr = dsintr | 0x500; /* set bits 8, 10 */ write_phy(lp->phy_address, MII_T78Q21INT_REG, dsintr); } else if (lp->phy_type == MII_DP83848_ID) { /* National Semiconductor DP83848 PHY */ read_phy(lp->phy_address, MII_DPMISR_REG, &dsintr); dsintr = dsintr | 0x3c; /* set bits 2..5 */ write_phy(lp->phy_address, MII_DPMISR_REG, dsintr); read_phy(lp->phy_address, MII_DPMICR_REG, &dsintr); dsintr = dsintr | 0x3; /* set bits 0,1 */ write_phy(lp->phy_address, MII_DPMICR_REG, dsintr); } disable_mdi(); spin_unlock_irq(&lp->lock); }
/* * Disable the PHY interrupt */ static void disable_phyirq(struct net_device *dev) { struct at91_private *lp = netdev_priv(dev); unsigned int dsintr; unsigned int irq_number; irq_number = lp->board_data.phy_irq_pin; if (!irq_number) { del_timer_sync(&lp->check_timer); return; } spin_lock_irq(&lp->lock); enable_mdi(); if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) { /* for Davicom PHY */ read_phy(lp->phy_address, MII_DSINTR_REG, &dsintr); dsintr = dsintr | 0xf00; /* set bits 8..11 */ write_phy(lp->phy_address, MII_DSINTR_REG, dsintr); } else if (lp->phy_type == MII_LXT971A_ID) { /* for Intel PHY */ read_phy(lp->phy_address, MII_ISINTE_REG, &dsintr); dsintr = dsintr & ~0xf2; /* clear bits 1, 4..7 */ write_phy(lp->phy_address, MII_ISINTE_REG, dsintr); } else if (lp->phy_type == MII_BCM5221_ID) { /* for Broadcom PHY */ read_phy(lp->phy_address, MII_BCMINTR_REG, &dsintr); dsintr = ~(1 << 14); write_phy(lp->phy_address, MII_BCMINTR_REG, dsintr); } else if ((lp->phy_type == MII_KS8721_ID) || (lp->phy_type == MII_KSZ8041_ID)) { /* for Micrel PHY */ read_phy(lp->phy_address, MII_TPISTATUS, &dsintr); dsintr = ~((1 << 10) | (1 << 8)); write_phy(lp->phy_address, MII_TPISTATUS, dsintr); } else if (lp->phy_type == MII_T78Q21x3_ID) { /* for Teridian PHY */ read_phy(lp->phy_address, MII_T78Q21INT_REG, &dsintr); dsintr = dsintr & ~0x500; /* clear bits 8, 10 */ write_phy(lp->phy_address, MII_T78Q21INT_REG, dsintr); } else if (lp->phy_type == MII_DP83848_ID) { /* National Semiconductor DP83848 PHY */ read_phy(lp->phy_address, MII_DPMICR_REG, &dsintr); dsintr = dsintr & ~0x3; /* clear bits 0, 1 */ write_phy(lp->phy_address, MII_DPMICR_REG, dsintr); read_phy(lp->phy_address, MII_DPMISR_REG, &dsintr); dsintr = dsintr & ~0x3c; /* clear bits 2..5 */ write_phy(lp->phy_address, MII_DPMISR_REG, dsintr); } else if (lp->phy_type == MII_STE100P_ID) { /* for STE100P PHY */ read_phy(lp->phy_address, MII_STE100P_XIE_REG, &dsintr); dsintr = dsintr & ~0x7f; write_phy(lp->phy_address, MII_STE100P_XIE_REG, dsintr); } disable_mdi(); spin_unlock_irq(&lp->lock); free_irq(irq_number, dev); /* Free interrupt handler */ }
static void enable_phyirq(struct net_device *dev) { struct at91_private *lp = netdev_priv(dev); unsigned int dsintr, irq_number; int status; irq_number = lp->board_data.phy_irq_pin; if (!irq_number) { mod_timer(&lp->check_timer, jiffies + LINK_POLL_INTERVAL); return; } status = request_irq(irq_number, at91ether_phy_interrupt, 0, dev->name, dev); if (status) { printk(KERN_ERR "at91_ether: PHY IRQ %d request failed - status %d!\n", irq_number, status); return; } spin_lock_irq(&lp->lock); enable_mdi(); if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) { read_phy(lp->phy_address, MII_DSINTR_REG, &dsintr); dsintr = dsintr & ~0xf00; write_phy(lp->phy_address, MII_DSINTR_REG, dsintr); } else if (lp->phy_type == MII_LXT971A_ID) { read_phy(lp->phy_address, MII_ISINTE_REG, &dsintr); dsintr = dsintr | 0xf2; write_phy(lp->phy_address, MII_ISINTE_REG, dsintr); } else if (lp->phy_type == MII_BCM5221_ID) { dsintr = (1 << 15) | ( 1 << 14); write_phy(lp->phy_address, MII_BCMINTR_REG, dsintr); } else if (lp->phy_type == MII_KS8721_ID) { dsintr = (1 << 10) | ( 1 << 8); write_phy(lp->phy_address, MII_TPISTATUS, dsintr); } else if (lp->phy_type == MII_T78Q21x3_ID) { read_phy(lp->phy_address, MII_T78Q21INT_REG, &dsintr); dsintr = dsintr | 0x500; write_phy(lp->phy_address, MII_T78Q21INT_REG, dsintr); } else if (lp->phy_type == MII_DP83848_ID) { read_phy(lp->phy_address, MII_DPMISR_REG, &dsintr); dsintr = dsintr | 0x3c; write_phy(lp->phy_address, MII_DPMISR_REG, dsintr); read_phy(lp->phy_address, MII_DPMICR_REG, &dsintr); dsintr = dsintr | 0x3; write_phy(lp->phy_address, MII_DPMICR_REG, dsintr); } disable_mdi(); spin_unlock_irq(&lp->lock); }
/* * Handle interrupts from the PHY */ static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct at91_private *lp = netdev_priv(dev); unsigned int phy; /* * This hander is triggered on both edges, but the PHY chips expect * level-triggering. We therefore have to check if the PHY actually has * an IRQ pending. */ enable_mdi(); if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) { read_phy(lp->phy_address, MII_DSINTR_REG, &phy); /* ack interrupt in Davicom PHY */ if (!(phy & (1 << 0))) goto done; } else if (lp->phy_type == MII_LXT971A_ID) { read_phy(lp->phy_address, MII_ISINTS_REG, &phy); /* ack interrupt in Intel PHY */ if (!(phy & (1 << 2))) goto done; } else if (lp->phy_type == MII_BCM5221_ID) { read_phy(lp->phy_address, MII_BCMINTR_REG, &phy); /* ack interrupt in Broadcom PHY */ if (!(phy & (1 << 0))) goto done; } else if ((lp->phy_type == MII_KS8721_ID) || (lp->phy_type == MII_KSZ8041_ID)) { read_phy(lp->phy_address, MII_TPISTATUS, &phy); /* ack interrupt in Micrel PHY */ if (!(phy & ((1 << 2) | 1))) goto done; } else if (lp->phy_type == MII_T78Q21x3_ID) { /* ack interrupt in Teridian PHY */ read_phy(lp->phy_address, MII_T78Q21INT_REG, &phy); if (!(phy & ((1 << 2) | 1))) goto done; } else if (lp->phy_type == MII_DP83848_ID) { read_phy(lp->phy_address, MII_DPPHYSTS_REG, &phy); /* ack interrupt in DP83848 PHY */ if (!(phy & (1 << 7))) goto done; } else if (lp->phy_type == MII_STE100P_ID) { /* ack interrupt in STE100P PHY */ read_phy(lp->phy_address, MII_STE100P_XCSIIS_REG, &phy); if (!(phy & 0x007F)) goto done; } update_linkspeed(dev, 0); done: disable_mdi(); return IRQ_HANDLED; }
static void at91ether_check_link(unsigned long dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct at91_private *lp = netdev_priv(dev); enable_mdi(); update_linkspeed(dev, 1); disable_mdi(); mod_timer(&lp->check_timer, jiffies + LINK_POLL_INTERVAL); }
static void disable_phyirq(struct net_device *dev) { struct at91_private *lp = netdev_priv(dev); unsigned int dsintr; unsigned int irq_number; irq_number = lp->board_data.phy_irq_pin; if (!irq_number) { del_timer_sync(&lp->check_timer); return; } spin_lock_irq(&lp->lock); enable_mdi(); if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) { read_phy(lp->phy_address, MII_DSINTR_REG, &dsintr); dsintr = dsintr | 0xf00; write_phy(lp->phy_address, MII_DSINTR_REG, dsintr); } else if (lp->phy_type == MII_LXT971A_ID) { read_phy(lp->phy_address, MII_ISINTE_REG, &dsintr); dsintr = dsintr & ~0xf2; write_phy(lp->phy_address, MII_ISINTE_REG, dsintr); } else if (lp->phy_type == MII_BCM5221_ID) { read_phy(lp->phy_address, MII_BCMINTR_REG, &dsintr); dsintr = ~(1 << 14); write_phy(lp->phy_address, MII_BCMINTR_REG, dsintr); } else if (lp->phy_type == MII_KS8721_ID) { read_phy(lp->phy_address, MII_TPISTATUS, &dsintr); dsintr = ~((1 << 10) | (1 << 8)); write_phy(lp->phy_address, MII_TPISTATUS, dsintr); } else if (lp->phy_type == MII_T78Q21x3_ID) { read_phy(lp->phy_address, MII_T78Q21INT_REG, &dsintr); dsintr = dsintr & ~0x500; write_phy(lp->phy_address, MII_T78Q21INT_REG, dsintr); } else if (lp->phy_type == MII_DP83848_ID) { read_phy(lp->phy_address, MII_DPMICR_REG, &dsintr); dsintr = dsintr & ~0x3; write_phy(lp->phy_address, MII_DPMICR_REG, dsintr); read_phy(lp->phy_address, MII_DPMISR_REG, &dsintr); dsintr = dsintr & ~0x3c; write_phy(lp->phy_address, MII_DPMISR_REG, dsintr); } disable_mdi(); spin_unlock_irq(&lp->lock); free_irq(irq_number, dev); }
static void at91ether_check_link(unsigned long dev_id) { struct net_device *dev = (struct net_device *) dev_id; enable_mdi(); update_linkspeed(dev, 1); disable_mdi(); check_timer.expires = jiffies + LINK_POLL_INTERVAL; add_timer(&check_timer); }
static int at91_ether_mii_write(struct mii_bus *dev, int addr, int reg, u16 val) { int ret; enable_mdi(); at91_emac_write(AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_W | ((addr & 0x1f) << 23) | (reg << 18) | (val & AT91_EMAC_DATA)); /* Wait until IDLE bit in Network Status register is cleared */ ret = at91_phy_wait(); disable_mdi(); return ret; }
static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct at91_private *lp = netdev_priv(dev); unsigned int phy; enable_mdi(); if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) { read_phy(lp->phy_address, MII_DSINTR_REG, &phy); if (!(phy & (1 << 0))) goto done; } else if (lp->phy_type == MII_LXT971A_ID) { read_phy(lp->phy_address, MII_ISINTS_REG, &phy); if (!(phy & (1 << 2))) goto done; } else if (lp->phy_type == MII_BCM5221_ID) { read_phy(lp->phy_address, MII_BCMINTR_REG, &phy); if (!(phy & (1 << 0))) goto done; } else if (lp->phy_type == MII_KS8721_ID) { read_phy(lp->phy_address, MII_TPISTATUS, &phy); if (!(phy & ((1 << 2) | 1))) goto done; } else if (lp->phy_type == MII_T78Q21x3_ID) { read_phy(lp->phy_address, MII_T78Q21INT_REG, &phy); if (!(phy & ((1 << 2) | 1))) goto done; } else if (lp->phy_type == MII_DP83848_ID) { read_phy(lp->phy_address, MII_DPPHYSTS_REG, &phy); if (!(phy & (1 << 7))) goto done; } update_linkspeed(dev, 0); done: disable_mdi(); return IRQ_HANDLED; }
/* * Initialize and enable the PHY interrupt for link-state changes */ static void enable_phyirq(struct net_device *dev) { struct at91_private *lp = (struct at91_private *) dev->priv; unsigned int dsintr, irq_number; int status; if (lp->phy_type == MII_RTL8201_ID) /* RTL8201 does not have an interrupt */ return; if (lp->phy_type == MII_DP83847_ID) /* DP83847 does not have an interrupt */ return; if (lp->phy_type == MII_AC101L_ID) /* AC101L interrupt not supported yet */ return; irq_number = lp->board_data.phy_irq_pin; status = request_irq(irq_number, at91ether_phy_interrupt, 0, dev->name, dev); if (status) { printk(KERN_ERR "at91_ether: PHY IRQ %d request failed - status %d!\n", irq_number, status); return; } spin_lock_irq(&lp->lock); enable_mdi(); if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) { /* for Davicom PHY */ read_phy(lp->phy_address, MII_DSINTR_REG, &dsintr); dsintr = dsintr & ~0xf00; /* clear bits 8..11 */ write_phy(lp->phy_address, MII_DSINTR_REG, dsintr); } else if (lp->phy_type == MII_LXT971A_ID) { /* for Intel PHY */ read_phy(lp->phy_address, MII_ISINTE_REG, &dsintr); dsintr = dsintr | 0xf2; /* set bits 1, 4..7 */ write_phy(lp->phy_address, MII_ISINTE_REG, dsintr); } else if (lp->phy_type == MII_BCM5221_ID) { /* for Broadcom PHY */ dsintr = (1 << 15) | ( 1 << 14); write_phy(lp->phy_address, MII_BCMINTR_REG, dsintr); } else if (lp->phy_type == MII_KS8721_ID) { /* for Micrel PHY */ dsintr = (1 << 10) | ( 1 << 8); write_phy(lp->phy_address, MII_TPISTATUS, dsintr); } disable_mdi(); spin_unlock_irq(&lp->lock); }
static void reset_phy(struct net_device *dev) { struct at91_private *lp = netdev_priv(dev); unsigned int bmcr; spin_lock_irq(&lp->lock); enable_mdi(); /* Perform PHY reset */ write_phy(lp->phy_address, MII_BMCR, BMCR_RESET); /* Wait until PHY reset is complete */ do { read_phy(lp->phy_address, MII_BMCR, &bmcr); } while (!(bmcr & BMCR_RESET)); disable_mdi(); spin_unlock_irq(&lp->lock); }
static rt_err_t rt_dm9161_close(rt_device_t dev) { rt_kprintf("SEP4020 ethernet interface close!\n\r"); /* Disable Receiver and Transmitter */ disable_mdi(); #warning disable ether; // INT_ENABLE(28); /* Disable PHY interrupt */ // disable_phyirq(dev); /* Disable MAC interrupts */ sep_emac_write(MAC_INTMASK,0); //屏蔽中断 // INT_DISABLE(28); return RT_EOK; }
/* * Disable the PHY interrupt */ static void disable_phyirq(struct net_device *dev) { struct at91_private *lp = (struct at91_private *) dev->priv; unsigned int dsintr; unsigned int irq_number; if (lp->phy_type == MII_RTL8201_ID) /* RTL8201 does not have an interrupt */ return; if (lp->phy_type == MII_DP83847_ID) /* DP83847 does not have an interrupt */ return; if (lp->phy_type == MII_AC101L_ID) /* AC101L interrupt not supported yet */ return; spin_lock_irq(&lp->lock); enable_mdi(); if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) { /* for Davicom PHY */ read_phy(lp->phy_address, MII_DSINTR_REG, &dsintr); dsintr = dsintr | 0xf00; /* set bits 8..11 */ write_phy(lp->phy_address, MII_DSINTR_REG, dsintr); } else if (lp->phy_type == MII_LXT971A_ID) { /* for Intel PHY */ read_phy(lp->phy_address, MII_ISINTE_REG, &dsintr); dsintr = dsintr & ~0xf2; /* clear bits 1, 4..7 */ write_phy(lp->phy_address, MII_ISINTE_REG, dsintr); } else if (lp->phy_type == MII_BCM5221_ID) { /* for Broadcom PHY */ read_phy(lp->phy_address, MII_BCMINTR_REG, &dsintr); dsintr = ~(1 << 14); write_phy(lp->phy_address, MII_BCMINTR_REG, dsintr); } else if (lp->phy_type == MII_KS8721_ID) { /* for Micrel PHY */ read_phy(lp->phy_address, MII_TPISTATUS, &dsintr); dsintr = ~((1 << 10) | (1 << 8)); write_phy(lp->phy_address, MII_TPISTATUS, dsintr); } disable_mdi(); spin_unlock_irq(&lp->lock); irq_number = lp->board_data.phy_irq_pin; free_irq(irq_number, dev); /* Free interrupt handler */ }
static rt_err_t rt_dm9161_open(rt_device_t dev, rt_uint16_t oflag) { unsigned int dsintr; enable_mdi(); mask_irq(28); sep_emac_write(MAC_INTMASK,0x0); //首先屏蔽中断 sepether_start(); /* Enable PHY interrupt */ *(volatile unsigned long*)GPIO_PORTA_DIR |= 0x0080 ; //1 stands for in *(volatile unsigned long*)GPIO_PORTA_SEL |= 0x0080 ; //for common use *(volatile unsigned long*)GPIO_PORTA_INCTL |= 0x0080; //中断输入方式 *(volatile unsigned long*)GPIO_PORTA_INTRCTL |= (0x3UL<<14); //中断类型为低电平解发 *(volatile unsigned long*)GPIO_PORTA_INTRCLR |= 0x0080; //清除中断 *(volatile unsigned long*)GPIO_PORTA_INTRCLR = 0x0000; //清除中断 rt_hw_interrupt_install(INTSRC_MAC, rt_dm9161_isr, RT_NULL); enable_irq(INTSRC_EXINT7); read_phy(dm9161_device.phy_addr, MII_DSINTR_REG, &dsintr); dsintr = dsintr & ~0xf00; /* clear bits 8..11 */ write_phy(dm9161_device.phy_addr, MII_DSINTR_REG, dsintr); update_link_speed(dm9161_device.phy_addr); /************************************************************************************/ /* Enable MAC interrupts */ sep_emac_write(MAC_INTMASK,0xff); //open中断 sep_emac_write(MAC_INTSRC,0xff); //clear all mac irq unmask_irq(28); disable_mdi(); rt_kprintf("SEP4020 ethernet interface open!\n\r"); return RT_EOK; }
static int at91_ether_mii_read(struct mii_bus *dev, int addr, int reg) { int value; enable_mdi(); at91_emac_write(AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_R | ((addr & 0x1f) << 23) | (reg << 18)); /* Wait until IDLE bit in Network Status register is cleared */ value = at91_phy_wait(); if (value < 0) goto out; value = at91_emac_read(AT91_EMAC_MAN) & AT91_EMAC_DATA; out: disable_mdi(); return value; }