📄 niu.c
字号:
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(ctrl_reg, ctrl_val); nw64(test_cfg_reg, test_cfg_val); /* 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; } err = esr_reset(np); if (err) return err; sig = nr64(ESR_INT_SIGNALS); switch (np->port) { case 0: mask = ESR_INT_SIGNALS_P0_BITS; val = (ESR_INT_SRDY0_P0 | ESR_INT_DET0_P0 | ESR_INT_XSRDY_P0 | ESR_INT_XDP_P0_CH3 | ESR_INT_XDP_P0_CH2 | ESR_INT_XDP_P0_CH1 | ESR_INT_XDP_P0_CH0); break; case 1: mask = ESR_INT_SIGNALS_P1_BITS; val = (ESR_INT_SRDY0_P1 | ESR_INT_DET0_P1 | ESR_INT_XSRDY_P1 | ESR_INT_XDP_P1_CH3 | ESR_INT_XDP_P1_CH2 | ESR_INT_XDP_P1_CH1 | ESR_INT_XDP_P1_CH0); 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 serdes_init_1g(struct niu *np){ u64 val; val = nr64(ENET_SERDES_1_PLL_CFG); val &= ~ENET_SERDES_PLL_FBDIV2; switch (np->port) { case 0: val |= ENET_SERDES_PLL_HRATE0; break; case 1: val |= ENET_SERDES_PLL_HRATE1; break; case 2: val |= ENET_SERDES_PLL_HRATE2; break; case 3: val |= ENET_SERDES_PLL_HRATE3; break; default: return -EINVAL; } nw64(ENET_SERDES_1_PLL_CFG, val); return 0;}static int bcm8704_reset(struct niu *np){ int err, limit; err = mdio_read(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR, MII_BMCR); if (err < 0) return err; err |= BMCR_RESET; err = mdio_write(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR, MII_BMCR, err); if (err) return err; limit = 1000; while (--limit >= 0) { err = mdio_read(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR, MII_BMCR); if (err < 0) return err; if (!(err & BMCR_RESET)) break; } if (limit < 0) { dev_err(np->device, PFX "Port %u PHY will not reset " "(bmcr=%04x)\n", np->port, (err & 0xffff)); return -ENODEV; } return 0;}/* When written, certain PHY registers need to be read back twice * in order for the bits to settle properly. */static int bcm8704_user_dev3_readback(struct niu *np, int reg){ int err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, reg); if (err < 0) return err; err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, reg); if (err < 0) return err; return 0;}static int bcm8704_init_user_dev3(struct niu *np){ int err; err = mdio_write(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, BCM8704_USER_CONTROL, (USER_CONTROL_OPTXRST_LVL | USER_CONTROL_OPBIASFLT_LVL | USER_CONTROL_OBTMPFLT_LVL | USER_CONTROL_OPPRFLT_LVL | USER_CONTROL_OPTXFLT_LVL | USER_CONTROL_OPRXLOS_LVL | USER_CONTROL_OPRXFLT_LVL | USER_CONTROL_OPTXON_LVL | (0x3f << USER_CONTROL_RES1_SHIFT))); if (err) return err; err = mdio_write(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, BCM8704_USER_PMD_TX_CONTROL, (USER_PMD_TX_CTL_XFP_CLKEN | (1 << USER_PMD_TX_CTL_TX_DAC_TXD_SH) | (2 << USER_PMD_TX_CTL_TX_DAC_TXCK_SH) | USER_PMD_TX_CTL_TSCK_LPWREN)); if (err) return err; err = bcm8704_user_dev3_readback(np, BCM8704_USER_CONTROL); if (err) return err; err = bcm8704_user_dev3_readback(np, BCM8704_USER_PMD_TX_CONTROL); if (err) return err; err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, BCM8704_USER_OPT_DIGITAL_CTRL); if (err < 0) return err; err &= ~USER_ODIG_CTRL_GPIOS; err |= (0x3 << USER_ODIG_CTRL_GPIOS_SHIFT); err = mdio_write(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, BCM8704_USER_OPT_DIGITAL_CTRL, err); if (err) return err; mdelay(1000); return 0;}static int mrvl88x2011_act_led(struct niu *np, int val){ int err; err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV2_ADDR, MRVL88X2011_LED_8_TO_11_CTL); if (err < 0) return err; err &= ~MRVL88X2011_LED(MRVL88X2011_LED_ACT,MRVL88X2011_LED_CTL_MASK); err |= MRVL88X2011_LED(MRVL88X2011_LED_ACT,val); return mdio_write(np, np->phy_addr, MRVL88X2011_USER_DEV2_ADDR, MRVL88X2011_LED_8_TO_11_CTL, err);}static int mrvl88x2011_led_blink_rate(struct niu *np, int rate){ int err; err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV2_ADDR, MRVL88X2011_LED_BLINK_CTL); if (err >= 0) { err &= ~MRVL88X2011_LED_BLKRATE_MASK; err |= (rate << 4); err = mdio_write(np, np->phy_addr, MRVL88X2011_USER_DEV2_ADDR, MRVL88X2011_LED_BLINK_CTL, err); } return err;}static int xcvr_init_10g_mrvl88x2011(struct niu *np){ int err; /* Set LED functions */ err = mrvl88x2011_led_blink_rate(np, MRVL88X2011_LED_BLKRATE_134MS); if (err) return err; /* led activity */ err = mrvl88x2011_act_led(np, MRVL88X2011_LED_CTL_OFF); if (err) return err; err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV3_ADDR, MRVL88X2011_GENERAL_CTL); if (err < 0) return err; err |= MRVL88X2011_ENA_XFPREFCLK; err = mdio_write(np, np->phy_addr, MRVL88X2011_USER_DEV3_ADDR, MRVL88X2011_GENERAL_CTL, err); if (err < 0) return err; err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV1_ADDR, MRVL88X2011_PMA_PMD_CTL_1); if (err < 0) return err; if (np->link_config.loopback_mode == LOOPBACK_MAC) err |= MRVL88X2011_LOOPBACK; else err &= ~MRVL88X2011_LOOPBACK; err = mdio_write(np, np->phy_addr, MRVL88X2011_USER_DEV1_ADDR, MRVL88X2011_PMA_PMD_CTL_1, err); if (err < 0) return err; /* Enable PMD */ return mdio_write(np, np->phy_addr, MRVL88X2011_USER_DEV1_ADDR, MRVL88X2011_10G_PMD_TX_DIS, MRVL88X2011_ENA_PMDTX);}static int xcvr_init_10g_bcm8704(struct niu *np){ struct niu_link_config *lp = &np->link_config; u16 analog_stat0, tx_alarm_status; int err; err = bcm8704_reset(np); if (err) return err; err = bcm8704_init_user_dev3(np); if (err) return err; err = mdio_read(np, np->phy_addr, BCM8704_PCS_DEV_ADDR, MII_BMCR); if (err < 0) return err; err &= ~BMCR_LOOPBACK; if (lp->loopback_mode == LOOPBACK_MAC) err |= BMCR_LOOPBACK; err = mdio_write(np, np->phy_addr, BCM8704_PCS_DEV_ADDR, MII_BMCR, err); if (err) return err;#if 1 err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR, MII_STAT1000); if (err < 0) return err; pr_info(PFX "Port %u PMA_PMD(MII_STAT1000) [%04x]\n", np->port, err); err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, 0x20); if (err < 0) return err; pr_info(PFX "Port %u USER_DEV3(0x20) [%04x]\n", np->port, err); err = mdio_read(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR, MII_NWAYTEST); if (err < 0) return err; pr_info(PFX "Port %u PHYXS(MII_NWAYTEST) [%04x]\n", np->port, err);#endif /* XXX dig this out it might not be so useful XXX */ err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, BCM8704_USER_ANALOG_STATUS0); if (err < 0) return err; err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, BCM8704_USER_ANALOG_STATUS0); if (err < 0) return err; analog_stat0 = err; err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, BCM8704_USER_TX_ALARM_STATUS); if (err < 0) return err; err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, BCM8704_USER_TX_ALARM_STATUS); if (err < 0) return err; tx_alarm_status = err; if (analog_stat0 != 0x03fc) { if ((analog_stat0 == 0x43bc) && (tx_alarm_status != 0)) { pr_info(PFX "Port %u cable not connected " "or bad cable.\n", np->port); } else if (analog_stat0 == 0x639c) { pr_info(PFX "Port %u optical module is bad " "or missing.\n", np->port); } } return 0;}static int xcvr_init_10g(struct niu *np){ int phy_id, err; u64 val; val = nr64_mac(XMAC_CONFIG); val &= ~XMAC_CONFIG_LED_POLARITY; val |= XMAC_CONFIG_FORCE_LED_ON; nw64_mac(XMAC_CONFIG, val); /* XXX shared resource, lock parent XXX */ val = nr64(MIF_CONFIG); val |= MIF_CONFIG_INDIRECT_MODE; nw64(MIF_CONFIG, val); phy_id = phy_decode(np->parent->port_phy, np->port); phy_id = np->parent->phy_probe_info.phy_id[phy_id][np->port]; /* handle different phy types */ switch (phy_id & NIU_PHY_ID_MASK) { case NIU_PHY_ID_MRVL88X2011: err = xcvr_init_10g_mrvl88x2011(np); break; default: /* bcom 8704 */ err = xcvr_init_10g_bcm8704(np); break; } return 0;}static int mii_reset(struct niu *np){ int limit, err; err = mii_write(np, np->phy_addr, MII_BMCR, BMCR_RESET); if (err) return err; limit = 1000; while (--limit >= 0) { udelay(500); err = mii_read(np, np->phy_addr, MII_BMCR); if (err < 0) return err; if (!(err & BMCR_RESET)) break; } if (limit < 0) { dev_err(np->device, PFX "Port %u MII would not reset, " "bmcr[%04x]\n", np->port, err); return -ENODEV; } return 0;}static int mii_init_common(struct niu *np){ struct niu_link_config *lp = &np->link_config; u16 bmcr, bmsr, adv, estat; int err; err = mii_reset(np); if (err) return err; err = mii_read(np, np->phy_addr, MII_BMSR); if (err < 0) return err; bmsr = err; estat = 0; if (bmsr & BMSR_ESTATEN) { err = mii_read(np, np->phy_addr, MII_ESTATUS); if (err < 0) return err; estat = err; } bmcr = 0; err = mii_write(np, np->phy_addr, MII_BMCR, bmcr); if (err) return err; if (lp->loopback_mode == LOOPBACK_MAC) { bmcr |= BMCR_LOOPBACK; if (lp->active_speed == SPEED_1000) bmcr |= BMCR_SPEED1000; if (lp->active_duplex == DUPLEX_FULL) bmcr |= BMCR_FULLDPLX; } if (lp->loopback_mode == LOOPBACK_PHY) { u16 aux; aux = (BCM5464R_AUX_CTL_EXT_LB | BCM5464R_AUX_CTL_WRITE_1); err = mii_write(np, np->phy_addr, BCM5464R_AUX_CTL, aux); if (err) return err; } /* XXX configurable XXX */ /* XXX for now don't advertise half-duplex or asym pause... XXX */ adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP; if (bmsr & BMSR_10FULL) adv |= ADVERTISE_10FULL; if (bmsr & BMSR_100FULL) adv |= ADVERTISE_100FULL; err = mii_write(np, np->phy_addr, MII_ADVERTISE, adv); if (err) return err; if (bmsr & BMSR_ESTATEN) { u16 ctrl1000 = 0; if (estat & ESTATUS_1000_TFULL) ctrl1000 |= ADVERTISE_1000FULL; err = mii_write(np, np->phy_addr, MII_CTRL1000, ctrl1000); if (err) return err; } bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); err = mii_write(np, np->phy_addr, MII_BMCR, bmcr); if (err) return err; err = mii_read(np, np->phy_addr, MII_BMCR); if (err < 0) return err; err = mii_read(np, np->phy_addr, MII_BMSR); if (err < 0) return err;#if 0 pr_info(PFX "Port %u after MII init bmcr[%04x] bmsr[%04x]\n", np->port, bmcr, bmsr);#endif return 0;}static int xcvr_init_1g(struct niu *np){ u64 val; /* XXX shared resource, lock parent XXX */ val = nr64(MIF_CONFIG); val &= ~MIF_CONFIG_INDIRECT_MODE; nw64(MIF_CONFIG, val); return mii_init_common(np);}static int niu_xcvr_init(struct niu *np){ const struct niu_phy_ops *ops = np->phy_ops; int err; err = 0; if (ops->xcvr_init) err = ops->xcvr_init(np); return err;}static int niu_serdes_init(struct niu *np){ const struct niu_phy_ops *ops = np->phy_ops; int err; err = 0; if (ops->serdes_init) err = ops->serdes_init(np); return err;}static void niu_init_xif(struct niu *);static void niu_handle_led(struct niu *, int status);static int niu_link_status_common(struct niu *np, int link_up){ struct niu_link_config *lp = &np->link_config;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -