/** * fdp110_setup_loopback -- setup or disable loopback * return 0 if success, negative value if fail */ static int fdp110_setup_loopback(ec_priv_t * ecp, bool loopback) { int bmcr; int err = 0; bool changed = false; bmcr = read_phy_reg(ecp, MII_BMCR); if (bmcr < 0) { return (bmcr); } if (loopback) { if (!(bmcr & BMCR_LOOPBACK)) { bmcr |= BMCR_LOOPBACK; changed = true; } } else { if (bmcr & BMCR_LOOPBACK) { bmcr &= ~BMCR_LOOPBACK; changed = true; } } if (changed) { err = write_phy_reg(ecp, MII_BMCR, bmcr); } printk(KERN_INFO"changed - %s \n", changed ? "true" : "false"); return (err); }
/** * fdp110_setup_advert -- set auto-negotiation advertisement * return positive value wrote to ANAR reg if success, negative value if fail */ static int fdp110_setup_advert(ec_priv_t * ecp, int advertising) { int adv; int err; const int supported = ADVERTISE_ALL | ADVERTISE_PAUSE_CAP; adv = read_phy_reg(ecp, MII_ADVERTISE); if (adv < 0) { return (adv); } /* remove old supported features, but maintain others bit */ adv &= ~supported; if (!(advertising & supported)) { return (-1); } adv |= (advertising & supported); err = write_phy_reg(ecp, MII_ADVERTISE, adv); if (err < 0) { return (err); } /* in fact, when we set new value to phy's advertisement reg, phy will auto-neg again, * but some times it don't, so we manually force it auto-neg again. * we don't wait for auto-neg completion, link change interrupt will capture it */ err = restart_autoneg(ecp); return (err < 0 ? err : adv); }
/** * fdp110_setup_forced -- configure phy work on @speed and @duplex mode forciblly * NOTE: this will close auto-neg function * return 0 if success, negative value if fail */ static int fdp110_setup_forced(ec_priv_t * ecp, int speed, int duplex) { int err = 0; int eval; int bmcr; bmcr = read_phy_reg(ecp, MII_BMCR); if (bmcr < 0) { printk(KERN_ERR"error read bmcr\n"); return (-1); } eval = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX); if (ETH_SPEED_100M == speed) { eval |= BMCR_SPEED100; } if (ETH_DUP_FULL == duplex) { eval |= BMCR_FULLDPLX; } if (eval != bmcr) { err = write_phy_reg(ecp, MII_BMCR, eval); } return (err); }
static inline void phy_reg_set_bits(ec_priv_t * ecp, unsigned short reg_addr, int bits) { unsigned short reg_val; reg_val = read_phy_reg(ecp, reg_addr); reg_val |= (unsigned short)bits; printk(KERN_DEBUG" %s %d write reg_val:0x%x\n", __FUNCTION__,__LINE__,reg_val); write_phy_reg(ecp, reg_addr, reg_val); reg_val = read_phy_reg(ecp, reg_addr); printk(KERN_DEBUG" %s %d write after read reg_val:0x%x\n", __FUNCTION__,__LINE__,reg_val); }
/** * fdp110_setup_aneg - setup or disable auto-negotiation; * if enable auto-neg, we enable and restart auto-neg, don't wait for it completion * link change interrupt can capture it * if disable auto-neg, but auto-neg is already disabled, then nothing to do, * else disable auto-neg * return 0 if success, negative value if fail */ static int fdp110_setup_aneg(ec_priv_t * ecp, bool autoneg) { int bmcr; int err; bmcr = read_phy_reg(ecp, MII_BMCR); if (bmcr < 0) { return (bmcr); } if (autoneg) { bmcr |= BMCR_ANENABLE | BMCR_ANRESTART; err = write_phy_reg(ecp, MII_BMCR, bmcr); if (err < 0) return (err); } else if (bmcr & BMCR_ANENABLE) { printk(KERN_INFO"disable auto-neg\n"); bmcr &= ~BMCR_ANENABLE; err = write_phy_reg(ecp, MII_BMCR, bmcr); if (err < 0) return (err); } return (0); }
static void config_sata_phy(u64 regbase) { u32 port, i, reg; for (port = 0; port < 2; port++) { for (i = 0, reg = RXCDRCALFOSC0; reg <= CALDUTY; reg++, i++) write_phy_reg(regbase, reg, port, sata_phy_config1[i]); for (i = 0, reg = RXDPIF; reg <= PPMDRIFTMAX_HI; reg++, i++) write_phy_reg(regbase, reg, port, sata_phy_config2[i]); } }
static inline void phy_reg_clear_bits(ec_priv_t * ecp, unsigned short reg_addr, int bits) { unsigned short reg_val; reg_val = read_phy_reg(ecp, reg_addr); reg_val &= ~(unsigned short)bits; write_phy_reg(ecp, reg_addr, reg_val); }
// Speed = 0: AUTO 1: 100M 2: 10M int set_network_speed(unsigned char *net_device, int net_speed) { unsigned int reg_num, reg_val; reg_num = 0; int speed; if ((net_speed==ETH_10MHD)||(net_speed==ETH_10MFD)) speed=2; else if ((net_speed==ETH_100MHD)||(net_speed==ETH_100MFD)) speed=1; else speed=0; if (read_phy_reg(net_device, reg_num, ®_val) == -1) return -1; if (speed) reg_val &= ~BMCR_ANENABLE; else reg_val |= BMCR_ANENABLE; if (write_phy_reg(net_device, reg_num, reg_val) == -1) return -1; switch (speed) { case 0: return 0; case 1: reg_val &= ~BMCR_ANENABLE; reg_val |= BMCR_SPEED100; break; case 2: reg_val &= ~(BMCR_ANENABLE|BMCR_SPEED100); break; default: return -1; } if (write_phy_reg(net_device, reg_num, reg_val) == -1) return -1; return 0; }
static inline int restart_autoneg(ec_priv_t * ecp) { int bmcr_val; bmcr_val = read_phy_reg(ecp, MII_BMCR); if (bmcr_val < 0) { return (bmcr_val); } bmcr_val |= BMCR_ANENABLE | BMCR_ANRESTART; return (write_phy_reg(ecp, MII_BMCR, bmcr_val)); }
/** * fdp110_suspend -- power down or power on the phy * return 0 if success, negative if fail */ static int fdp110_suspend(ec_priv_t * ecp, bool power_down) { int reg_val; reg_val = read_phy_reg(ecp, MII_BMCR); if (reg_val < 0) { return (reg_val); } if (power_down) { reg_val |= BMCR_PDOWN; } else { reg_val &= ~BMCR_PDOWN; } return (write_phy_reg(ecp, MII_BMCR, reg_val)); }
static int atc2605_hw_init(ec_priv_t *ecp) { unsigned short atc260x_temp; struct atc260x_dev *atc260x = ecp->atc260x; /*ethernet mfp0 RMII 1st*/ //hw_rmii_get_pin(); //mac_rmii_get_pin(); /************************phy init*****************************/ /*enable phy clock*/ atc260x_reg_setbits(atc260x, atc2603_CMU_DEVRST, 0x200, 0x200); udelay(100); /*ethernet wrapper rest*/ atc260x_reg_setbits(atc260x, atc2603_CMU_DEVRST, 0x08, 0x0); udelay(100); atc260x_reg_setbits(atc260x, atc2603_CMU_DEVRST, 0x08, 0x08); udelay(100); /*GL5302 PHY avoid reboot bug, reset PLL*/ atc260x_reg_setbits(atc260x, atc2603_PHY_PLL_CTL0, 0x03, 0x02); //25Mhz mdelay(5); atc260x_reg_setbits(atc260x, atc2603_PHY_PLL_CTL1, 0x200, 0x200);//bit9=1,enetpll ALV LDO enable mdelay(200); atc260x_reg_setbits(atc260x, atc2603_PHY_PLL_CTL0, 0x03, 0x01); //bit0=1,bit1=0,ethernet pll enable ,24Mhz mdelay(1); /* 5203 PAD_CLKO_25M output 25MHz clock to 2605 */ atc260x_reg_setbits(atc260x, atc2603_PHY_PLL_CTL0, 0x03, 0x03); //25Mhz mdelay(5); atc260x_reg_write(atc260x, atc2603_PHY_CONFIG, 0x00); //auto, phy power on atc260x_reg_write(atc260x, atc2603_PHY_ADDR, 0x01); //set phy address= 0x01 atc260x_reg_write(atc260x, atc2603_PHY_CTRL, 0x01); //rmii,100Mbps //add modify atc260x_reg_write(atc260x, atc2603_PHY_HW_RST, 0x01); //reset the phy udelay(100); do { atc260x_temp = atc260x_reg_read(atc260x, atc2603_PHY_HW_RST); }while(atc260x_temp & 0x1); //waite for reset process completion /*enable RMII_REF_CLK and EXTIRQ pad and disable the other 6 RMII pad, gl5302 bug amend*/ atc260x_reg_setbits(atc260x, atc2603_PAD_EN, 0xff, 0x81); udelay(100); //pad_drv level 3 for fpga test atc260x_reg_setbits(atc260x, atc2603_PAD_DRV1, 0xfff, 0x145); //atc260x_reg_setbits(atc260x, atc2603_PAD_DRV1, 0xfff, 0x28a); //level 4 printk("5302 PAD_EN: 0x%x\n", (uint)atc260x_reg_read(atc260x, atc2603_PAD_EN)); printk("5302 PAD_DRV1: 0x%x\n", (uint)atc260x_reg_read(atc260x, atc2603_PAD_DRV1)); atc260x_reg_setbits(atc260x, atc2603_PHY_INT_CTRL, 0xf, 0xf); //enable phy int control /*clear phy INT_STAT*/ atc260x_reg_write(ecp->atc260x, atc2603_PHY_INT_STAT, 0xff); //printk("1f.atc2603_PHY_INT_STAT:0x%x\n", atc260x_reg_read(atc260x, gl5302_PHY_INT_STAT)); udelay(100); printk("5302 MFP_CTL0: 0x%x\n", (uint)atc260x_reg_read(atc260x, atc2603_MFP_CTL0)); #ifdef ETHENRET_PHY_LOOP_BACK /* phy loopback */ //atc260x_reg_setbits(atc260x, atc2603_PHY_CONFIG, 0x1 << 11, 0x1 << 11); printk("phy config: 0x%x\n", (uint)atc260x_reg_read(atc260x, atc2603_PHY_CONFIG)); { /* shut auto-negoiation */ ushort bmcr = read_phy_reg(ecp, MII_BMCR); bmcr &= ~BMCR_ANENABLE; write_phy_reg(ecp, MII_BMCR, bmcr); bmcr = read_phy_reg(ecp, MII_BMCR); bmcr |= BMCR_LOOPBACK; write_phy_reg(ecp, MII_BMCR, bmcr); printk("phy bmcr: 0x%x\n", (uint)read_phy_reg(ecp, MII_BMCR)); } #endif return 0; }
/** * phy_init -- initialize phy - ATC2605 or KSZ8041 * return 0 if success, else fail */ static int phy_init(ec_priv_t * ecp) { int reg_val; //u16 temp; unsigned int cnt = 0; phy_reg_set_bits(ecp, MII_BMCR, BMCR_RESET); do { reg_val = read_phy_reg(ecp, MII_BMCR); if (cnt++ > 1000) { printk(KERN_ERR"ethernet phy BMCR_RESET timeout!!!\n"); break; } } while (reg_val & BMCR_RESET); if (ecp->phy_model == ETH_PHY_MODEL_ATC2605) { phy_reg_set_bits(ecp, PHY_REG_FTC1, PHY_FTC_PRL); phy_reg_set_bits(ecp, PHY_REG_FTC2, PHY_FTC_CMPT); } else if (ecp->phy_model == ETH_PHY_MODEL_KSZ8041TL) { /* only turn on link up/down phy interrupt */ write_phy_reg(ecp, MII_ICSR, ICSR_LINKUP_EN | ICSR_LINKDOWN_EN); printk(KERN_DEBUG"MII_ICSR:0x%x\n", (unsigned)read_phy_reg(ecp, MII_ICSR)); phy_reg_set_bits(ecp, MII_PHY_CTL2, PHY_CTL2_INT_LEVEL); printk(KERN_DEBUG"MII_PHY_CTL2:0x%x\n", (unsigned)read_phy_reg(ecp, MII_PHY_CTL2)); } else if (ecp->phy_model == ETH_PHY_MODEL_RTL8201) { write_phy_reg(ecp, PHY_RTL8201F_REG_PAGE_SELECT, PHY_RTL8201F_REG_PAGE_SELECT_SEVEN); #ifndef CONFIG_POLL_PHY_STATE /* only turn on link up/down phy interrupt */ write_phy_reg(ecp, PHY_RTL8201F_REG_INT_LED_FUNC, PHY_RTL8201F_PIN_LINK_STATE_CHANGE); #endif /*As datasheet says tx&rx offset's default value is 0xF but be zero in fact.Reset them*/ write_phy_reg(ecp, PHY_RTL8201F_REG_RMSR, PHY_RTL8201F_RMSR_CLK_DIR_INPUT | PHY_RTL8201F_RMSR_RMII_MODE|PHY_RTL8201F_RMSR_RMII_RX_OFFSET|PHY_RTL8201F_RMSR_RMII_TX_OFFSET); write_phy_reg(ecp, PHY_RTL8201F_REG_PAGE_SELECT, PHY_RTL8201F_REG_PAGE_SELECT_ZERO); } else if (ecp->phy_model == ETH_PHY_MODEL_SR8201G) { write_phy_reg(ecp, PHY_SR8201G_REG_PAGE_SELECT, PHY_SR8201G_REG_PAGE_SELECT_SEVEN); #ifndef CONFIG_POLL_PHY_STATE /* only turn on link up/down phy interrupt */ write_phy_reg(ecp, PHY_SR8201G_REG_INT_LED_FUNC, PHY_SR8201G_INT_PIN_SELECT | PHY_SR8201G_INT_PIN_LINK_STATE_CHANGE); #endif write_phy_reg(ecp, PHY_SR8201G_REG_RMSR, PHY_SR8201G_CLK_DIR_INPUT); write_phy_reg(ecp, PHY_SR8201G_REG_PAGE_SELECT, PHY_SR8201G_REG_PAGE_SELECT_ZERO); }else { printk(KERN_ERR"NOT supported phy model: %u\n", ecp->phy_model); } #if 0 /* adjust tx current */ temp = read_phy_reg(ecp, 0x12); temp &= ~0x780; //temp |= 0x600; //1100, add 50+100uA //temp |= 0x680; //1101 //temp |= 0x480; //1001 //temp |= 0x280; //0101 //temp |= 0x80; //0001 temp |= 0x180; //0011, minus 50uA max 2.57V //temp |= 0x780; //1111 write_phy_reg(ecp, 0x12, temp); printk("PHY_REG_TXPN = 0x%x\n", (u32)read_phy_reg(ecp, 0x12)); #endif #ifdef WORK_IN_10M_MODE /* limit to 10M for 5203 MAC bug */ phy_reg_clear_bits(ecp, MII_ADVERTISE, ADVERTISE_100HALF | ADVERTISE_100FULL); #endif printk(KERN_DEBUG"MII_ADVERTISE: 0x%04x\n", (uint)read_phy_reg(ecp, MII_ADVERTISE)); printk(KERN_DEBUG"%s %d MII_BMCR: 0x%04x\n", __FUNCTION__,__LINE__,(uint)read_phy_reg(ecp, MII_BMCR)); /* auto-negotiate and wait for completion, then get link status */ phy_reg_set_bits(ecp, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART); printk(KERN_DEBUG"start aneg...\n"); printk(KERN_DEBUG"%s %d MII_BMCR: 0x%04x\n", __FUNCTION__,__LINE__,(uint)read_phy_reg(ecp, MII_BMCR)); /* wait_for_aneg_completion(ecp) sleep(), so it shall not be invoked in * ec_netdev_transmit_timeout() which runs in interrupt bottom half. */ #if 0 printk("wait for aneg...\n"); if (wait_for_aneg_completion(ecp)) { printk("MII_BMCR:0x%x\n", read_phy_reg(ecp, MII_BMCR)); printk("auto-negotiation is timeout.\n"); return (1); } int i = 0 ; for (i = 0; i < MII_TIME_OUT; i++) { reg_val = read_phy_reg(ecp, MII_BMSR); if (reg_val & BMSR_LSTATUS) { ecp->linked = true; break; } udelay(1); } if (MII_TIME_OUT == i) { ecp->linked = false; printk("link fail.\n"); return (1); } #else /* not wait, set link status not connected and return*/ ecp->linked = false; #endif printk(KERN_INFO"link status is: %s\n", ecp->linked ? "true" : "false"); return (0); }