static int mvebu_comphy_ethernet_init_reset()

in marvell/phy-mvebu-cp110-comphy.c [336:450]


static int mvebu_comphy_ethernet_init_reset(struct mvebu_comphy_lane *lane)
{
	struct mvebu_comphy_priv *priv = lane->priv;
	u32 val;

	regmap_read(priv->regmap, MVEBU_COMPHY_CONF1(lane->id), &val);
	val &= ~MVEBU_COMPHY_CONF1_USB_PCIE;
	val |= MVEBU_COMPHY_CONF1_PWRUP;
	regmap_write(priv->regmap, MVEBU_COMPHY_CONF1(lane->id), val);

	/* Select baud rates and PLLs */
	val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG0(lane->id));
	val &= ~(MVEBU_COMPHY_SERDES_CFG0_PU_PLL |
		 MVEBU_COMPHY_SERDES_CFG0_PU_RX |
		 MVEBU_COMPHY_SERDES_CFG0_PU_TX |
		 MVEBU_COMPHY_SERDES_CFG0_HALF_BUS |
		 MVEBU_COMPHY_SERDES_CFG0_GEN_RX(0xf) |
		 MVEBU_COMPHY_SERDES_CFG0_GEN_TX(0xf) |
		 MVEBU_COMPHY_SERDES_CFG0_RXAUI_MODE);

	switch (lane->submode) {
	case PHY_INTERFACE_MODE_10GBASER:
		val |= MVEBU_COMPHY_SERDES_CFG0_GEN_RX(0xe) |
		       MVEBU_COMPHY_SERDES_CFG0_GEN_TX(0xe);
		break;
	case PHY_INTERFACE_MODE_RXAUI:
		val |= MVEBU_COMPHY_SERDES_CFG0_GEN_RX(0xb) |
		       MVEBU_COMPHY_SERDES_CFG0_GEN_TX(0xb) |
		       MVEBU_COMPHY_SERDES_CFG0_RXAUI_MODE;
		break;
	case PHY_INTERFACE_MODE_2500BASEX:
		val |= MVEBU_COMPHY_SERDES_CFG0_GEN_RX(0x8) |
		       MVEBU_COMPHY_SERDES_CFG0_GEN_TX(0x8) |
		       MVEBU_COMPHY_SERDES_CFG0_HALF_BUS;
		break;
	case PHY_INTERFACE_MODE_SGMII:
		val |= MVEBU_COMPHY_SERDES_CFG0_GEN_RX(0x6) |
		       MVEBU_COMPHY_SERDES_CFG0_GEN_TX(0x6) |
		       MVEBU_COMPHY_SERDES_CFG0_HALF_BUS;
		break;
	default:
		dev_err(priv->dev,
			"unsupported comphy submode (%d) on lane %d\n",
			lane->submode,
			lane->id);
		return -ENOTSUPP;
	}

	writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG0(lane->id));

	if (lane->submode == PHY_INTERFACE_MODE_RXAUI) {
		regmap_read(priv->regmap, MVEBU_COMPHY_SD1_CTRL1, &val);

		switch (lane->id) {
		case 2:
		case 3:
			val |= MVEBU_COMPHY_SD1_CTRL1_RXAUI0_EN;
			break;
		case 4:
		case 5:
			val |= MVEBU_COMPHY_SD1_CTRL1_RXAUI1_EN;
			break;
		default:
			dev_err(priv->dev,
				"RXAUI is not supported on comphy lane %d\n",
				lane->id);
			return -EINVAL;
		}

		regmap_write(priv->regmap, MVEBU_COMPHY_SD1_CTRL1, val);
	}

	/* reset */
	val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));
	val &= ~(MVEBU_COMPHY_SERDES_CFG1_RESET |
		 MVEBU_COMPHY_SERDES_CFG1_CORE_RESET |
		 MVEBU_COMPHY_SERDES_CFG1_RF_RESET);
	writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));

	/* de-assert reset */
	val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));
	val |= MVEBU_COMPHY_SERDES_CFG1_RESET |
	       MVEBU_COMPHY_SERDES_CFG1_CORE_RESET;
	writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));

	/* wait until clocks are ready */
	mdelay(1);

	/* exlicitly disable 40B, the bits isn't clear on reset */
	regmap_read(priv->regmap, MVEBU_COMPHY_CONF6(lane->id), &val);
	val &= ~MVEBU_COMPHY_CONF6_40B;
	regmap_write(priv->regmap, MVEBU_COMPHY_CONF6(lane->id), val);

	/* refclk selection */
	val = readl(priv->base + MVEBU_COMPHY_MISC_CTRL0(lane->id));
	val &= ~MVEBU_COMPHY_MISC_CTRL0_REFCLK_SEL;
	if (lane->submode == PHY_INTERFACE_MODE_10GBASER)
		val |= MVEBU_COMPHY_MISC_CTRL0_ICP_FORCE;
	writel(val, priv->base + MVEBU_COMPHY_MISC_CTRL0(lane->id));

	/* power and pll selection */
	val = readl(priv->base + MVEBU_COMPHY_PWRPLL_CTRL(lane->id));
	val &= ~(MVEBU_COMPHY_PWRPLL_CTRL_RFREQ(0x1f) |
		 MVEBU_COMPHY_PWRPLL_PHY_MODE(0x7));
	val |= MVEBU_COMPHY_PWRPLL_CTRL_RFREQ(0x1) |
	       MVEBU_COMPHY_PWRPLL_PHY_MODE(0x4);
	writel(val, priv->base + MVEBU_COMPHY_PWRPLL_CTRL(lane->id));

	val = readl(priv->base + MVEBU_COMPHY_LOOPBACK(lane->id));
	val &= ~MVEBU_COMPHY_LOOPBACK_DBUS_WIDTH(0x7);
	val |= MVEBU_COMPHY_LOOPBACK_DBUS_WIDTH(0x1);
	writel(val, priv->base + MVEBU_COMPHY_LOOPBACK(lane->id));

	return 0;
}