⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 niu.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	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 + -