brintos

brintos / linux-shallow public Read only

0
0
Text · 36.0 KiB · fefc02d Raw
1113 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2017 Marvell4 *5 * Antoine Tenart <antoine.tenart@free-electrons.com>6 */7 8#include <linux/arm-smccc.h>9#include <linux/clk.h>10#include <linux/io.h>11#include <linux/iopoll.h>12#include <linux/mfd/syscon.h>13#include <linux/module.h>14#include <linux/of.h>15#include <linux/phy.h>16#include <linux/phy/phy.h>17#include <linux/platform_device.h>18#include <linux/regmap.h>19 20/* Relative to priv->base */21#define MVEBU_COMPHY_SERDES_CFG0(n)		(0x0 + (n) * 0x1000)22#define     MVEBU_COMPHY_SERDES_CFG0_PU_PLL	BIT(1)23#define     MVEBU_COMPHY_SERDES_CFG0_GEN_RX(n)	((n) << 3)24#define     MVEBU_COMPHY_SERDES_CFG0_GEN_TX(n)	((n) << 7)25#define     MVEBU_COMPHY_SERDES_CFG0_PU_RX	BIT(11)26#define     MVEBU_COMPHY_SERDES_CFG0_PU_TX	BIT(12)27#define     MVEBU_COMPHY_SERDES_CFG0_HALF_BUS	BIT(14)28#define     MVEBU_COMPHY_SERDES_CFG0_RXAUI_MODE	BIT(15)29#define MVEBU_COMPHY_SERDES_CFG1(n)		(0x4 + (n) * 0x1000)30#define     MVEBU_COMPHY_SERDES_CFG1_RESET	BIT(3)31#define     MVEBU_COMPHY_SERDES_CFG1_RX_INIT	BIT(4)32#define     MVEBU_COMPHY_SERDES_CFG1_CORE_RESET	BIT(5)33#define     MVEBU_COMPHY_SERDES_CFG1_RF_RESET	BIT(6)34#define MVEBU_COMPHY_SERDES_CFG2(n)		(0x8 + (n) * 0x1000)35#define     MVEBU_COMPHY_SERDES_CFG2_DFE_EN	BIT(4)36#define MVEBU_COMPHY_SERDES_STATUS0(n)		(0x18 + (n) * 0x1000)37#define     MVEBU_COMPHY_SERDES_STATUS0_TX_PLL_RDY	BIT(2)38#define     MVEBU_COMPHY_SERDES_STATUS0_RX_PLL_RDY	BIT(3)39#define     MVEBU_COMPHY_SERDES_STATUS0_RX_INIT		BIT(4)40#define MVEBU_COMPHY_PWRPLL_CTRL(n)		(0x804 + (n) * 0x1000)41#define     MVEBU_COMPHY_PWRPLL_CTRL_RFREQ(n)	((n) << 0)42#define     MVEBU_COMPHY_PWRPLL_PHY_MODE(n)	((n) << 5)43#define MVEBU_COMPHY_IMP_CAL(n)			(0x80c + (n) * 0x1000)44#define     MVEBU_COMPHY_IMP_CAL_TX_EXT(n)	((n) << 10)45#define     MVEBU_COMPHY_IMP_CAL_TX_EXT_EN	BIT(15)46#define MVEBU_COMPHY_DFE_RES(n)			(0x81c + (n) * 0x1000)47#define     MVEBU_COMPHY_DFE_RES_FORCE_GEN_TBL	BIT(15)48#define MVEBU_COMPHY_COEF(n)			(0x828 + (n) * 0x1000)49#define     MVEBU_COMPHY_COEF_DFE_EN		BIT(14)50#define     MVEBU_COMPHY_COEF_DFE_CTRL		BIT(15)51#define MVEBU_COMPHY_GEN1_S0(n)			(0x834 + (n) * 0x1000)52#define     MVEBU_COMPHY_GEN1_S0_TX_AMP(n)	((n) << 1)53#define     MVEBU_COMPHY_GEN1_S0_TX_EMPH(n)	((n) << 7)54#define MVEBU_COMPHY_GEN1_S1(n)			(0x838 + (n) * 0x1000)55#define     MVEBU_COMPHY_GEN1_S1_RX_MUL_PI(n)	((n) << 0)56#define     MVEBU_COMPHY_GEN1_S1_RX_MUL_PF(n)	((n) << 3)57#define     MVEBU_COMPHY_GEN1_S1_RX_MUL_FI(n)	((n) << 6)58#define     MVEBU_COMPHY_GEN1_S1_RX_MUL_FF(n)	((n) << 8)59#define     MVEBU_COMPHY_GEN1_S1_RX_DFE_EN	BIT(10)60#define     MVEBU_COMPHY_GEN1_S1_RX_DIV(n)	((n) << 11)61#define MVEBU_COMPHY_GEN1_S2(n)			(0x8f4 + (n) * 0x1000)62#define     MVEBU_COMPHY_GEN1_S2_TX_EMPH(n)	((n) << 0)63#define     MVEBU_COMPHY_GEN1_S2_TX_EMPH_EN	BIT(4)64#define MVEBU_COMPHY_LOOPBACK(n)		(0x88c + (n) * 0x1000)65#define     MVEBU_COMPHY_LOOPBACK_DBUS_WIDTH(n)	((n) << 1)66#define MVEBU_COMPHY_VDD_CAL0(n)		(0x908 + (n) * 0x1000)67#define     MVEBU_COMPHY_VDD_CAL0_CONT_MODE	BIT(15)68#define MVEBU_COMPHY_EXT_SELV(n)		(0x914 + (n) * 0x1000)69#define     MVEBU_COMPHY_EXT_SELV_RX_SAMPL(n)	((n) << 5)70#define MVEBU_COMPHY_MISC_CTRL0(n)		(0x93c + (n) * 0x1000)71#define     MVEBU_COMPHY_MISC_CTRL0_ICP_FORCE	BIT(5)72#define     MVEBU_COMPHY_MISC_CTRL0_REFCLK_SEL	BIT(10)73#define MVEBU_COMPHY_RX_CTRL1(n)		(0x940 + (n) * 0x1000)74#define     MVEBU_COMPHY_RX_CTRL1_RXCLK2X_SEL	BIT(11)75#define     MVEBU_COMPHY_RX_CTRL1_CLK8T_EN	BIT(12)76#define MVEBU_COMPHY_SPEED_DIV(n)		(0x954 + (n) * 0x1000)77#define     MVEBU_COMPHY_SPEED_DIV_TX_FORCE	BIT(7)78#define MVEBU_SP_CALIB(n)			(0x96c + (n) * 0x1000)79#define     MVEBU_SP_CALIB_SAMPLER(n)		((n) << 8)80#define     MVEBU_SP_CALIB_SAMPLER_EN		BIT(12)81#define MVEBU_COMPHY_TX_SLEW_RATE(n)		(0x974 + (n) * 0x1000)82#define     MVEBU_COMPHY_TX_SLEW_RATE_EMPH(n)	((n) << 5)83#define     MVEBU_COMPHY_TX_SLEW_RATE_SLC(n)	((n) << 10)84#define MVEBU_COMPHY_DTL_CTRL(n)		(0x984 + (n) * 0x1000)85#define     MVEBU_COMPHY_DTL_CTRL_DTL_FLOOP_EN	BIT(2)86#define MVEBU_COMPHY_FRAME_DETECT0(n)		(0xa14 + (n) * 0x1000)87#define     MVEBU_COMPHY_FRAME_DETECT0_PATN(n)	((n) << 7)88#define MVEBU_COMPHY_FRAME_DETECT3(n)		(0xa20 + (n) * 0x1000)89#define     MVEBU_COMPHY_FRAME_DETECT3_LOST_TIMEOUT_EN	BIT(12)90#define MVEBU_COMPHY_DME(n)			(0xa28 + (n) * 0x1000)91#define     MVEBU_COMPHY_DME_ETH_MODE		BIT(7)92#define MVEBU_COMPHY_TRAINING0(n)		(0xa68 + (n) * 0x1000)93#define     MVEBU_COMPHY_TRAINING0_P2P_HOLD	BIT(15)94#define MVEBU_COMPHY_TRAINING5(n)		(0xaa4 + (n) * 0x1000)95#define	    MVEBU_COMPHY_TRAINING5_RX_TIMER(n)	((n) << 0)96#define MVEBU_COMPHY_TX_TRAIN_PRESET(n)		(0xb1c + (n) * 0x1000)97#define     MVEBU_COMPHY_TX_TRAIN_PRESET_16B_AUTO_EN	BIT(8)98#define     MVEBU_COMPHY_TX_TRAIN_PRESET_PRBS11		BIT(9)99#define MVEBU_COMPHY_GEN1_S3(n)			(0xc40 + (n) * 0x1000)100#define     MVEBU_COMPHY_GEN1_S3_FBCK_SEL	BIT(9)101#define MVEBU_COMPHY_GEN1_S4(n)			(0xc44 + (n) * 0x1000)102#define	    MVEBU_COMPHY_GEN1_S4_DFE_RES(n)	((n) << 8)103#define MVEBU_COMPHY_TX_PRESET(n)		(0xc68 + (n) * 0x1000)104#define     MVEBU_COMPHY_TX_PRESET_INDEX(n)	((n) << 0)105#define MVEBU_COMPHY_GEN1_S5(n)			(0xd38 + (n) * 0x1000)106#define     MVEBU_COMPHY_GEN1_S5_ICP(n)		((n) << 0)107 108/* Relative to priv->regmap */109#define MVEBU_COMPHY_CONF1(n)			(0x1000 + (n) * 0x28)110#define     MVEBU_COMPHY_CONF1_PWRUP		BIT(1)111#define     MVEBU_COMPHY_CONF1_USB_PCIE		BIT(2)	/* 0: Ethernet/SATA */112#define MVEBU_COMPHY_CONF6(n)			(0x1014 + (n) * 0x28)113#define     MVEBU_COMPHY_CONF6_40B		BIT(18)114#define MVEBU_COMPHY_SELECTOR			0x1140115#define     MVEBU_COMPHY_SELECTOR_PHY(n)	((n) * 0x4)116#define MVEBU_COMPHY_PIPE_SELECTOR		0x1144117#define     MVEBU_COMPHY_PIPE_SELECTOR_PIPE(n)	((n) * 0x4)118#define MVEBU_COMPHY_SD1_CTRL1			0x1148119#define     MVEBU_COMPHY_SD1_CTRL1_RXAUI1_EN	BIT(26)120#define     MVEBU_COMPHY_SD1_CTRL1_RXAUI0_EN	BIT(27)121 122#define MVEBU_COMPHY_LANES	6123#define MVEBU_COMPHY_PORTS	3124 125#define COMPHY_SIP_POWER_ON	0x82000001126#define COMPHY_SIP_POWER_OFF	0x82000002127 128/*129 * A lane is described by the following bitfields:130 * [ 1- 0]: COMPHY polarity invertion131 * [ 2- 7]: COMPHY speed132 * [ 5-11]: COMPHY port index133 * [12-16]: COMPHY mode134 * [17]: Clock source135 * [18-20]: PCIe width (x1, x2, x4)136 */137#define COMPHY_FW_POL_OFFSET	0138#define COMPHY_FW_POL_MASK	GENMASK(1, 0)139#define COMPHY_FW_SPEED_OFFSET	2140#define COMPHY_FW_SPEED_MASK	GENMASK(7, 2)141#define COMPHY_FW_SPEED_MAX	COMPHY_FW_SPEED_MASK142#define COMPHY_FW_SPEED_1250	0143#define COMPHY_FW_SPEED_3125	2144#define COMPHY_FW_SPEED_5000	3145#define COMPHY_FW_SPEED_515625	4146#define COMPHY_FW_SPEED_103125	6147#define COMPHY_FW_PORT_OFFSET	8148#define COMPHY_FW_PORT_MASK	GENMASK(11, 8)149#define COMPHY_FW_MODE_OFFSET	12150#define COMPHY_FW_MODE_MASK	GENMASK(16, 12)151#define COMPHY_FW_WIDTH_OFFSET	18152#define COMPHY_FW_WIDTH_MASK	GENMASK(20, 18)153 154#define COMPHY_FW_PARAM_FULL(mode, port, speed, pol, width)		\155	((((pol) << COMPHY_FW_POL_OFFSET) & COMPHY_FW_POL_MASK) |	\156	 (((mode) << COMPHY_FW_MODE_OFFSET) & COMPHY_FW_MODE_MASK) |	\157	 (((port) << COMPHY_FW_PORT_OFFSET) & COMPHY_FW_PORT_MASK) |	\158	 (((speed) << COMPHY_FW_SPEED_OFFSET) & COMPHY_FW_SPEED_MASK) |	\159	 (((width) << COMPHY_FW_WIDTH_OFFSET) & COMPHY_FW_WIDTH_MASK))160 161#define COMPHY_FW_PARAM(mode, port)					\162	COMPHY_FW_PARAM_FULL(mode, port, COMPHY_FW_SPEED_MAX, 0, 0)163 164#define COMPHY_FW_PARAM_ETH(mode, port, speed)				\165	COMPHY_FW_PARAM_FULL(mode, port, speed, 0, 0)166 167#define COMPHY_FW_PARAM_PCIE(mode, port, width)				\168	COMPHY_FW_PARAM_FULL(mode, port, COMPHY_FW_SPEED_5000, 0, width)169 170#define COMPHY_FW_MODE_SATA		0x1171#define COMPHY_FW_MODE_SGMII		0x2 /* SGMII 1G */172#define COMPHY_FW_MODE_2500BASEX	0x3 /* 2500BASE-X */173#define COMPHY_FW_MODE_USB3H		0x4174#define COMPHY_FW_MODE_USB3D		0x5175#define COMPHY_FW_MODE_PCIE		0x6176#define COMPHY_FW_MODE_RXAUI		0x7177#define COMPHY_FW_MODE_XFI		0x8 /* SFI: 0x9 (is treated like XFI) */178 179struct mvebu_comphy_conf {180	enum phy_mode mode;181	int submode;182	unsigned lane;183	unsigned port;184	u32 mux;185	u32 fw_mode;186};187 188#define ETH_CONF(_lane, _port, _submode, _mux, _fw)	\189	{						\190		.lane = _lane,				\191		.port = _port,				\192		.mode = PHY_MODE_ETHERNET,		\193		.submode = _submode,			\194		.mux = _mux,				\195		.fw_mode = _fw,				\196	}197 198#define GEN_CONF(_lane, _port, _mode, _fw)		\199	{						\200		.lane = _lane,				\201		.port = _port,				\202		.mode = _mode,				\203		.submode = PHY_INTERFACE_MODE_NA,	\204		.mux = -1,				\205		.fw_mode = _fw,				\206	}207 208static const struct mvebu_comphy_conf mvebu_comphy_cp110_modes[] = {209	/* lane 0 */210	GEN_CONF(0, 0, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE),211	ETH_CONF(0, 1, PHY_INTERFACE_MODE_SGMII, 0x1, COMPHY_FW_MODE_SGMII),212	ETH_CONF(0, 1, PHY_INTERFACE_MODE_2500BASEX, 0x1, COMPHY_FW_MODE_2500BASEX),213	GEN_CONF(0, 1, PHY_MODE_SATA, COMPHY_FW_MODE_SATA),214	/* lane 1 */215	GEN_CONF(1, 0, PHY_MODE_USB_HOST_SS, COMPHY_FW_MODE_USB3H),216	GEN_CONF(1, 0, PHY_MODE_USB_DEVICE_SS, COMPHY_FW_MODE_USB3D),217	GEN_CONF(1, 0, PHY_MODE_SATA, COMPHY_FW_MODE_SATA),218	GEN_CONF(1, 0, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE),219	ETH_CONF(1, 2, PHY_INTERFACE_MODE_SGMII, 0x1, COMPHY_FW_MODE_SGMII),220	ETH_CONF(1, 2, PHY_INTERFACE_MODE_2500BASEX, 0x1, COMPHY_FW_MODE_2500BASEX),221	/* lane 2 */222	ETH_CONF(2, 0, PHY_INTERFACE_MODE_SGMII, 0x1, COMPHY_FW_MODE_SGMII),223	ETH_CONF(2, 0, PHY_INTERFACE_MODE_2500BASEX, 0x1, COMPHY_FW_MODE_2500BASEX),224	ETH_CONF(2, 0, PHY_INTERFACE_MODE_RXAUI, 0x1, COMPHY_FW_MODE_RXAUI),225	ETH_CONF(2, 0, PHY_INTERFACE_MODE_5GBASER, 0x1, COMPHY_FW_MODE_XFI),226	ETH_CONF(2, 0, PHY_INTERFACE_MODE_10GBASER, 0x1, COMPHY_FW_MODE_XFI),227	GEN_CONF(2, 0, PHY_MODE_USB_HOST_SS, COMPHY_FW_MODE_USB3H),228	GEN_CONF(2, 0, PHY_MODE_SATA, COMPHY_FW_MODE_SATA),229	GEN_CONF(2, 0, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE),230	/* lane 3 */231	GEN_CONF(3, 0, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE),232	ETH_CONF(3, 1, PHY_INTERFACE_MODE_SGMII, 0x2, COMPHY_FW_MODE_SGMII),233	ETH_CONF(3, 1, PHY_INTERFACE_MODE_2500BASEX, 0x2, COMPHY_FW_MODE_2500BASEX),234	ETH_CONF(3, 1, PHY_INTERFACE_MODE_RXAUI, 0x1, COMPHY_FW_MODE_RXAUI),235	GEN_CONF(3, 1, PHY_MODE_USB_HOST_SS, COMPHY_FW_MODE_USB3H),236	GEN_CONF(3, 1, PHY_MODE_SATA, COMPHY_FW_MODE_SATA),237	/* lane 4 */238	ETH_CONF(4, 0, PHY_INTERFACE_MODE_SGMII, 0x2, COMPHY_FW_MODE_SGMII),239	ETH_CONF(4, 0, PHY_INTERFACE_MODE_2500BASEX, 0x2, COMPHY_FW_MODE_2500BASEX),240	ETH_CONF(4, 0, PHY_INTERFACE_MODE_5GBASER, 0x2, COMPHY_FW_MODE_XFI),241	ETH_CONF(4, 0, PHY_INTERFACE_MODE_10GBASER, 0x2, COMPHY_FW_MODE_XFI),242	ETH_CONF(4, 0, PHY_INTERFACE_MODE_RXAUI, 0x2, COMPHY_FW_MODE_RXAUI),243	GEN_CONF(4, 0, PHY_MODE_USB_DEVICE_SS, COMPHY_FW_MODE_USB3D),244	GEN_CONF(4, 1, PHY_MODE_USB_HOST_SS, COMPHY_FW_MODE_USB3H),245	GEN_CONF(4, 1, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE),246	ETH_CONF(4, 1, PHY_INTERFACE_MODE_SGMII, 0x1, COMPHY_FW_MODE_SGMII),247	ETH_CONF(4, 1, PHY_INTERFACE_MODE_2500BASEX, 0x1, COMPHY_FW_MODE_2500BASEX),248	ETH_CONF(4, 1, PHY_INTERFACE_MODE_5GBASER, 0x1, COMPHY_FW_MODE_XFI),249	ETH_CONF(4, 1, PHY_INTERFACE_MODE_10GBASER, -1, COMPHY_FW_MODE_XFI),250	/* lane 5 */251	ETH_CONF(5, 1, PHY_INTERFACE_MODE_RXAUI, 0x2, COMPHY_FW_MODE_RXAUI),252	GEN_CONF(5, 1, PHY_MODE_SATA, COMPHY_FW_MODE_SATA),253	ETH_CONF(5, 2, PHY_INTERFACE_MODE_SGMII, 0x1, COMPHY_FW_MODE_SGMII),254	ETH_CONF(5, 2, PHY_INTERFACE_MODE_2500BASEX, 0x1, COMPHY_FW_MODE_2500BASEX),255	GEN_CONF(5, 2, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE),256};257 258struct mvebu_comphy_priv {259	void __iomem *base;260	struct regmap *regmap;261	struct device *dev;262	struct clk *mg_domain_clk;263	struct clk *mg_core_clk;264	struct clk *axi_clk;265	unsigned long cp_phys;266};267 268struct mvebu_comphy_lane {269	struct mvebu_comphy_priv *priv;270	unsigned id;271	enum phy_mode mode;272	int submode;273	int port;274};275 276static int mvebu_comphy_smc(unsigned long function, unsigned long phys,277			    unsigned long lane, unsigned long mode)278{279	struct arm_smccc_res res;280	s32 ret;281 282	arm_smccc_smc(function, phys, lane, mode, 0, 0, 0, 0, &res);283	ret = res.a0;284 285	switch (ret) {286	case SMCCC_RET_SUCCESS:287		return 0;288	case SMCCC_RET_NOT_SUPPORTED:289		return -EOPNOTSUPP;290	default:291		return -EINVAL;292	}293}294 295static int mvebu_comphy_get_mode(bool fw_mode, int lane, int port,296				 enum phy_mode mode, int submode)297{298	int i, n = ARRAY_SIZE(mvebu_comphy_cp110_modes);299	/* Ignore PCIe submode: it represents the width */300	bool ignore_submode = (mode == PHY_MODE_PCIE);301	const struct mvebu_comphy_conf *conf;302 303	/* Unused PHY mux value is 0x0 */304	if (mode == PHY_MODE_INVALID)305		return 0;306 307	for (i = 0; i < n; i++) {308		conf = &mvebu_comphy_cp110_modes[i];309		if (conf->lane == lane &&310		    conf->port == port &&311		    conf->mode == mode &&312		    (conf->submode == submode || ignore_submode))313			break;314	}315 316	if (i == n)317		return -EINVAL;318 319	if (fw_mode)320		return conf->fw_mode;321	else322		return conf->mux;323}324 325static inline int mvebu_comphy_get_mux(int lane, int port,326				       enum phy_mode mode, int submode)327{328	return mvebu_comphy_get_mode(false, lane, port, mode, submode);329}330 331static inline int mvebu_comphy_get_fw_mode(int lane, int port,332					   enum phy_mode mode, int submode)333{334	return mvebu_comphy_get_mode(true, lane, port, mode, submode);335}336 337static int mvebu_comphy_ethernet_init_reset(struct mvebu_comphy_lane *lane)338{339	struct mvebu_comphy_priv *priv = lane->priv;340	u32 val;341 342	regmap_read(priv->regmap, MVEBU_COMPHY_CONF1(lane->id), &val);343	val &= ~MVEBU_COMPHY_CONF1_USB_PCIE;344	val |= MVEBU_COMPHY_CONF1_PWRUP;345	regmap_write(priv->regmap, MVEBU_COMPHY_CONF1(lane->id), val);346 347	/* Select baud rates and PLLs */348	val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG0(lane->id));349	val &= ~(MVEBU_COMPHY_SERDES_CFG0_PU_PLL |350		 MVEBU_COMPHY_SERDES_CFG0_PU_RX |351		 MVEBU_COMPHY_SERDES_CFG0_PU_TX |352		 MVEBU_COMPHY_SERDES_CFG0_HALF_BUS |353		 MVEBU_COMPHY_SERDES_CFG0_GEN_RX(0xf) |354		 MVEBU_COMPHY_SERDES_CFG0_GEN_TX(0xf) |355		 MVEBU_COMPHY_SERDES_CFG0_RXAUI_MODE);356 357	switch (lane->submode) {358	case PHY_INTERFACE_MODE_10GBASER:359		val |= MVEBU_COMPHY_SERDES_CFG0_GEN_RX(0xe) |360		       MVEBU_COMPHY_SERDES_CFG0_GEN_TX(0xe);361		break;362	case PHY_INTERFACE_MODE_RXAUI:363		val |= MVEBU_COMPHY_SERDES_CFG0_GEN_RX(0xb) |364		       MVEBU_COMPHY_SERDES_CFG0_GEN_TX(0xb) |365		       MVEBU_COMPHY_SERDES_CFG0_RXAUI_MODE;366		break;367	case PHY_INTERFACE_MODE_2500BASEX:368		val |= MVEBU_COMPHY_SERDES_CFG0_GEN_RX(0x8) |369		       MVEBU_COMPHY_SERDES_CFG0_GEN_TX(0x8) |370		       MVEBU_COMPHY_SERDES_CFG0_HALF_BUS;371		break;372	case PHY_INTERFACE_MODE_SGMII:373		val |= MVEBU_COMPHY_SERDES_CFG0_GEN_RX(0x6) |374		       MVEBU_COMPHY_SERDES_CFG0_GEN_TX(0x6) |375		       MVEBU_COMPHY_SERDES_CFG0_HALF_BUS;376		break;377	default:378		dev_err(priv->dev,379			"unsupported comphy submode (%d) on lane %d\n",380			lane->submode,381			lane->id);382		return -ENOTSUPP;383	}384 385	writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG0(lane->id));386 387	if (lane->submode == PHY_INTERFACE_MODE_RXAUI) {388		regmap_read(priv->regmap, MVEBU_COMPHY_SD1_CTRL1, &val);389 390		switch (lane->id) {391		case 2:392		case 3:393			val |= MVEBU_COMPHY_SD1_CTRL1_RXAUI0_EN;394			break;395		case 4:396		case 5:397			val |= MVEBU_COMPHY_SD1_CTRL1_RXAUI1_EN;398			break;399		default:400			dev_err(priv->dev,401				"RXAUI is not supported on comphy lane %d\n",402				lane->id);403			return -EINVAL;404		}405 406		regmap_write(priv->regmap, MVEBU_COMPHY_SD1_CTRL1, val);407	}408 409	/* reset */410	val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));411	val &= ~(MVEBU_COMPHY_SERDES_CFG1_RESET |412		 MVEBU_COMPHY_SERDES_CFG1_CORE_RESET |413		 MVEBU_COMPHY_SERDES_CFG1_RF_RESET);414	writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));415 416	/* de-assert reset */417	val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));418	val |= MVEBU_COMPHY_SERDES_CFG1_RESET |419	       MVEBU_COMPHY_SERDES_CFG1_CORE_RESET;420	writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));421 422	/* wait until clocks are ready */423	mdelay(1);424 425	/* exlicitly disable 40B, the bits isn't clear on reset */426	regmap_read(priv->regmap, MVEBU_COMPHY_CONF6(lane->id), &val);427	val &= ~MVEBU_COMPHY_CONF6_40B;428	regmap_write(priv->regmap, MVEBU_COMPHY_CONF6(lane->id), val);429 430	/* refclk selection */431	val = readl(priv->base + MVEBU_COMPHY_MISC_CTRL0(lane->id));432	val &= ~MVEBU_COMPHY_MISC_CTRL0_REFCLK_SEL;433	if (lane->submode == PHY_INTERFACE_MODE_10GBASER)434		val |= MVEBU_COMPHY_MISC_CTRL0_ICP_FORCE;435	writel(val, priv->base + MVEBU_COMPHY_MISC_CTRL0(lane->id));436 437	/* power and pll selection */438	val = readl(priv->base + MVEBU_COMPHY_PWRPLL_CTRL(lane->id));439	val &= ~(MVEBU_COMPHY_PWRPLL_CTRL_RFREQ(0x1f) |440		 MVEBU_COMPHY_PWRPLL_PHY_MODE(0x7));441	val |= MVEBU_COMPHY_PWRPLL_CTRL_RFREQ(0x1) |442	       MVEBU_COMPHY_PWRPLL_PHY_MODE(0x4);443	writel(val, priv->base + MVEBU_COMPHY_PWRPLL_CTRL(lane->id));444 445	val = readl(priv->base + MVEBU_COMPHY_LOOPBACK(lane->id));446	val &= ~MVEBU_COMPHY_LOOPBACK_DBUS_WIDTH(0x7);447	val |= MVEBU_COMPHY_LOOPBACK_DBUS_WIDTH(0x1);448	writel(val, priv->base + MVEBU_COMPHY_LOOPBACK(lane->id));449 450	return 0;451}452 453static int mvebu_comphy_init_plls(struct mvebu_comphy_lane *lane)454{455	struct mvebu_comphy_priv *priv = lane->priv;456	u32 val;457 458	/* SERDES external config */459	val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG0(lane->id));460	val |= MVEBU_COMPHY_SERDES_CFG0_PU_PLL |461	       MVEBU_COMPHY_SERDES_CFG0_PU_RX |462	       MVEBU_COMPHY_SERDES_CFG0_PU_TX;463	writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG0(lane->id));464 465	/* check rx/tx pll */466	readl_poll_timeout(priv->base + MVEBU_COMPHY_SERDES_STATUS0(lane->id),467			   val,468			   val & (MVEBU_COMPHY_SERDES_STATUS0_RX_PLL_RDY |469				  MVEBU_COMPHY_SERDES_STATUS0_TX_PLL_RDY),470			   1000, 150000);471	if (!(val & (MVEBU_COMPHY_SERDES_STATUS0_RX_PLL_RDY |472		     MVEBU_COMPHY_SERDES_STATUS0_TX_PLL_RDY)))473		return -ETIMEDOUT;474 475	/* rx init */476	val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));477	val |= MVEBU_COMPHY_SERDES_CFG1_RX_INIT;478	writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));479 480	/* check rx */481	readl_poll_timeout(priv->base + MVEBU_COMPHY_SERDES_STATUS0(lane->id),482			   val, val & MVEBU_COMPHY_SERDES_STATUS0_RX_INIT,483			   1000, 10000);484	if (!(val & MVEBU_COMPHY_SERDES_STATUS0_RX_INIT))485		return -ETIMEDOUT;486 487	val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));488	val &= ~MVEBU_COMPHY_SERDES_CFG1_RX_INIT;489	writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));490 491	return 0;492}493 494static int mvebu_comphy_set_mode_sgmii(struct phy *phy)495{496	struct mvebu_comphy_lane *lane = phy_get_drvdata(phy);497	struct mvebu_comphy_priv *priv = lane->priv;498	u32 val;499	int err;500 501	err = mvebu_comphy_ethernet_init_reset(lane);502	if (err)503		return err;504 505	val = readl(priv->base + MVEBU_COMPHY_RX_CTRL1(lane->id));506	val &= ~MVEBU_COMPHY_RX_CTRL1_CLK8T_EN;507	val |= MVEBU_COMPHY_RX_CTRL1_RXCLK2X_SEL;508	writel(val, priv->base + MVEBU_COMPHY_RX_CTRL1(lane->id));509 510	val = readl(priv->base + MVEBU_COMPHY_DTL_CTRL(lane->id));511	val &= ~MVEBU_COMPHY_DTL_CTRL_DTL_FLOOP_EN;512	writel(val, priv->base + MVEBU_COMPHY_DTL_CTRL(lane->id));513 514	regmap_read(priv->regmap, MVEBU_COMPHY_CONF1(lane->id), &val);515	val &= ~MVEBU_COMPHY_CONF1_USB_PCIE;516	val |= MVEBU_COMPHY_CONF1_PWRUP;517	regmap_write(priv->regmap, MVEBU_COMPHY_CONF1(lane->id), val);518 519	val = readl(priv->base + MVEBU_COMPHY_GEN1_S0(lane->id));520	val &= ~MVEBU_COMPHY_GEN1_S0_TX_EMPH(0xf);521	val |= MVEBU_COMPHY_GEN1_S0_TX_EMPH(0x1);522	writel(val, priv->base + MVEBU_COMPHY_GEN1_S0(lane->id));523 524	return mvebu_comphy_init_plls(lane);525}526 527static int mvebu_comphy_set_mode_rxaui(struct phy *phy)528{529	struct mvebu_comphy_lane *lane = phy_get_drvdata(phy);530	struct mvebu_comphy_priv *priv = lane->priv;531	u32 val;532	int err;533 534	err = mvebu_comphy_ethernet_init_reset(lane);535	if (err)536		return err;537 538	val = readl(priv->base + MVEBU_COMPHY_RX_CTRL1(lane->id));539	val |= MVEBU_COMPHY_RX_CTRL1_RXCLK2X_SEL |540	       MVEBU_COMPHY_RX_CTRL1_CLK8T_EN;541	writel(val, priv->base + MVEBU_COMPHY_RX_CTRL1(lane->id));542 543	val = readl(priv->base + MVEBU_COMPHY_DTL_CTRL(lane->id));544	val |= MVEBU_COMPHY_DTL_CTRL_DTL_FLOOP_EN;545	writel(val, priv->base + MVEBU_COMPHY_DTL_CTRL(lane->id));546 547	val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG2(lane->id));548	val |= MVEBU_COMPHY_SERDES_CFG2_DFE_EN;549	writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG2(lane->id));550 551	val = readl(priv->base + MVEBU_COMPHY_DFE_RES(lane->id));552	val |= MVEBU_COMPHY_DFE_RES_FORCE_GEN_TBL;553	writel(val, priv->base + MVEBU_COMPHY_DFE_RES(lane->id));554 555	val = readl(priv->base + MVEBU_COMPHY_GEN1_S0(lane->id));556	val &= ~MVEBU_COMPHY_GEN1_S0_TX_EMPH(0xf);557	val |= MVEBU_COMPHY_GEN1_S0_TX_EMPH(0xd);558	writel(val, priv->base + MVEBU_COMPHY_GEN1_S0(lane->id));559 560	val = readl(priv->base + MVEBU_COMPHY_GEN1_S1(lane->id));561	val &= ~(MVEBU_COMPHY_GEN1_S1_RX_MUL_PI(0x7) |562		 MVEBU_COMPHY_GEN1_S1_RX_MUL_PF(0x7));563	val |= MVEBU_COMPHY_GEN1_S1_RX_MUL_PI(0x1) |564	       MVEBU_COMPHY_GEN1_S1_RX_MUL_PF(0x1) |565	       MVEBU_COMPHY_GEN1_S1_RX_DFE_EN;566	writel(val, priv->base + MVEBU_COMPHY_GEN1_S1(lane->id));567 568	val = readl(priv->base + MVEBU_COMPHY_COEF(lane->id));569	val &= ~(MVEBU_COMPHY_COEF_DFE_EN | MVEBU_COMPHY_COEF_DFE_CTRL);570	writel(val, priv->base + MVEBU_COMPHY_COEF(lane->id));571 572	val = readl(priv->base + MVEBU_COMPHY_GEN1_S4(lane->id));573	val &= ~MVEBU_COMPHY_GEN1_S4_DFE_RES(0x3);574	val |= MVEBU_COMPHY_GEN1_S4_DFE_RES(0x1);575	writel(val, priv->base + MVEBU_COMPHY_GEN1_S4(lane->id));576 577	return mvebu_comphy_init_plls(lane);578}579 580static int mvebu_comphy_set_mode_10gbaser(struct phy *phy)581{582	struct mvebu_comphy_lane *lane = phy_get_drvdata(phy);583	struct mvebu_comphy_priv *priv = lane->priv;584	u32 val;585	int err;586 587	err = mvebu_comphy_ethernet_init_reset(lane);588	if (err)589		return err;590 591	val = readl(priv->base + MVEBU_COMPHY_RX_CTRL1(lane->id));592	val |= MVEBU_COMPHY_RX_CTRL1_RXCLK2X_SEL |593	       MVEBU_COMPHY_RX_CTRL1_CLK8T_EN;594	writel(val, priv->base + MVEBU_COMPHY_RX_CTRL1(lane->id));595 596	val = readl(priv->base + MVEBU_COMPHY_DTL_CTRL(lane->id));597	val |= MVEBU_COMPHY_DTL_CTRL_DTL_FLOOP_EN;598	writel(val, priv->base + MVEBU_COMPHY_DTL_CTRL(lane->id));599 600	/* Speed divider */601	val = readl(priv->base + MVEBU_COMPHY_SPEED_DIV(lane->id));602	val |= MVEBU_COMPHY_SPEED_DIV_TX_FORCE;603	writel(val, priv->base + MVEBU_COMPHY_SPEED_DIV(lane->id));604 605	val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG2(lane->id));606	val |= MVEBU_COMPHY_SERDES_CFG2_DFE_EN;607	writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG2(lane->id));608 609	/* DFE resolution */610	val = readl(priv->base + MVEBU_COMPHY_DFE_RES(lane->id));611	val |= MVEBU_COMPHY_DFE_RES_FORCE_GEN_TBL;612	writel(val, priv->base + MVEBU_COMPHY_DFE_RES(lane->id));613 614	val = readl(priv->base + MVEBU_COMPHY_GEN1_S0(lane->id));615	val &= ~(MVEBU_COMPHY_GEN1_S0_TX_AMP(0x1f) |616		 MVEBU_COMPHY_GEN1_S0_TX_EMPH(0xf));617	val |= MVEBU_COMPHY_GEN1_S0_TX_AMP(0x1c) |618	       MVEBU_COMPHY_GEN1_S0_TX_EMPH(0xe);619	writel(val, priv->base + MVEBU_COMPHY_GEN1_S0(lane->id));620 621	val = readl(priv->base + MVEBU_COMPHY_GEN1_S2(lane->id));622	val &= ~MVEBU_COMPHY_GEN1_S2_TX_EMPH(0xf);623	val |= MVEBU_COMPHY_GEN1_S2_TX_EMPH_EN;624	writel(val, priv->base + MVEBU_COMPHY_GEN1_S2(lane->id));625 626	val = readl(priv->base + MVEBU_COMPHY_TX_SLEW_RATE(lane->id));627	val |= MVEBU_COMPHY_TX_SLEW_RATE_EMPH(0x3) |628	       MVEBU_COMPHY_TX_SLEW_RATE_SLC(0x3f);629	writel(val, priv->base + MVEBU_COMPHY_TX_SLEW_RATE(lane->id));630 631	/* Impedance calibration */632	val = readl(priv->base + MVEBU_COMPHY_IMP_CAL(lane->id));633	val &= ~MVEBU_COMPHY_IMP_CAL_TX_EXT(0x1f);634	val |= MVEBU_COMPHY_IMP_CAL_TX_EXT(0xe) |635	       MVEBU_COMPHY_IMP_CAL_TX_EXT_EN;636	writel(val, priv->base + MVEBU_COMPHY_IMP_CAL(lane->id));637 638	val = readl(priv->base + MVEBU_COMPHY_GEN1_S5(lane->id));639	val &= ~MVEBU_COMPHY_GEN1_S5_ICP(0xf);640	writel(val, priv->base + MVEBU_COMPHY_GEN1_S5(lane->id));641 642	val = readl(priv->base + MVEBU_COMPHY_GEN1_S1(lane->id));643	val &= ~(MVEBU_COMPHY_GEN1_S1_RX_MUL_PI(0x7) |644		 MVEBU_COMPHY_GEN1_S1_RX_MUL_PF(0x7) |645		 MVEBU_COMPHY_GEN1_S1_RX_MUL_FI(0x3) |646		 MVEBU_COMPHY_GEN1_S1_RX_MUL_FF(0x3));647	val |= MVEBU_COMPHY_GEN1_S1_RX_DFE_EN |648	       MVEBU_COMPHY_GEN1_S1_RX_MUL_PI(0x2) |649	       MVEBU_COMPHY_GEN1_S1_RX_MUL_PF(0x2) |650	       MVEBU_COMPHY_GEN1_S1_RX_MUL_FF(0x1) |651	       MVEBU_COMPHY_GEN1_S1_RX_DIV(0x3);652	writel(val, priv->base + MVEBU_COMPHY_GEN1_S1(lane->id));653 654	val = readl(priv->base + MVEBU_COMPHY_COEF(lane->id));655	val &= ~(MVEBU_COMPHY_COEF_DFE_EN | MVEBU_COMPHY_COEF_DFE_CTRL);656	writel(val, priv->base + MVEBU_COMPHY_COEF(lane->id));657 658	val = readl(priv->base + MVEBU_COMPHY_GEN1_S4(lane->id));659	val &= ~MVEBU_COMPHY_GEN1_S4_DFE_RES(0x3);660	val |= MVEBU_COMPHY_GEN1_S4_DFE_RES(0x1);661	writel(val, priv->base + MVEBU_COMPHY_GEN1_S4(lane->id));662 663	val = readl(priv->base + MVEBU_COMPHY_GEN1_S3(lane->id));664	val |= MVEBU_COMPHY_GEN1_S3_FBCK_SEL;665	writel(val, priv->base + MVEBU_COMPHY_GEN1_S3(lane->id));666 667	/* rx training timer */668	val = readl(priv->base + MVEBU_COMPHY_TRAINING5(lane->id));669	val &= ~MVEBU_COMPHY_TRAINING5_RX_TIMER(0x3ff);670	val |= MVEBU_COMPHY_TRAINING5_RX_TIMER(0x13);671	writel(val, priv->base + MVEBU_COMPHY_TRAINING5(lane->id));672 673	/* tx train peak to peak hold */674	val = readl(priv->base + MVEBU_COMPHY_TRAINING0(lane->id));675	val |= MVEBU_COMPHY_TRAINING0_P2P_HOLD;676	writel(val, priv->base + MVEBU_COMPHY_TRAINING0(lane->id));677 678	val = readl(priv->base + MVEBU_COMPHY_TX_PRESET(lane->id));679	val &= ~MVEBU_COMPHY_TX_PRESET_INDEX(0xf);680	val |= MVEBU_COMPHY_TX_PRESET_INDEX(0x2);	/* preset coeff */681	writel(val, priv->base + MVEBU_COMPHY_TX_PRESET(lane->id));682 683	val = readl(priv->base + MVEBU_COMPHY_FRAME_DETECT3(lane->id));684	val &= ~MVEBU_COMPHY_FRAME_DETECT3_LOST_TIMEOUT_EN;685	writel(val, priv->base + MVEBU_COMPHY_FRAME_DETECT3(lane->id));686 687	val = readl(priv->base + MVEBU_COMPHY_TX_TRAIN_PRESET(lane->id));688	val |= MVEBU_COMPHY_TX_TRAIN_PRESET_16B_AUTO_EN |689	       MVEBU_COMPHY_TX_TRAIN_PRESET_PRBS11;690	writel(val, priv->base + MVEBU_COMPHY_TX_TRAIN_PRESET(lane->id));691 692	val = readl(priv->base + MVEBU_COMPHY_FRAME_DETECT0(lane->id));693	val &= ~MVEBU_COMPHY_FRAME_DETECT0_PATN(0x1ff);694	val |= MVEBU_COMPHY_FRAME_DETECT0_PATN(0x88);695	writel(val, priv->base + MVEBU_COMPHY_FRAME_DETECT0(lane->id));696 697	val = readl(priv->base + MVEBU_COMPHY_DME(lane->id));698	val |= MVEBU_COMPHY_DME_ETH_MODE;699	writel(val, priv->base + MVEBU_COMPHY_DME(lane->id));700 701	val = readl(priv->base + MVEBU_COMPHY_VDD_CAL0(lane->id));702	val |= MVEBU_COMPHY_VDD_CAL0_CONT_MODE;703	writel(val, priv->base + MVEBU_COMPHY_VDD_CAL0(lane->id));704 705	val = readl(priv->base + MVEBU_SP_CALIB(lane->id));706	val &= ~MVEBU_SP_CALIB_SAMPLER(0x3);707	val |= MVEBU_SP_CALIB_SAMPLER(0x3) |708	       MVEBU_SP_CALIB_SAMPLER_EN;709	writel(val, priv->base + MVEBU_SP_CALIB(lane->id));710	val &= ~MVEBU_SP_CALIB_SAMPLER_EN;711	writel(val, priv->base + MVEBU_SP_CALIB(lane->id));712 713	/* External rx regulator */714	val = readl(priv->base + MVEBU_COMPHY_EXT_SELV(lane->id));715	val &= ~MVEBU_COMPHY_EXT_SELV_RX_SAMPL(0x1f);716	val |= MVEBU_COMPHY_EXT_SELV_RX_SAMPL(0x1a);717	writel(val, priv->base + MVEBU_COMPHY_EXT_SELV(lane->id));718 719	return mvebu_comphy_init_plls(lane);720}721 722static int mvebu_comphy_power_on_legacy(struct phy *phy)723{724	struct mvebu_comphy_lane *lane = phy_get_drvdata(phy);725	struct mvebu_comphy_priv *priv = lane->priv;726	int ret, mux;727	u32 val;728 729	mux = mvebu_comphy_get_mux(lane->id, lane->port,730				   lane->mode, lane->submode);731	if (mux < 0)732		return -ENOTSUPP;733 734	regmap_read(priv->regmap, MVEBU_COMPHY_PIPE_SELECTOR, &val);735	val &= ~(0xf << MVEBU_COMPHY_PIPE_SELECTOR_PIPE(lane->id));736	regmap_write(priv->regmap, MVEBU_COMPHY_PIPE_SELECTOR, val);737 738	regmap_read(priv->regmap, MVEBU_COMPHY_SELECTOR, &val);739	val &= ~(0xf << MVEBU_COMPHY_SELECTOR_PHY(lane->id));740	val |= mux << MVEBU_COMPHY_SELECTOR_PHY(lane->id);741	regmap_write(priv->regmap, MVEBU_COMPHY_SELECTOR, val);742 743	switch (lane->submode) {744	case PHY_INTERFACE_MODE_SGMII:745	case PHY_INTERFACE_MODE_2500BASEX:746		ret = mvebu_comphy_set_mode_sgmii(phy);747		break;748	case PHY_INTERFACE_MODE_RXAUI:749		ret = mvebu_comphy_set_mode_rxaui(phy);750		break;751	case PHY_INTERFACE_MODE_10GBASER:752		ret = mvebu_comphy_set_mode_10gbaser(phy);753		break;754	default:755		return -ENOTSUPP;756	}757 758	/* digital reset */759	val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));760	val |= MVEBU_COMPHY_SERDES_CFG1_RF_RESET;761	writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));762 763	return ret;764}765 766static int mvebu_comphy_power_on(struct phy *phy)767{768	struct mvebu_comphy_lane *lane = phy_get_drvdata(phy);769	struct mvebu_comphy_priv *priv = lane->priv;770	int fw_mode, fw_speed;771	u32 fw_param = 0;772	int ret;773 774	fw_mode = mvebu_comphy_get_fw_mode(lane->id, lane->port,775					   lane->mode, lane->submode);776	if (fw_mode < 0)777		goto try_legacy;778 779	/* Try SMC flow first */780	switch (lane->mode) {781	case PHY_MODE_ETHERNET:782		switch (lane->submode) {783		case PHY_INTERFACE_MODE_RXAUI:784			dev_dbg(priv->dev, "set lane %d to RXAUI mode\n",785				lane->id);786			fw_speed = 0;787			break;788		case PHY_INTERFACE_MODE_SGMII:789			dev_dbg(priv->dev, "set lane %d to 1000BASE-X mode\n",790				lane->id);791			fw_speed = COMPHY_FW_SPEED_1250;792			break;793		case PHY_INTERFACE_MODE_2500BASEX:794			dev_dbg(priv->dev, "set lane %d to 2500BASE-X mode\n",795				lane->id);796			fw_speed = COMPHY_FW_SPEED_3125;797			break;798		case PHY_INTERFACE_MODE_5GBASER:799			dev_dbg(priv->dev, "set lane %d to 5GBASE-R mode\n",800				lane->id);801			fw_speed = COMPHY_FW_SPEED_515625;802			break;803		case PHY_INTERFACE_MODE_10GBASER:804			dev_dbg(priv->dev, "set lane %d to 10GBASE-R mode\n",805				lane->id);806			fw_speed = COMPHY_FW_SPEED_103125;807			break;808		default:809			dev_err(priv->dev, "unsupported Ethernet mode (%d)\n",810				lane->submode);811			return -ENOTSUPP;812		}813		fw_param = COMPHY_FW_PARAM_ETH(fw_mode, lane->port, fw_speed);814		break;815	case PHY_MODE_USB_HOST_SS:816	case PHY_MODE_USB_DEVICE_SS:817		dev_dbg(priv->dev, "set lane %d to USB3 mode\n", lane->id);818		fw_param = COMPHY_FW_PARAM(fw_mode, lane->port);819		break;820	case PHY_MODE_SATA:821		dev_dbg(priv->dev, "set lane %d to SATA mode\n", lane->id);822		fw_param = COMPHY_FW_PARAM(fw_mode, lane->port);823		break;824	case PHY_MODE_PCIE:825		dev_dbg(priv->dev, "set lane %d to PCIe mode (x%d)\n", lane->id,826			lane->submode);827		fw_param = COMPHY_FW_PARAM_PCIE(fw_mode, lane->port,828						lane->submode);829		break;830	default:831		dev_err(priv->dev, "unsupported PHY mode (%d)\n", lane->mode);832		return -ENOTSUPP;833	}834 835	ret = mvebu_comphy_smc(COMPHY_SIP_POWER_ON, priv->cp_phys, lane->id,836			       fw_param);837	if (!ret)838		return ret;839 840	if (ret == -EOPNOTSUPP)841		dev_err(priv->dev,842			"unsupported SMC call, try updating your firmware\n");843 844	dev_warn(priv->dev,845		 "Firmware could not configure PHY %d with mode %d (ret: %d), trying legacy method\n",846		 lane->id, lane->mode, ret);847 848try_legacy:849	/* Fallback to Linux's implementation */850	return mvebu_comphy_power_on_legacy(phy);851}852 853static int mvebu_comphy_set_mode(struct phy *phy,854				 enum phy_mode mode, int submode)855{856	struct mvebu_comphy_lane *lane = phy_get_drvdata(phy);857 858	if (submode == PHY_INTERFACE_MODE_1000BASEX)859		submode = PHY_INTERFACE_MODE_SGMII;860 861	if (mvebu_comphy_get_fw_mode(lane->id, lane->port, mode, submode) < 0)862		return -EINVAL;863 864	lane->mode = mode;865	lane->submode = submode;866 867	/* PCIe submode represents the width */868	if (mode == PHY_MODE_PCIE && !lane->submode)869		lane->submode = 1;870 871	return 0;872}873 874static int mvebu_comphy_power_off_legacy(struct phy *phy)875{876	struct mvebu_comphy_lane *lane = phy_get_drvdata(phy);877	struct mvebu_comphy_priv *priv = lane->priv;878	u32 val;879 880	val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));881	val &= ~(MVEBU_COMPHY_SERDES_CFG1_RESET |882		 MVEBU_COMPHY_SERDES_CFG1_CORE_RESET |883		 MVEBU_COMPHY_SERDES_CFG1_RF_RESET);884	writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));885 886	regmap_read(priv->regmap, MVEBU_COMPHY_SELECTOR, &val);887	val &= ~(0xf << MVEBU_COMPHY_SELECTOR_PHY(lane->id));888	regmap_write(priv->regmap, MVEBU_COMPHY_SELECTOR, val);889 890	regmap_read(priv->regmap, MVEBU_COMPHY_PIPE_SELECTOR, &val);891	val &= ~(0xf << MVEBU_COMPHY_PIPE_SELECTOR_PIPE(lane->id));892	regmap_write(priv->regmap, MVEBU_COMPHY_PIPE_SELECTOR, val);893 894	return 0;895}896 897static int mvebu_comphy_power_off(struct phy *phy)898{899	struct mvebu_comphy_lane *lane = phy_get_drvdata(phy);900	struct mvebu_comphy_priv *priv = lane->priv;901	int ret;902 903	ret = mvebu_comphy_smc(COMPHY_SIP_POWER_OFF, priv->cp_phys,904			       lane->id, 0);905	if (!ret)906		return ret;907 908	/* Fallback to Linux's implementation */909	return mvebu_comphy_power_off_legacy(phy);910}911 912static const struct phy_ops mvebu_comphy_ops = {913	.power_on	= mvebu_comphy_power_on,914	.power_off	= mvebu_comphy_power_off,915	.set_mode	= mvebu_comphy_set_mode,916	.owner		= THIS_MODULE,917};918 919static struct phy *mvebu_comphy_xlate(struct device *dev,920				      const struct of_phandle_args *args)921{922	struct mvebu_comphy_lane *lane;923	struct phy *phy;924 925	if (WARN_ON(args->args[0] >= MVEBU_COMPHY_PORTS))926		return ERR_PTR(-EINVAL);927 928	phy = of_phy_simple_xlate(dev, args);929	if (IS_ERR(phy))930		return phy;931 932	lane = phy_get_drvdata(phy);933	lane->port = args->args[0];934 935	return phy;936}937 938static int mvebu_comphy_init_clks(struct mvebu_comphy_priv *priv)939{940	int ret;941 942	priv->mg_domain_clk = devm_clk_get(priv->dev, "mg_clk");943	if (IS_ERR(priv->mg_domain_clk))944		return PTR_ERR(priv->mg_domain_clk);945 946	ret = clk_prepare_enable(priv->mg_domain_clk);947	if (ret < 0)948		return ret;949 950	priv->mg_core_clk = devm_clk_get(priv->dev, "mg_core_clk");951	if (IS_ERR(priv->mg_core_clk)) {952		ret = PTR_ERR(priv->mg_core_clk);953		goto dis_mg_domain_clk;954	}955 956	ret = clk_prepare_enable(priv->mg_core_clk);957	if (ret < 0)958		goto dis_mg_domain_clk;959 960	priv->axi_clk = devm_clk_get(priv->dev, "axi_clk");961	if (IS_ERR(priv->axi_clk)) {962		ret = PTR_ERR(priv->axi_clk);963		goto dis_mg_core_clk;964	}965 966	ret = clk_prepare_enable(priv->axi_clk);967	if (ret < 0)968		goto dis_mg_core_clk;969 970	return 0;971 972dis_mg_core_clk:973	clk_disable_unprepare(priv->mg_core_clk);974 975dis_mg_domain_clk:976	clk_disable_unprepare(priv->mg_domain_clk);977 978	priv->mg_domain_clk = NULL;979	priv->mg_core_clk = NULL;980	priv->axi_clk = NULL;981 982	return ret;983};984 985static void mvebu_comphy_disable_unprepare_clks(struct mvebu_comphy_priv *priv)986{987	if (priv->axi_clk)988		clk_disable_unprepare(priv->axi_clk);989 990	if (priv->mg_core_clk)991		clk_disable_unprepare(priv->mg_core_clk);992 993	if (priv->mg_domain_clk)994		clk_disable_unprepare(priv->mg_domain_clk);995}996 997static int mvebu_comphy_probe(struct platform_device *pdev)998{999	struct mvebu_comphy_priv *priv;1000	struct phy_provider *provider;1001	struct device_node *child;1002	struct resource *res;1003	int ret;1004 1005	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);1006	if (!priv)1007		return -ENOMEM;1008 1009	priv->dev = &pdev->dev;1010	priv->regmap =1011		syscon_regmap_lookup_by_phandle(pdev->dev.of_node,1012						"marvell,system-controller");1013	if (IS_ERR(priv->regmap))1014		return PTR_ERR(priv->regmap);1015	priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);1016	if (IS_ERR(priv->base))1017		return PTR_ERR(priv->base);1018 1019	/*1020	 * Ignore error if clocks have not been initialized properly for DT1021	 * compatibility reasons.1022	 */1023	ret = mvebu_comphy_init_clks(priv);1024	if (ret) {1025		if (ret == -EPROBE_DEFER)1026			return ret;1027		dev_warn(&pdev->dev, "cannot initialize clocks\n");1028	}1029 1030	/*1031	 * Hack to retrieve a physical offset relative to this CP that will be1032	 * given to the firmware1033	 */1034	priv->cp_phys = res->start;1035 1036	for_each_available_child_of_node(pdev->dev.of_node, child) {1037		struct mvebu_comphy_lane *lane;1038		struct phy *phy;1039		u32 val;1040 1041		ret = of_property_read_u32(child, "reg", &val);1042		if (ret < 0) {1043			dev_err(&pdev->dev, "missing 'reg' property (%d)\n",1044				ret);1045			continue;1046		}1047 1048		if (val >= MVEBU_COMPHY_LANES) {1049			dev_err(&pdev->dev, "invalid 'reg' property\n");1050			continue;1051		}1052 1053		lane = devm_kzalloc(&pdev->dev, sizeof(*lane), GFP_KERNEL);1054		if (!lane) {1055			of_node_put(child);1056			ret = -ENOMEM;1057			goto disable_clks;1058		}1059 1060		phy = devm_phy_create(&pdev->dev, child, &mvebu_comphy_ops);1061		if (IS_ERR(phy)) {1062			of_node_put(child);1063			ret = PTR_ERR(phy);1064			goto disable_clks;1065		}1066 1067		lane->priv = priv;1068		lane->mode = PHY_MODE_INVALID;1069		lane->submode = PHY_INTERFACE_MODE_NA;1070		lane->id = val;1071		lane->port = -1;1072		phy_set_drvdata(phy, lane);1073 1074		/*1075		 * All modes are supported in this driver so we could call1076		 * mvebu_comphy_power_off(phy) here to avoid relying on the1077		 * bootloader/firmware configuration, but for compatibility1078		 * reasons we cannot de-configure the COMPHY without being sure1079		 * that the firmware is up-to-date and fully-featured.1080		 */1081	}1082 1083	dev_set_drvdata(&pdev->dev, priv);1084	provider = devm_of_phy_provider_register(&pdev->dev,1085						 mvebu_comphy_xlate);1086 1087	return PTR_ERR_OR_ZERO(provider);1088 1089disable_clks:1090	mvebu_comphy_disable_unprepare_clks(priv);1091 1092	return ret;1093}1094 1095static const struct of_device_id mvebu_comphy_of_match_table[] = {1096	{ .compatible = "marvell,comphy-cp110" },1097	{ },1098};1099MODULE_DEVICE_TABLE(of, mvebu_comphy_of_match_table);1100 1101static struct platform_driver mvebu_comphy_driver = {1102	.probe	= mvebu_comphy_probe,1103	.driver	= {1104		.name = "mvebu-comphy",1105		.of_match_table = mvebu_comphy_of_match_table,1106	},1107};1108module_platform_driver(mvebu_comphy_driver);1109 1110MODULE_AUTHOR("Antoine Tenart <antoine.tenart@free-electrons.com>");1111MODULE_DESCRIPTION("Common PHY driver for mvebu SoCs");1112MODULE_LICENSE("GPL v2");1113