+static int serdes_init_1g_serdes(struct niu *np)
+{
+ struct niu_link_config *lp = &np->link_config;
+ unsigned long ctrl_reg, test_cfg_reg, pll_cfg, i;
+ u64 ctrl_val, test_cfg_val, sig, mask, val;
+ int err;
+ u64 reset_val, val_rd;
+
+ val = ENET_SERDES_PLL_HRATE0 | ENET_SERDES_PLL_HRATE1 |
+ ENET_SERDES_PLL_HRATE2 | ENET_SERDES_PLL_HRATE3 |
+ ENET_SERDES_PLL_FBDIV0;
+ switch (np->port) {
+ case 0:
+ reset_val = ENET_SERDES_RESET_0;
+ ctrl_reg = ENET_SERDES_0_CTRL_CFG;
+ test_cfg_reg = ENET_SERDES_0_TEST_CFG;
+ pll_cfg = ENET_SERDES_0_PLL_CFG;
+ break;
+ case 1:
+ reset_val = ENET_SERDES_RESET_1;
+ ctrl_reg = ENET_SERDES_1_CTRL_CFG;
+ test_cfg_reg = ENET_SERDES_1_TEST_CFG;
+ pll_cfg = ENET_SERDES_1_PLL_CFG;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ ctrl_val = (ENET_SERDES_CTRL_SDET_0 |
+ ENET_SERDES_CTRL_SDET_1 |
+ ENET_SERDES_CTRL_SDET_2 |
+ ENET_SERDES_CTRL_SDET_3 |
+ (0x5 << ENET_SERDES_CTRL_EMPH_0_SHIFT) |
+ (0x5 << ENET_SERDES_CTRL_EMPH_1_SHIFT) |
+ (0x5 << ENET_SERDES_CTRL_EMPH_2_SHIFT) |
+ (0x5 << ENET_SERDES_CTRL_EMPH_3_SHIFT) |
+ (0x1 << ENET_SERDES_CTRL_LADJ_0_SHIFT) |
+ (0x1 << ENET_SERDES_CTRL_LADJ_1_SHIFT) |
+ (0x1 << ENET_SERDES_CTRL_LADJ_2_SHIFT) |
+ (0x1 << ENET_SERDES_CTRL_LADJ_3_SHIFT));
+ test_cfg_val = 0;
+
+ if (lp->loopback_mode == LOOPBACK_PHY) {
+ test_cfg_val |= ((ENET_TEST_MD_PAD_LOOPBACK <<
+ ENET_SERDES_TEST_MD_0_SHIFT) |
+ (ENET_TEST_MD_PAD_LOOPBACK <<
+ ENET_SERDES_TEST_MD_1_SHIFT) |
+ (ENET_TEST_MD_PAD_LOOPBACK <<
+ ENET_SERDES_TEST_MD_2_SHIFT) |
+ (ENET_TEST_MD_PAD_LOOPBACK <<
+ ENET_SERDES_TEST_MD_3_SHIFT));
+ }
+
+ nw64(ENET_SERDES_RESET, reset_val);
+ mdelay(20);
+ val_rd = nr64(ENET_SERDES_RESET);
+ val_rd &= ~reset_val;
+ nw64(pll_cfg, val);
+ nw64(ctrl_reg, ctrl_val);
+ nw64(test_cfg_reg, test_cfg_val);
+ nw64(ENET_SERDES_RESET, val_rd);
+ mdelay(2000);
+
+ /* Initialize all 4 lanes of the SERDES. */
+ for (i = 0; i < 4; i++) {
+ u32 rxtx_ctrl, glue0;
+
+ err = esr_read_rxtx_ctrl(np, i, &rxtx_ctrl);
+ if (err)
+ return err;
+ err = esr_read_glue0(np, i, &glue0);
+ if (err)
+ return err;
+
+ rxtx_ctrl &= ~(ESR_RXTX_CTRL_VMUXLO);
+ rxtx_ctrl |= (ESR_RXTX_CTRL_ENSTRETCH |
+ (2 << ESR_RXTX_CTRL_VMUXLO_SHIFT));
+
+ glue0 &= ~(ESR_GLUE_CTRL0_SRATE |
+ ESR_GLUE_CTRL0_THCNT |
+ ESR_GLUE_CTRL0_BLTIME);
+ glue0 |= (ESR_GLUE_CTRL0_RXLOSENAB |
+ (0xf << ESR_GLUE_CTRL0_SRATE_SHIFT) |
+ (0xff << ESR_GLUE_CTRL0_THCNT_SHIFT) |
+ (BLTIME_300_CYCLES <<
+ ESR_GLUE_CTRL0_BLTIME_SHIFT));
+
+ err = esr_write_rxtx_ctrl(np, i, rxtx_ctrl);
+ if (err)
+ return err;
+ err = esr_write_glue0(np, i, glue0);
+ if (err)
+ return err;
+ }
+
+
+ sig = nr64(ESR_INT_SIGNALS);
+ switch (np->port) {
+ case 0:
+ val = (ESR_INT_SRDY0_P0 | ESR_INT_DET0_P0);
+ mask = val;
+ break;
+
+ case 1:
+ val = (ESR_INT_SRDY0_P1 | ESR_INT_DET0_P1);
+ mask = val;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if ((sig & mask) != val) {
+ dev_err(np->device, PFX "Port %u signal bits [%08x] are not "
+ "[%08x]\n", np->port, (int) (sig & mask), (int) val);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int link_status_1g_serdes(struct niu *np, int *link_up_p)
+{
+ struct niu_link_config *lp = &np->link_config;
+ int link_up;
+ u64 val;
+ u16 current_speed;
+ unsigned long flags;
+ u8 current_duplex;
+
+ link_up = 0;
+ current_speed = SPEED_INVALID;
+ current_duplex = DUPLEX_INVALID;
+
+ spin_lock_irqsave(&np->lock, flags);
+
+ val = nr64_pcs(PCS_MII_STAT);
+
+ if (val & PCS_MII_STAT_LINK_STATUS) {
+ link_up = 1;
+ current_speed = SPEED_1000;
+ current_duplex = DUPLEX_FULL;
+ }
+
+ lp->active_speed = current_speed;
+ lp->active_duplex = current_duplex;
+ spin_unlock_irqrestore(&np->lock, flags);
+
+ *link_up_p = link_up;
+ return 0;
+}
+
+
+static int link_status_10g_serdes(struct niu *np, int *link_up_p)
+{
+ unsigned long flags;
+ struct niu_link_config *lp = &np->link_config;
+ int link_up = 0;
+ int link_ok = 1;
+ u64 val, val2;
+ u16 current_speed;
+ u8 current_duplex;
+
+ if (!(np->flags & NIU_FLAGS_10G))
+ return link_status_1g_serdes(np, link_up_p);
+
+ current_speed = SPEED_INVALID;
+ current_duplex = DUPLEX_INVALID;
+ spin_lock_irqsave(&np->lock, flags);
+
+ val = nr64_xpcs(XPCS_STATUS(0));
+ val2 = nr64_mac(XMAC_INTER2);
+ if (val2 & 0x01000000)
+ link_ok = 0;
+
+ if ((val & 0x1000ULL) && link_ok) {
+ link_up = 1;
+ current_speed = SPEED_10000;
+ current_duplex = DUPLEX_FULL;
+ }
+ lp->active_speed = current_speed;
+ lp->active_duplex = current_duplex;
+ spin_unlock_irqrestore(&np->lock, flags);
+ *link_up_p = link_up;
+ return 0;
+}
+
+
+static int link_status_1g_rgmii(struct niu *np, int *link_up_p)
+{
+ struct niu_link_config *lp = &np->link_config;
+ u16 current_speed, bmsr;
+ unsigned long flags;
+ u8 current_duplex;
+ int err, link_up;
+
+ link_up = 0;
+ current_speed = SPEED_INVALID;
+ current_duplex = DUPLEX_INVALID;
+
+ spin_lock_irqsave(&np->lock, flags);
+
+ err = -EINVAL;
+
+ err = mii_read(np, np->phy_addr, MII_BMSR);
+ if (err < 0)
+ goto out;
+
+ bmsr = err;
+ if (bmsr & BMSR_LSTATUS) {
+ u16 adv, lpa, common, estat;
+
+ err = mii_read(np, np->phy_addr, MII_ADVERTISE);
+ if (err < 0)
+ goto out;
+ adv = err;
+
+ err = mii_read(np, np->phy_addr, MII_LPA);
+ if (err < 0)
+ goto out;
+ lpa = err;
+
+ common = adv & lpa;
+
+ err = mii_read(np, np->phy_addr, MII_ESTATUS);
+ if (err < 0)
+ goto out;
+ estat = err;
+ link_up = 1;
+ current_speed = SPEED_1000;
+ current_duplex = DUPLEX_FULL;
+
+ }
+ lp->active_speed = current_speed;
+ lp->active_duplex = current_duplex;
+ err = 0;
+
+out:
+ spin_unlock_irqrestore(&np->lock, flags);
+
+ *link_up_p = link_up;
+ return err;
+}
+
+