1ec14b83aSAntoine Tenart // SPDX-License-Identifier: GPL-2.0
2d0438bd6SAntoine Tenart /*
3d0438bd6SAntoine Tenart  * Copyright (C) 2017 Marvell
4d0438bd6SAntoine Tenart  *
5d0438bd6SAntoine Tenart  * Antoine Tenart <antoine.tenart@free-electrons.com>
6d0438bd6SAntoine Tenart  */
7d0438bd6SAntoine Tenart 
8eb6a1fcbSGrzegorz Jaszczyk #include <linux/arm-smccc.h>
90629d57bSMiquel Raynal #include <linux/clk.h>
10d0438bd6SAntoine Tenart #include <linux/io.h>
11d0438bd6SAntoine Tenart #include <linux/iopoll.h>
12d0438bd6SAntoine Tenart #include <linux/mfd/syscon.h>
13d0438bd6SAntoine Tenart #include <linux/module.h>
14*7559e757SRob Herring #include <linux/of.h>
15cccc43b8SGrygorii Strashko #include <linux/phy.h>
16d0438bd6SAntoine Tenart #include <linux/phy/phy.h>
17d0438bd6SAntoine Tenart #include <linux/platform_device.h>
18d0438bd6SAntoine Tenart #include <linux/regmap.h>
19d0438bd6SAntoine Tenart 
20d0438bd6SAntoine Tenart /* Relative to priv->base */
21d0438bd6SAntoine Tenart #define MVEBU_COMPHY_SERDES_CFG0(n)		(0x0 + (n) * 0x1000)
22d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_SERDES_CFG0_PU_PLL	BIT(1)
23d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_SERDES_CFG0_GEN_RX(n)	((n) << 3)
24d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_SERDES_CFG0_GEN_TX(n)	((n) << 7)
25d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_SERDES_CFG0_PU_RX	BIT(11)
26d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_SERDES_CFG0_PU_TX	BIT(12)
27d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_SERDES_CFG0_HALF_BUS	BIT(14)
28f2a857aaSMatt Pelland #define     MVEBU_COMPHY_SERDES_CFG0_RXAUI_MODE	BIT(15)
29d0438bd6SAntoine Tenart #define MVEBU_COMPHY_SERDES_CFG1(n)		(0x4 + (n) * 0x1000)
30d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_SERDES_CFG1_RESET	BIT(3)
31d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_SERDES_CFG1_RX_INIT	BIT(4)
32d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_SERDES_CFG1_CORE_RESET	BIT(5)
33d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_SERDES_CFG1_RF_RESET	BIT(6)
34d0438bd6SAntoine Tenart #define MVEBU_COMPHY_SERDES_CFG2(n)		(0x8 + (n) * 0x1000)
35d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_SERDES_CFG2_DFE_EN	BIT(4)
36d0438bd6SAntoine Tenart #define MVEBU_COMPHY_SERDES_STATUS0(n)		(0x18 + (n) * 0x1000)
37d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_SERDES_STATUS0_TX_PLL_RDY	BIT(2)
38d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_SERDES_STATUS0_RX_PLL_RDY	BIT(3)
39d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_SERDES_STATUS0_RX_INIT		BIT(4)
40d0438bd6SAntoine Tenart #define MVEBU_COMPHY_PWRPLL_CTRL(n)		(0x804 + (n) * 0x1000)
41d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_PWRPLL_CTRL_RFREQ(n)	((n) << 0)
42d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_PWRPLL_PHY_MODE(n)	((n) << 5)
43d0438bd6SAntoine Tenart #define MVEBU_COMPHY_IMP_CAL(n)			(0x80c + (n) * 0x1000)
44d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_IMP_CAL_TX_EXT(n)	((n) << 10)
45d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_IMP_CAL_TX_EXT_EN	BIT(15)
46d0438bd6SAntoine Tenart #define MVEBU_COMPHY_DFE_RES(n)			(0x81c + (n) * 0x1000)
47d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_DFE_RES_FORCE_GEN_TBL	BIT(15)
48d0438bd6SAntoine Tenart #define MVEBU_COMPHY_COEF(n)			(0x828 + (n) * 0x1000)
49d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_COEF_DFE_EN		BIT(14)
50d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_COEF_DFE_CTRL		BIT(15)
51d0438bd6SAntoine Tenart #define MVEBU_COMPHY_GEN1_S0(n)			(0x834 + (n) * 0x1000)
52d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_GEN1_S0_TX_AMP(n)	((n) << 1)
53d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_GEN1_S0_TX_EMPH(n)	((n) << 7)
54d0438bd6SAntoine Tenart #define MVEBU_COMPHY_GEN1_S1(n)			(0x838 + (n) * 0x1000)
55d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_GEN1_S1_RX_MUL_PI(n)	((n) << 0)
56d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_GEN1_S1_RX_MUL_PF(n)	((n) << 3)
57d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_GEN1_S1_RX_MUL_FI(n)	((n) << 6)
58d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_GEN1_S1_RX_MUL_FF(n)	((n) << 8)
59d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_GEN1_S1_RX_DFE_EN	BIT(10)
60d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_GEN1_S1_RX_DIV(n)	((n) << 11)
61d0438bd6SAntoine Tenart #define MVEBU_COMPHY_GEN1_S2(n)			(0x8f4 + (n) * 0x1000)
62d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_GEN1_S2_TX_EMPH(n)	((n) << 0)
63d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_GEN1_S2_TX_EMPH_EN	BIT(4)
64d0438bd6SAntoine Tenart #define MVEBU_COMPHY_LOOPBACK(n)		(0x88c + (n) * 0x1000)
65d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_LOOPBACK_DBUS_WIDTH(n)	((n) << 1)
66d0438bd6SAntoine Tenart #define MVEBU_COMPHY_VDD_CAL0(n)		(0x908 + (n) * 0x1000)
67d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_VDD_CAL0_CONT_MODE	BIT(15)
68d0438bd6SAntoine Tenart #define MVEBU_COMPHY_EXT_SELV(n)		(0x914 + (n) * 0x1000)
69d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_EXT_SELV_RX_SAMPL(n)	((n) << 5)
70d0438bd6SAntoine Tenart #define MVEBU_COMPHY_MISC_CTRL0(n)		(0x93c + (n) * 0x1000)
71d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_MISC_CTRL0_ICP_FORCE	BIT(5)
72d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_MISC_CTRL0_REFCLK_SEL	BIT(10)
73d0438bd6SAntoine Tenart #define MVEBU_COMPHY_RX_CTRL1(n)		(0x940 + (n) * 0x1000)
74d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_RX_CTRL1_RXCLK2X_SEL	BIT(11)
75d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_RX_CTRL1_CLK8T_EN	BIT(12)
76d0438bd6SAntoine Tenart #define MVEBU_COMPHY_SPEED_DIV(n)		(0x954 + (n) * 0x1000)
77d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_SPEED_DIV_TX_FORCE	BIT(7)
78d0438bd6SAntoine Tenart #define MVEBU_SP_CALIB(n)			(0x96c + (n) * 0x1000)
79d0438bd6SAntoine Tenart #define     MVEBU_SP_CALIB_SAMPLER(n)		((n) << 8)
80d0438bd6SAntoine Tenart #define     MVEBU_SP_CALIB_SAMPLER_EN		BIT(12)
81d0438bd6SAntoine Tenart #define MVEBU_COMPHY_TX_SLEW_RATE(n)		(0x974 + (n) * 0x1000)
82d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_TX_SLEW_RATE_EMPH(n)	((n) << 5)
83d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_TX_SLEW_RATE_SLC(n)	((n) << 10)
845af67635SMatt Pelland #define MVEBU_COMPHY_DTL_CTRL(n)		(0x984 + (n) * 0x1000)
855af67635SMatt Pelland #define     MVEBU_COMPHY_DTL_CTRL_DTL_FLOOP_EN	BIT(2)
86d0438bd6SAntoine Tenart #define MVEBU_COMPHY_FRAME_DETECT0(n)		(0xa14 + (n) * 0x1000)
87d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_FRAME_DETECT0_PATN(n)	((n) << 7)
88d0438bd6SAntoine Tenart #define MVEBU_COMPHY_FRAME_DETECT3(n)		(0xa20 + (n) * 0x1000)
89d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_FRAME_DETECT3_LOST_TIMEOUT_EN	BIT(12)
90d0438bd6SAntoine Tenart #define MVEBU_COMPHY_DME(n)			(0xa28 + (n) * 0x1000)
91d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_DME_ETH_MODE		BIT(7)
92d0438bd6SAntoine Tenart #define MVEBU_COMPHY_TRAINING0(n)		(0xa68 + (n) * 0x1000)
93d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_TRAINING0_P2P_HOLD	BIT(15)
94d0438bd6SAntoine Tenart #define MVEBU_COMPHY_TRAINING5(n)		(0xaa4 + (n) * 0x1000)
95d0438bd6SAntoine Tenart #define	    MVEBU_COMPHY_TRAINING5_RX_TIMER(n)	((n) << 0)
96d0438bd6SAntoine Tenart #define MVEBU_COMPHY_TX_TRAIN_PRESET(n)		(0xb1c + (n) * 0x1000)
97d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_TX_TRAIN_PRESET_16B_AUTO_EN	BIT(8)
98d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_TX_TRAIN_PRESET_PRBS11		BIT(9)
99d0438bd6SAntoine Tenart #define MVEBU_COMPHY_GEN1_S3(n)			(0xc40 + (n) * 0x1000)
100d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_GEN1_S3_FBCK_SEL	BIT(9)
101d0438bd6SAntoine Tenart #define MVEBU_COMPHY_GEN1_S4(n)			(0xc44 + (n) * 0x1000)
102d0438bd6SAntoine Tenart #define	    MVEBU_COMPHY_GEN1_S4_DFE_RES(n)	((n) << 8)
103d0438bd6SAntoine Tenart #define MVEBU_COMPHY_TX_PRESET(n)		(0xc68 + (n) * 0x1000)
104d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_TX_PRESET_INDEX(n)	((n) << 0)
105d0438bd6SAntoine Tenart #define MVEBU_COMPHY_GEN1_S5(n)			(0xd38 + (n) * 0x1000)
106d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_GEN1_S5_ICP(n)		((n) << 0)
107d0438bd6SAntoine Tenart 
108d0438bd6SAntoine Tenart /* Relative to priv->regmap */
109d0438bd6SAntoine Tenart #define MVEBU_COMPHY_CONF1(n)			(0x1000 + (n) * 0x28)
110d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_CONF1_PWRUP		BIT(1)
111d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_CONF1_USB_PCIE		BIT(2)	/* 0: Ethernet/SATA */
112d0438bd6SAntoine Tenart #define MVEBU_COMPHY_CONF6(n)			(0x1014 + (n) * 0x28)
113d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_CONF6_40B		BIT(18)
114d0438bd6SAntoine Tenart #define MVEBU_COMPHY_SELECTOR			0x1140
115d0438bd6SAntoine Tenart #define     MVEBU_COMPHY_SELECTOR_PHY(n)	((n) * 0x4)
11617fb745dSAntoine Tenart #define MVEBU_COMPHY_PIPE_SELECTOR		0x1144
11717fb745dSAntoine Tenart #define     MVEBU_COMPHY_PIPE_SELECTOR_PIPE(n)	((n) * 0x4)
118f2a857aaSMatt Pelland #define MVEBU_COMPHY_SD1_CTRL1			0x1148
119f2a857aaSMatt Pelland #define     MVEBU_COMPHY_SD1_CTRL1_RXAUI1_EN	BIT(26)
120f2a857aaSMatt Pelland #define     MVEBU_COMPHY_SD1_CTRL1_RXAUI0_EN	BIT(27)
121d0438bd6SAntoine Tenart 
122d0438bd6SAntoine Tenart #define MVEBU_COMPHY_LANES	6
123d0438bd6SAntoine Tenart #define MVEBU_COMPHY_PORTS	3
124d0438bd6SAntoine Tenart 
125eb6a1fcbSGrzegorz Jaszczyk #define COMPHY_SIP_POWER_ON	0x82000001
126eb6a1fcbSGrzegorz Jaszczyk #define COMPHY_SIP_POWER_OFF	0x82000002
127eb6a1fcbSGrzegorz Jaszczyk 
128eb6a1fcbSGrzegorz Jaszczyk /*
129eb6a1fcbSGrzegorz Jaszczyk  * A lane is described by the following bitfields:
130eb6a1fcbSGrzegorz Jaszczyk  * [ 1- 0]: COMPHY polarity invertion
131eb6a1fcbSGrzegorz Jaszczyk  * [ 2- 7]: COMPHY speed
132eb6a1fcbSGrzegorz Jaszczyk  * [ 5-11]: COMPHY port index
133eb6a1fcbSGrzegorz Jaszczyk  * [12-16]: COMPHY mode
134eb6a1fcbSGrzegorz Jaszczyk  * [17]: Clock source
13565248876SGrzegorz Jaszczyk  * [18-20]: PCIe width (x1, x2, x4)
136eb6a1fcbSGrzegorz Jaszczyk  */
137eb6a1fcbSGrzegorz Jaszczyk #define COMPHY_FW_POL_OFFSET	0
138eb6a1fcbSGrzegorz Jaszczyk #define COMPHY_FW_POL_MASK	GENMASK(1, 0)
139eb6a1fcbSGrzegorz Jaszczyk #define COMPHY_FW_SPEED_OFFSET	2
140eb6a1fcbSGrzegorz Jaszczyk #define COMPHY_FW_SPEED_MASK	GENMASK(7, 2)
141eb6a1fcbSGrzegorz Jaszczyk #define COMPHY_FW_SPEED_MAX	COMPHY_FW_SPEED_MASK
142eb6a1fcbSGrzegorz Jaszczyk #define COMPHY_FW_SPEED_1250	0
143eb6a1fcbSGrzegorz Jaszczyk #define COMPHY_FW_SPEED_3125	2
144eb6a1fcbSGrzegorz Jaszczyk #define COMPHY_FW_SPEED_5000	3
145a1fb410aSMarek Behún #define COMPHY_FW_SPEED_515625	4
146eb6a1fcbSGrzegorz Jaszczyk #define COMPHY_FW_SPEED_103125	6
147eb6a1fcbSGrzegorz Jaszczyk #define COMPHY_FW_PORT_OFFSET	8
148eb6a1fcbSGrzegorz Jaszczyk #define COMPHY_FW_PORT_MASK	GENMASK(11, 8)
149eb6a1fcbSGrzegorz Jaszczyk #define COMPHY_FW_MODE_OFFSET	12
150eb6a1fcbSGrzegorz Jaszczyk #define COMPHY_FW_MODE_MASK	GENMASK(16, 12)
15165248876SGrzegorz Jaszczyk #define COMPHY_FW_WIDTH_OFFSET	18
15265248876SGrzegorz Jaszczyk #define COMPHY_FW_WIDTH_MASK	GENMASK(20, 18)
153eb6a1fcbSGrzegorz Jaszczyk 
15465248876SGrzegorz Jaszczyk #define COMPHY_FW_PARAM_FULL(mode, port, speed, pol, width)		\
155eb6a1fcbSGrzegorz Jaszczyk 	((((pol) << COMPHY_FW_POL_OFFSET) & COMPHY_FW_POL_MASK) |	\
156eb6a1fcbSGrzegorz Jaszczyk 	 (((mode) << COMPHY_FW_MODE_OFFSET) & COMPHY_FW_MODE_MASK) |	\
157eb6a1fcbSGrzegorz Jaszczyk 	 (((port) << COMPHY_FW_PORT_OFFSET) & COMPHY_FW_PORT_MASK) |	\
15865248876SGrzegorz Jaszczyk 	 (((speed) << COMPHY_FW_SPEED_OFFSET) & COMPHY_FW_SPEED_MASK) |	\
15965248876SGrzegorz Jaszczyk 	 (((width) << COMPHY_FW_WIDTH_OFFSET) & COMPHY_FW_WIDTH_MASK))
160eb6a1fcbSGrzegorz Jaszczyk 
161eb6a1fcbSGrzegorz Jaszczyk #define COMPHY_FW_PARAM(mode, port)					\
16265248876SGrzegorz Jaszczyk 	COMPHY_FW_PARAM_FULL(mode, port, COMPHY_FW_SPEED_MAX, 0, 0)
163eb6a1fcbSGrzegorz Jaszczyk 
164eb6a1fcbSGrzegorz Jaszczyk #define COMPHY_FW_PARAM_ETH(mode, port, speed)				\
16565248876SGrzegorz Jaszczyk 	COMPHY_FW_PARAM_FULL(mode, port, speed, 0, 0)
16665248876SGrzegorz Jaszczyk 
16765248876SGrzegorz Jaszczyk #define COMPHY_FW_PARAM_PCIE(mode, port, width)				\
16865248876SGrzegorz Jaszczyk 	COMPHY_FW_PARAM_FULL(mode, port, COMPHY_FW_SPEED_5000, 0, width)
169eb6a1fcbSGrzegorz Jaszczyk 
170ef0ac9f2SGrzegorz Jaszczyk #define COMPHY_FW_MODE_SATA		0x1
171eb6a1fcbSGrzegorz Jaszczyk #define COMPHY_FW_MODE_SGMII		0x2 /* SGMII 1G */
1723f141ad6SPali Rohár #define COMPHY_FW_MODE_2500BASEX	0x3 /* 2500BASE-X */
173c527a636SGrzegorz Jaszczyk #define COMPHY_FW_MODE_USB3H		0x4
174c527a636SGrzegorz Jaszczyk #define COMPHY_FW_MODE_USB3D		0x5
17565248876SGrzegorz Jaszczyk #define COMPHY_FW_MODE_PCIE		0x6
176461324f0SGrzegorz Jaszczyk #define COMPHY_FW_MODE_RXAUI		0x7
177eb6a1fcbSGrzegorz Jaszczyk #define COMPHY_FW_MODE_XFI		0x8 /* SFI: 0x9 (is treated like XFI) */
178eb6a1fcbSGrzegorz Jaszczyk 
179c5e18b34SMiquel Raynal struct mvebu_comphy_conf {
180d0438bd6SAntoine Tenart 	enum phy_mode mode;
181cccc43b8SGrygorii Strashko 	int submode;
182d0438bd6SAntoine Tenart 	unsigned lane;
183d0438bd6SAntoine Tenart 	unsigned port;
184d0438bd6SAntoine Tenart 	u32 mux;
185eb6a1fcbSGrzegorz Jaszczyk 	u32 fw_mode;
186d0438bd6SAntoine Tenart };
187d0438bd6SAntoine Tenart 
188c2afb2feSMiquel Raynal #define ETH_CONF(_lane, _port, _submode, _mux, _fw)	\
189d0438bd6SAntoine Tenart 	{						\
190d0438bd6SAntoine Tenart 		.lane = _lane,				\
191d0438bd6SAntoine Tenart 		.port = _port,				\
192cccc43b8SGrygorii Strashko 		.mode = PHY_MODE_ETHERNET,		\
193cccc43b8SGrygorii Strashko 		.submode = _submode,			\
194d0438bd6SAntoine Tenart 		.mux = _mux,				\
195eb6a1fcbSGrzegorz Jaszczyk 		.fw_mode = _fw,				\
196d0438bd6SAntoine Tenart 	}
197d0438bd6SAntoine Tenart 
198c527a636SGrzegorz Jaszczyk #define GEN_CONF(_lane, _port, _mode, _fw)		\
199c527a636SGrzegorz Jaszczyk 	{						\
200c527a636SGrzegorz Jaszczyk 		.lane = _lane,				\
201c527a636SGrzegorz Jaszczyk 		.port = _port,				\
202c527a636SGrzegorz Jaszczyk 		.mode = _mode,				\
203c527a636SGrzegorz Jaszczyk 		.submode = PHY_INTERFACE_MODE_NA,	\
204c527a636SGrzegorz Jaszczyk 		.mux = -1,				\
205c527a636SGrzegorz Jaszczyk 		.fw_mode = _fw,				\
206c527a636SGrzegorz Jaszczyk 	}
207c527a636SGrzegorz Jaszczyk 
208c5e18b34SMiquel Raynal static const struct mvebu_comphy_conf mvebu_comphy_cp110_modes[] = {
209d0438bd6SAntoine Tenart 	/* lane 0 */
21065248876SGrzegorz Jaszczyk 	GEN_CONF(0, 0, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE),
211c2afb2feSMiquel Raynal 	ETH_CONF(0, 1, PHY_INTERFACE_MODE_SGMII, 0x1, COMPHY_FW_MODE_SGMII),
2123f141ad6SPali Rohár 	ETH_CONF(0, 1, PHY_INTERFACE_MODE_2500BASEX, 0x1, COMPHY_FW_MODE_2500BASEX),
213ef0ac9f2SGrzegorz Jaszczyk 	GEN_CONF(0, 1, PHY_MODE_SATA, COMPHY_FW_MODE_SATA),
214d0438bd6SAntoine Tenart 	/* lane 1 */
215c527a636SGrzegorz Jaszczyk 	GEN_CONF(1, 0, PHY_MODE_USB_HOST_SS, COMPHY_FW_MODE_USB3H),
216c527a636SGrzegorz Jaszczyk 	GEN_CONF(1, 0, PHY_MODE_USB_DEVICE_SS, COMPHY_FW_MODE_USB3D),
217ef0ac9f2SGrzegorz Jaszczyk 	GEN_CONF(1, 0, PHY_MODE_SATA, COMPHY_FW_MODE_SATA),
21865248876SGrzegorz Jaszczyk 	GEN_CONF(1, 0, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE),
219c2afb2feSMiquel Raynal 	ETH_CONF(1, 2, PHY_INTERFACE_MODE_SGMII, 0x1, COMPHY_FW_MODE_SGMII),
2203f141ad6SPali Rohár 	ETH_CONF(1, 2, PHY_INTERFACE_MODE_2500BASEX, 0x1, COMPHY_FW_MODE_2500BASEX),
221d0438bd6SAntoine Tenart 	/* lane 2 */
222c2afb2feSMiquel Raynal 	ETH_CONF(2, 0, PHY_INTERFACE_MODE_SGMII, 0x1, COMPHY_FW_MODE_SGMII),
2233f141ad6SPali Rohár 	ETH_CONF(2, 0, PHY_INTERFACE_MODE_2500BASEX, 0x1, COMPHY_FW_MODE_2500BASEX),
224f2a857aaSMatt Pelland 	ETH_CONF(2, 0, PHY_INTERFACE_MODE_RXAUI, 0x1, COMPHY_FW_MODE_RXAUI),
225a1fb410aSMarek Behún 	ETH_CONF(2, 0, PHY_INTERFACE_MODE_5GBASER, 0x1, COMPHY_FW_MODE_XFI),
226e0f909bcSRussell King 	ETH_CONF(2, 0, PHY_INTERFACE_MODE_10GBASER, 0x1, COMPHY_FW_MODE_XFI),
227c527a636SGrzegorz Jaszczyk 	GEN_CONF(2, 0, PHY_MODE_USB_HOST_SS, COMPHY_FW_MODE_USB3H),
228ef0ac9f2SGrzegorz Jaszczyk 	GEN_CONF(2, 0, PHY_MODE_SATA, COMPHY_FW_MODE_SATA),
22965248876SGrzegorz Jaszczyk 	GEN_CONF(2, 0, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE),
230d0438bd6SAntoine Tenart 	/* lane 3 */
23165248876SGrzegorz Jaszczyk 	GEN_CONF(3, 0, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE),
232c2afb2feSMiquel Raynal 	ETH_CONF(3, 1, PHY_INTERFACE_MODE_SGMII, 0x2, COMPHY_FW_MODE_SGMII),
2333f141ad6SPali Rohár 	ETH_CONF(3, 1, PHY_INTERFACE_MODE_2500BASEX, 0x2, COMPHY_FW_MODE_2500BASEX),
234f2a857aaSMatt Pelland 	ETH_CONF(3, 1, PHY_INTERFACE_MODE_RXAUI, 0x1, COMPHY_FW_MODE_RXAUI),
235c527a636SGrzegorz Jaszczyk 	GEN_CONF(3, 1, PHY_MODE_USB_HOST_SS, COMPHY_FW_MODE_USB3H),
236ef0ac9f2SGrzegorz Jaszczyk 	GEN_CONF(3, 1, PHY_MODE_SATA, COMPHY_FW_MODE_SATA),
237d0438bd6SAntoine Tenart 	/* lane 4 */
238c2afb2feSMiquel Raynal 	ETH_CONF(4, 0, PHY_INTERFACE_MODE_SGMII, 0x2, COMPHY_FW_MODE_SGMII),
2393f141ad6SPali Rohár 	ETH_CONF(4, 0, PHY_INTERFACE_MODE_2500BASEX, 0x2, COMPHY_FW_MODE_2500BASEX),
240a1fb410aSMarek Behún 	ETH_CONF(4, 0, PHY_INTERFACE_MODE_5GBASER, 0x2, COMPHY_FW_MODE_XFI),
241e0f909bcSRussell King 	ETH_CONF(4, 0, PHY_INTERFACE_MODE_10GBASER, 0x2, COMPHY_FW_MODE_XFI),
242f2a857aaSMatt Pelland 	ETH_CONF(4, 0, PHY_INTERFACE_MODE_RXAUI, 0x2, COMPHY_FW_MODE_RXAUI),
243c527a636SGrzegorz Jaszczyk 	GEN_CONF(4, 0, PHY_MODE_USB_DEVICE_SS, COMPHY_FW_MODE_USB3D),
244c527a636SGrzegorz Jaszczyk 	GEN_CONF(4, 1, PHY_MODE_USB_HOST_SS, COMPHY_FW_MODE_USB3H),
24565248876SGrzegorz Jaszczyk 	GEN_CONF(4, 1, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE),
246c2afb2feSMiquel Raynal 	ETH_CONF(4, 1, PHY_INTERFACE_MODE_SGMII, 0x1, COMPHY_FW_MODE_SGMII),
2473f141ad6SPali Rohár 	ETH_CONF(4, 1, PHY_INTERFACE_MODE_2500BASEX, -1, COMPHY_FW_MODE_2500BASEX),
248a1fb410aSMarek Behún 	ETH_CONF(4, 1, PHY_INTERFACE_MODE_5GBASER, -1, COMPHY_FW_MODE_XFI),
249e0f909bcSRussell King 	ETH_CONF(4, 1, PHY_INTERFACE_MODE_10GBASER, -1, COMPHY_FW_MODE_XFI),
250d0438bd6SAntoine Tenart 	/* lane 5 */
251f2a857aaSMatt Pelland 	ETH_CONF(5, 1, PHY_INTERFACE_MODE_RXAUI, 0x2, COMPHY_FW_MODE_RXAUI),
252ef0ac9f2SGrzegorz Jaszczyk 	GEN_CONF(5, 1, PHY_MODE_SATA, COMPHY_FW_MODE_SATA),
253c2afb2feSMiquel Raynal 	ETH_CONF(5, 2, PHY_INTERFACE_MODE_SGMII, 0x1, COMPHY_FW_MODE_SGMII),
2543f141ad6SPali Rohár 	ETH_CONF(5, 2, PHY_INTERFACE_MODE_2500BASEX, 0x1, COMPHY_FW_MODE_2500BASEX),
25565248876SGrzegorz Jaszczyk 	GEN_CONF(5, 2, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE),
256d0438bd6SAntoine Tenart };
257d0438bd6SAntoine Tenart 
258d0438bd6SAntoine Tenart struct mvebu_comphy_priv {
259d0438bd6SAntoine Tenart 	void __iomem *base;
260d0438bd6SAntoine Tenart 	struct regmap *regmap;
261d0438bd6SAntoine Tenart 	struct device *dev;
2620629d57bSMiquel Raynal 	struct clk *mg_domain_clk;
2630629d57bSMiquel Raynal 	struct clk *mg_core_clk;
2640629d57bSMiquel Raynal 	struct clk *axi_clk;
265eb6a1fcbSGrzegorz Jaszczyk 	unsigned long cp_phys;
266d0438bd6SAntoine Tenart };
267d0438bd6SAntoine Tenart 
268d0438bd6SAntoine Tenart struct mvebu_comphy_lane {
269d0438bd6SAntoine Tenart 	struct mvebu_comphy_priv *priv;
270d0438bd6SAntoine Tenart 	unsigned id;
271d0438bd6SAntoine Tenart 	enum phy_mode mode;
272cccc43b8SGrygorii Strashko 	int submode;
273d0438bd6SAntoine Tenart 	int port;
274d0438bd6SAntoine Tenart };
275d0438bd6SAntoine Tenart 
mvebu_comphy_smc(unsigned long function,unsigned long phys,unsigned long lane,unsigned long mode)276eb6a1fcbSGrzegorz Jaszczyk static int mvebu_comphy_smc(unsigned long function, unsigned long phys,
277eb6a1fcbSGrzegorz Jaszczyk 			    unsigned long lane, unsigned long mode)
278eb6a1fcbSGrzegorz Jaszczyk {
279eb6a1fcbSGrzegorz Jaszczyk 	struct arm_smccc_res res;
280ea17a0f1SPali Rohár 	s32 ret;
281eb6a1fcbSGrzegorz Jaszczyk 
282eb6a1fcbSGrzegorz Jaszczyk 	arm_smccc_smc(function, phys, lane, mode, 0, 0, 0, 0, &res);
283ea17a0f1SPali Rohár 	ret = res.a0;
284eb6a1fcbSGrzegorz Jaszczyk 
285ea17a0f1SPali Rohár 	switch (ret) {
286ea17a0f1SPali Rohár 	case SMCCC_RET_SUCCESS:
287ea17a0f1SPali Rohár 		return 0;
288ea17a0f1SPali Rohár 	case SMCCC_RET_NOT_SUPPORTED:
289ea17a0f1SPali Rohár 		return -EOPNOTSUPP;
290ea17a0f1SPali Rohár 	default:
291ea17a0f1SPali Rohár 		return -EINVAL;
292ea17a0f1SPali Rohár 	}
293eb6a1fcbSGrzegorz Jaszczyk }
294eb6a1fcbSGrzegorz Jaszczyk 
mvebu_comphy_get_mode(bool fw_mode,int lane,int port,enum phy_mode mode,int submode)295eb6a1fcbSGrzegorz Jaszczyk static int mvebu_comphy_get_mode(bool fw_mode, int lane, int port,
296cccc43b8SGrygorii Strashko 				 enum phy_mode mode, int submode)
297d0438bd6SAntoine Tenart {
298d0438bd6SAntoine Tenart 	int i, n = ARRAY_SIZE(mvebu_comphy_cp110_modes);
29965248876SGrzegorz Jaszczyk 	/* Ignore PCIe submode: it represents the width */
30065248876SGrzegorz Jaszczyk 	bool ignore_submode = (mode == PHY_MODE_PCIE);
3011eb9157aSMiquel Raynal 	const struct mvebu_comphy_conf *conf;
302d0438bd6SAntoine Tenart 
303d0438bd6SAntoine Tenart 	/* Unused PHY mux value is 0x0 */
304d0438bd6SAntoine Tenart 	if (mode == PHY_MODE_INVALID)
305d0438bd6SAntoine Tenart 		return 0;
306d0438bd6SAntoine Tenart 
307d0438bd6SAntoine Tenart 	for (i = 0; i < n; i++) {
3081eb9157aSMiquel Raynal 		conf = &mvebu_comphy_cp110_modes[i];
3091eb9157aSMiquel Raynal 		if (conf->lane == lane &&
3101eb9157aSMiquel Raynal 		    conf->port == port &&
3111eb9157aSMiquel Raynal 		    conf->mode == mode &&
31265248876SGrzegorz Jaszczyk 		    (conf->submode == submode || ignore_submode))
313d0438bd6SAntoine Tenart 			break;
314d0438bd6SAntoine Tenart 	}
315d0438bd6SAntoine Tenart 
316d0438bd6SAntoine Tenart 	if (i == n)
317d0438bd6SAntoine Tenart 		return -EINVAL;
318d0438bd6SAntoine Tenart 
319eb6a1fcbSGrzegorz Jaszczyk 	if (fw_mode)
3201eb9157aSMiquel Raynal 		return conf->fw_mode;
321eb6a1fcbSGrzegorz Jaszczyk 	else
3221eb9157aSMiquel Raynal 		return conf->mux;
323d0438bd6SAntoine Tenart }
324d0438bd6SAntoine Tenart 
mvebu_comphy_get_mux(int lane,int port,enum phy_mode mode,int submode)325eb6a1fcbSGrzegorz Jaszczyk static inline int mvebu_comphy_get_mux(int lane, int port,
326eb6a1fcbSGrzegorz Jaszczyk 				       enum phy_mode mode, int submode)
327eb6a1fcbSGrzegorz Jaszczyk {
328eb6a1fcbSGrzegorz Jaszczyk 	return mvebu_comphy_get_mode(false, lane, port, mode, submode);
329eb6a1fcbSGrzegorz Jaszczyk }
330eb6a1fcbSGrzegorz Jaszczyk 
mvebu_comphy_get_fw_mode(int lane,int port,enum phy_mode mode,int submode)331eb6a1fcbSGrzegorz Jaszczyk static inline int mvebu_comphy_get_fw_mode(int lane, int port,
332eb6a1fcbSGrzegorz Jaszczyk 					   enum phy_mode mode, int submode)
333eb6a1fcbSGrzegorz Jaszczyk {
334eb6a1fcbSGrzegorz Jaszczyk 	return mvebu_comphy_get_mode(true, lane, port, mode, submode);
335eb6a1fcbSGrzegorz Jaszczyk }
336eb6a1fcbSGrzegorz Jaszczyk 
mvebu_comphy_ethernet_init_reset(struct mvebu_comphy_lane * lane)337f2a857aaSMatt Pelland static int mvebu_comphy_ethernet_init_reset(struct mvebu_comphy_lane *lane)
338d0438bd6SAntoine Tenart {
339d0438bd6SAntoine Tenart 	struct mvebu_comphy_priv *priv = lane->priv;
340d0438bd6SAntoine Tenart 	u32 val;
341d0438bd6SAntoine Tenart 
342d0438bd6SAntoine Tenart 	regmap_read(priv->regmap, MVEBU_COMPHY_CONF1(lane->id), &val);
343d0438bd6SAntoine Tenart 	val &= ~MVEBU_COMPHY_CONF1_USB_PCIE;
344d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_CONF1_PWRUP;
345d0438bd6SAntoine Tenart 	regmap_write(priv->regmap, MVEBU_COMPHY_CONF1(lane->id), val);
346d0438bd6SAntoine Tenart 
347d0438bd6SAntoine Tenart 	/* Select baud rates and PLLs */
348d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG0(lane->id));
349d0438bd6SAntoine Tenart 	val &= ~(MVEBU_COMPHY_SERDES_CFG0_PU_PLL |
350d0438bd6SAntoine Tenart 		 MVEBU_COMPHY_SERDES_CFG0_PU_RX |
351d0438bd6SAntoine Tenart 		 MVEBU_COMPHY_SERDES_CFG0_PU_TX |
352d0438bd6SAntoine Tenart 		 MVEBU_COMPHY_SERDES_CFG0_HALF_BUS |
353d0438bd6SAntoine Tenart 		 MVEBU_COMPHY_SERDES_CFG0_GEN_RX(0xf) |
354f2a857aaSMatt Pelland 		 MVEBU_COMPHY_SERDES_CFG0_GEN_TX(0xf) |
355f2a857aaSMatt Pelland 		 MVEBU_COMPHY_SERDES_CFG0_RXAUI_MODE);
356f2a857aaSMatt Pelland 
357f2a857aaSMatt Pelland 	switch (lane->submode) {
358e0f909bcSRussell King 	case PHY_INTERFACE_MODE_10GBASER:
359d0438bd6SAntoine Tenart 		val |= MVEBU_COMPHY_SERDES_CFG0_GEN_RX(0xe) |
360d0438bd6SAntoine Tenart 		       MVEBU_COMPHY_SERDES_CFG0_GEN_TX(0xe);
361f2a857aaSMatt Pelland 		break;
362f2a857aaSMatt Pelland 	case PHY_INTERFACE_MODE_RXAUI:
363f2a857aaSMatt Pelland 		val |= MVEBU_COMPHY_SERDES_CFG0_GEN_RX(0xb) |
364f2a857aaSMatt Pelland 		       MVEBU_COMPHY_SERDES_CFG0_GEN_TX(0xb) |
365f2a857aaSMatt Pelland 		       MVEBU_COMPHY_SERDES_CFG0_RXAUI_MODE;
366f2a857aaSMatt Pelland 		break;
367f2a857aaSMatt Pelland 	case PHY_INTERFACE_MODE_2500BASEX:
3689ad8bd81SAntoine Tenart 		val |= MVEBU_COMPHY_SERDES_CFG0_GEN_RX(0x8) |
3699ad8bd81SAntoine Tenart 		       MVEBU_COMPHY_SERDES_CFG0_GEN_TX(0x8) |
3709ad8bd81SAntoine Tenart 		       MVEBU_COMPHY_SERDES_CFG0_HALF_BUS;
371f2a857aaSMatt Pelland 		break;
372f2a857aaSMatt Pelland 	case PHY_INTERFACE_MODE_SGMII:
373d0438bd6SAntoine Tenart 		val |= MVEBU_COMPHY_SERDES_CFG0_GEN_RX(0x6) |
374d0438bd6SAntoine Tenart 		       MVEBU_COMPHY_SERDES_CFG0_GEN_TX(0x6) |
375d0438bd6SAntoine Tenart 		       MVEBU_COMPHY_SERDES_CFG0_HALF_BUS;
376f2a857aaSMatt Pelland 		break;
377f2a857aaSMatt Pelland 	default:
378f2a857aaSMatt Pelland 		dev_err(priv->dev,
379f2a857aaSMatt Pelland 			"unsupported comphy submode (%d) on lane %d\n",
380f2a857aaSMatt Pelland 			lane->submode,
381f2a857aaSMatt Pelland 			lane->id);
382f2a857aaSMatt Pelland 		return -ENOTSUPP;
383f2a857aaSMatt Pelland 	}
384f2a857aaSMatt Pelland 
385d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG0(lane->id));
386d0438bd6SAntoine Tenart 
387f2a857aaSMatt Pelland 	if (lane->submode == PHY_INTERFACE_MODE_RXAUI) {
388f2a857aaSMatt Pelland 		regmap_read(priv->regmap, MVEBU_COMPHY_SD1_CTRL1, &val);
389f2a857aaSMatt Pelland 
390f2a857aaSMatt Pelland 		switch (lane->id) {
391f2a857aaSMatt Pelland 		case 2:
392f2a857aaSMatt Pelland 		case 3:
393f2a857aaSMatt Pelland 			val |= MVEBU_COMPHY_SD1_CTRL1_RXAUI0_EN;
394f2a857aaSMatt Pelland 			break;
395f2a857aaSMatt Pelland 		case 4:
396f2a857aaSMatt Pelland 		case 5:
397f2a857aaSMatt Pelland 			val |= MVEBU_COMPHY_SD1_CTRL1_RXAUI1_EN;
398f2a857aaSMatt Pelland 			break;
399f2a857aaSMatt Pelland 		default:
400f2a857aaSMatt Pelland 			dev_err(priv->dev,
401f2a857aaSMatt Pelland 				"RXAUI is not supported on comphy lane %d\n",
402f2a857aaSMatt Pelland 				lane->id);
403f2a857aaSMatt Pelland 			return -EINVAL;
404f2a857aaSMatt Pelland 		}
405f2a857aaSMatt Pelland 
406f2a857aaSMatt Pelland 		regmap_write(priv->regmap, MVEBU_COMPHY_SD1_CTRL1, val);
407f2a857aaSMatt Pelland 	}
408f2a857aaSMatt Pelland 
409d0438bd6SAntoine Tenart 	/* reset */
410d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));
411d0438bd6SAntoine Tenart 	val &= ~(MVEBU_COMPHY_SERDES_CFG1_RESET |
412d0438bd6SAntoine Tenart 		 MVEBU_COMPHY_SERDES_CFG1_CORE_RESET |
413d0438bd6SAntoine Tenart 		 MVEBU_COMPHY_SERDES_CFG1_RF_RESET);
414d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));
415d0438bd6SAntoine Tenart 
416d0438bd6SAntoine Tenart 	/* de-assert reset */
417d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));
418d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_SERDES_CFG1_RESET |
419d0438bd6SAntoine Tenart 	       MVEBU_COMPHY_SERDES_CFG1_CORE_RESET;
420d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));
421d0438bd6SAntoine Tenart 
422d0438bd6SAntoine Tenart 	/* wait until clocks are ready */
423d0438bd6SAntoine Tenart 	mdelay(1);
424d0438bd6SAntoine Tenart 
425d0438bd6SAntoine Tenart 	/* exlicitly disable 40B, the bits isn't clear on reset */
426d0438bd6SAntoine Tenart 	regmap_read(priv->regmap, MVEBU_COMPHY_CONF6(lane->id), &val);
427d0438bd6SAntoine Tenart 	val &= ~MVEBU_COMPHY_CONF6_40B;
428d0438bd6SAntoine Tenart 	regmap_write(priv->regmap, MVEBU_COMPHY_CONF6(lane->id), val);
429d0438bd6SAntoine Tenart 
430d0438bd6SAntoine Tenart 	/* refclk selection */
431d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_MISC_CTRL0(lane->id));
432d0438bd6SAntoine Tenart 	val &= ~MVEBU_COMPHY_MISC_CTRL0_REFCLK_SEL;
433e0f909bcSRussell King 	if (lane->submode == PHY_INTERFACE_MODE_10GBASER)
434d0438bd6SAntoine Tenart 		val |= MVEBU_COMPHY_MISC_CTRL0_ICP_FORCE;
435d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_MISC_CTRL0(lane->id));
436d0438bd6SAntoine Tenart 
437d0438bd6SAntoine Tenart 	/* power and pll selection */
438d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_PWRPLL_CTRL(lane->id));
439d0438bd6SAntoine Tenart 	val &= ~(MVEBU_COMPHY_PWRPLL_CTRL_RFREQ(0x1f) |
440d0438bd6SAntoine Tenart 		 MVEBU_COMPHY_PWRPLL_PHY_MODE(0x7));
441d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_PWRPLL_CTRL_RFREQ(0x1) |
442d0438bd6SAntoine Tenart 	       MVEBU_COMPHY_PWRPLL_PHY_MODE(0x4);
443d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_PWRPLL_CTRL(lane->id));
444d0438bd6SAntoine Tenart 
445d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_LOOPBACK(lane->id));
446d0438bd6SAntoine Tenart 	val &= ~MVEBU_COMPHY_LOOPBACK_DBUS_WIDTH(0x7);
447d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_LOOPBACK_DBUS_WIDTH(0x1);
448d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_LOOPBACK(lane->id));
449f2a857aaSMatt Pelland 
450f2a857aaSMatt Pelland 	return 0;
451d0438bd6SAntoine Tenart }
452d0438bd6SAntoine Tenart 
mvebu_comphy_init_plls(struct mvebu_comphy_lane * lane)453cccc43b8SGrygorii Strashko static int mvebu_comphy_init_plls(struct mvebu_comphy_lane *lane)
454d0438bd6SAntoine Tenart {
455d0438bd6SAntoine Tenart 	struct mvebu_comphy_priv *priv = lane->priv;
456d0438bd6SAntoine Tenart 	u32 val;
457d0438bd6SAntoine Tenart 
458d0438bd6SAntoine Tenart 	/* SERDES external config */
459d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG0(lane->id));
460d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_SERDES_CFG0_PU_PLL |
461d0438bd6SAntoine Tenart 	       MVEBU_COMPHY_SERDES_CFG0_PU_RX |
462d0438bd6SAntoine Tenart 	       MVEBU_COMPHY_SERDES_CFG0_PU_TX;
463d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG0(lane->id));
464d0438bd6SAntoine Tenart 
465d0438bd6SAntoine Tenart 	/* check rx/tx pll */
466d0438bd6SAntoine Tenart 	readl_poll_timeout(priv->base + MVEBU_COMPHY_SERDES_STATUS0(lane->id),
467d0438bd6SAntoine Tenart 			   val,
468d0438bd6SAntoine Tenart 			   val & (MVEBU_COMPHY_SERDES_STATUS0_RX_PLL_RDY |
469d0438bd6SAntoine Tenart 				  MVEBU_COMPHY_SERDES_STATUS0_TX_PLL_RDY),
470d0438bd6SAntoine Tenart 			   1000, 150000);
471d0438bd6SAntoine Tenart 	if (!(val & (MVEBU_COMPHY_SERDES_STATUS0_RX_PLL_RDY |
472d0438bd6SAntoine Tenart 		     MVEBU_COMPHY_SERDES_STATUS0_TX_PLL_RDY)))
473d0438bd6SAntoine Tenart 		return -ETIMEDOUT;
474d0438bd6SAntoine Tenart 
475d0438bd6SAntoine Tenart 	/* rx init */
476d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));
477d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_SERDES_CFG1_RX_INIT;
478d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));
479d0438bd6SAntoine Tenart 
480d0438bd6SAntoine Tenart 	/* check rx */
481d0438bd6SAntoine Tenart 	readl_poll_timeout(priv->base + MVEBU_COMPHY_SERDES_STATUS0(lane->id),
482d0438bd6SAntoine Tenart 			   val, val & MVEBU_COMPHY_SERDES_STATUS0_RX_INIT,
483d0438bd6SAntoine Tenart 			   1000, 10000);
484d0438bd6SAntoine Tenart 	if (!(val & MVEBU_COMPHY_SERDES_STATUS0_RX_INIT))
485d0438bd6SAntoine Tenart 		return -ETIMEDOUT;
486d0438bd6SAntoine Tenart 
487d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));
488d0438bd6SAntoine Tenart 	val &= ~MVEBU_COMPHY_SERDES_CFG1_RX_INIT;
489d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));
490d0438bd6SAntoine Tenart 
491d0438bd6SAntoine Tenart 	return 0;
492d0438bd6SAntoine Tenart }
493d0438bd6SAntoine Tenart 
mvebu_comphy_set_mode_sgmii(struct phy * phy)494cccc43b8SGrygorii Strashko static int mvebu_comphy_set_mode_sgmii(struct phy *phy)
495d0438bd6SAntoine Tenart {
496d0438bd6SAntoine Tenart 	struct mvebu_comphy_lane *lane = phy_get_drvdata(phy);
497d0438bd6SAntoine Tenart 	struct mvebu_comphy_priv *priv = lane->priv;
498d0438bd6SAntoine Tenart 	u32 val;
499f2a857aaSMatt Pelland 	int err;
500d0438bd6SAntoine Tenart 
501f2a857aaSMatt Pelland 	err = mvebu_comphy_ethernet_init_reset(lane);
502f2a857aaSMatt Pelland 	if (err)
503f2a857aaSMatt Pelland 		return err;
504d0438bd6SAntoine Tenart 
505d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_RX_CTRL1(lane->id));
506d0438bd6SAntoine Tenart 	val &= ~MVEBU_COMPHY_RX_CTRL1_CLK8T_EN;
507d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_RX_CTRL1_RXCLK2X_SEL;
508d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_RX_CTRL1(lane->id));
509d0438bd6SAntoine Tenart 
5105af67635SMatt Pelland 	val = readl(priv->base + MVEBU_COMPHY_DTL_CTRL(lane->id));
5115af67635SMatt Pelland 	val &= ~MVEBU_COMPHY_DTL_CTRL_DTL_FLOOP_EN;
5125af67635SMatt Pelland 	writel(val, priv->base + MVEBU_COMPHY_DTL_CTRL(lane->id));
513d0438bd6SAntoine Tenart 
514d0438bd6SAntoine Tenart 	regmap_read(priv->regmap, MVEBU_COMPHY_CONF1(lane->id), &val);
515d0438bd6SAntoine Tenart 	val &= ~MVEBU_COMPHY_CONF1_USB_PCIE;
516d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_CONF1_PWRUP;
517d0438bd6SAntoine Tenart 	regmap_write(priv->regmap, MVEBU_COMPHY_CONF1(lane->id), val);
518d0438bd6SAntoine Tenart 
519d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_GEN1_S0(lane->id));
520d0438bd6SAntoine Tenart 	val &= ~MVEBU_COMPHY_GEN1_S0_TX_EMPH(0xf);
521d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_GEN1_S0_TX_EMPH(0x1);
522d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_GEN1_S0(lane->id));
523d0438bd6SAntoine Tenart 
524cccc43b8SGrygorii Strashko 	return mvebu_comphy_init_plls(lane);
525d0438bd6SAntoine Tenart }
526d0438bd6SAntoine Tenart 
mvebu_comphy_set_mode_rxaui(struct phy * phy)527f2a857aaSMatt Pelland static int mvebu_comphy_set_mode_rxaui(struct phy *phy)
528f2a857aaSMatt Pelland {
529f2a857aaSMatt Pelland 	struct mvebu_comphy_lane *lane = phy_get_drvdata(phy);
530f2a857aaSMatt Pelland 	struct mvebu_comphy_priv *priv = lane->priv;
531f2a857aaSMatt Pelland 	u32 val;
532f2a857aaSMatt Pelland 	int err;
533f2a857aaSMatt Pelland 
534f2a857aaSMatt Pelland 	err = mvebu_comphy_ethernet_init_reset(lane);
535f2a857aaSMatt Pelland 	if (err)
536f2a857aaSMatt Pelland 		return err;
537f2a857aaSMatt Pelland 
538f2a857aaSMatt Pelland 	val = readl(priv->base + MVEBU_COMPHY_RX_CTRL1(lane->id));
539f2a857aaSMatt Pelland 	val |= MVEBU_COMPHY_RX_CTRL1_RXCLK2X_SEL |
540f2a857aaSMatt Pelland 	       MVEBU_COMPHY_RX_CTRL1_CLK8T_EN;
541f2a857aaSMatt Pelland 	writel(val, priv->base + MVEBU_COMPHY_RX_CTRL1(lane->id));
542f2a857aaSMatt Pelland 
5435af67635SMatt Pelland 	val = readl(priv->base + MVEBU_COMPHY_DTL_CTRL(lane->id));
5445af67635SMatt Pelland 	val |= MVEBU_COMPHY_DTL_CTRL_DTL_FLOOP_EN;
5455af67635SMatt Pelland 	writel(val, priv->base + MVEBU_COMPHY_DTL_CTRL(lane->id));
546f2a857aaSMatt Pelland 
547f2a857aaSMatt Pelland 	val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG2(lane->id));
548f2a857aaSMatt Pelland 	val |= MVEBU_COMPHY_SERDES_CFG2_DFE_EN;
549f2a857aaSMatt Pelland 	writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG2(lane->id));
550f2a857aaSMatt Pelland 
551f2a857aaSMatt Pelland 	val = readl(priv->base + MVEBU_COMPHY_DFE_RES(lane->id));
552f2a857aaSMatt Pelland 	val |= MVEBU_COMPHY_DFE_RES_FORCE_GEN_TBL;
553f2a857aaSMatt Pelland 	writel(val, priv->base + MVEBU_COMPHY_DFE_RES(lane->id));
554f2a857aaSMatt Pelland 
555f2a857aaSMatt Pelland 	val = readl(priv->base + MVEBU_COMPHY_GEN1_S0(lane->id));
556f2a857aaSMatt Pelland 	val &= ~MVEBU_COMPHY_GEN1_S0_TX_EMPH(0xf);
557f2a857aaSMatt Pelland 	val |= MVEBU_COMPHY_GEN1_S0_TX_EMPH(0xd);
558f2a857aaSMatt Pelland 	writel(val, priv->base + MVEBU_COMPHY_GEN1_S0(lane->id));
559f2a857aaSMatt Pelland 
560f2a857aaSMatt Pelland 	val = readl(priv->base + MVEBU_COMPHY_GEN1_S1(lane->id));
561f2a857aaSMatt Pelland 	val &= ~(MVEBU_COMPHY_GEN1_S1_RX_MUL_PI(0x7) |
562f2a857aaSMatt Pelland 		 MVEBU_COMPHY_GEN1_S1_RX_MUL_PF(0x7));
563f2a857aaSMatt Pelland 	val |= MVEBU_COMPHY_GEN1_S1_RX_MUL_PI(0x1) |
564f2a857aaSMatt Pelland 	       MVEBU_COMPHY_GEN1_S1_RX_MUL_PF(0x1) |
565f2a857aaSMatt Pelland 	       MVEBU_COMPHY_GEN1_S1_RX_DFE_EN;
566f2a857aaSMatt Pelland 	writel(val, priv->base + MVEBU_COMPHY_GEN1_S1(lane->id));
567f2a857aaSMatt Pelland 
568f2a857aaSMatt Pelland 	val = readl(priv->base + MVEBU_COMPHY_COEF(lane->id));
569f2a857aaSMatt Pelland 	val &= ~(MVEBU_COMPHY_COEF_DFE_EN | MVEBU_COMPHY_COEF_DFE_CTRL);
570f2a857aaSMatt Pelland 	writel(val, priv->base + MVEBU_COMPHY_COEF(lane->id));
571f2a857aaSMatt Pelland 
572f2a857aaSMatt Pelland 	val = readl(priv->base + MVEBU_COMPHY_GEN1_S4(lane->id));
573f2a857aaSMatt Pelland 	val &= ~MVEBU_COMPHY_GEN1_S4_DFE_RES(0x3);
574f2a857aaSMatt Pelland 	val |= MVEBU_COMPHY_GEN1_S4_DFE_RES(0x1);
575f2a857aaSMatt Pelland 	writel(val, priv->base + MVEBU_COMPHY_GEN1_S4(lane->id));
576f2a857aaSMatt Pelland 
577f2a857aaSMatt Pelland 	return mvebu_comphy_init_plls(lane);
578f2a857aaSMatt Pelland }
579f2a857aaSMatt Pelland 
mvebu_comphy_set_mode_10gbaser(struct phy * phy)580e0f909bcSRussell King static int mvebu_comphy_set_mode_10gbaser(struct phy *phy)
581d0438bd6SAntoine Tenart {
582d0438bd6SAntoine Tenart 	struct mvebu_comphy_lane *lane = phy_get_drvdata(phy);
583d0438bd6SAntoine Tenart 	struct mvebu_comphy_priv *priv = lane->priv;
584d0438bd6SAntoine Tenart 	u32 val;
585f2a857aaSMatt Pelland 	int err;
586d0438bd6SAntoine Tenart 
587f2a857aaSMatt Pelland 	err = mvebu_comphy_ethernet_init_reset(lane);
588f2a857aaSMatt Pelland 	if (err)
589f2a857aaSMatt Pelland 		return err;
590d0438bd6SAntoine Tenart 
591d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_RX_CTRL1(lane->id));
592d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_RX_CTRL1_RXCLK2X_SEL |
593d0438bd6SAntoine Tenart 	       MVEBU_COMPHY_RX_CTRL1_CLK8T_EN;
594d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_RX_CTRL1(lane->id));
595d0438bd6SAntoine Tenart 
5965af67635SMatt Pelland 	val = readl(priv->base + MVEBU_COMPHY_DTL_CTRL(lane->id));
5975af67635SMatt Pelland 	val |= MVEBU_COMPHY_DTL_CTRL_DTL_FLOOP_EN;
5985af67635SMatt Pelland 	writel(val, priv->base + MVEBU_COMPHY_DTL_CTRL(lane->id));
599d0438bd6SAntoine Tenart 
600d0438bd6SAntoine Tenart 	/* Speed divider */
601d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_SPEED_DIV(lane->id));
602d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_SPEED_DIV_TX_FORCE;
603d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_SPEED_DIV(lane->id));
604d0438bd6SAntoine Tenart 
605d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG2(lane->id));
606d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_SERDES_CFG2_DFE_EN;
607d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG2(lane->id));
608d0438bd6SAntoine Tenart 
609d0438bd6SAntoine Tenart 	/* DFE resolution */
610d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_DFE_RES(lane->id));
611d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_DFE_RES_FORCE_GEN_TBL;
612d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_DFE_RES(lane->id));
613d0438bd6SAntoine Tenart 
614d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_GEN1_S0(lane->id));
615d0438bd6SAntoine Tenart 	val &= ~(MVEBU_COMPHY_GEN1_S0_TX_AMP(0x1f) |
616d0438bd6SAntoine Tenart 		 MVEBU_COMPHY_GEN1_S0_TX_EMPH(0xf));
617d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_GEN1_S0_TX_AMP(0x1c) |
618d0438bd6SAntoine Tenart 	       MVEBU_COMPHY_GEN1_S0_TX_EMPH(0xe);
619d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_GEN1_S0(lane->id));
620d0438bd6SAntoine Tenart 
621d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_GEN1_S2(lane->id));
622d0438bd6SAntoine Tenart 	val &= ~MVEBU_COMPHY_GEN1_S2_TX_EMPH(0xf);
623d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_GEN1_S2_TX_EMPH_EN;
624d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_GEN1_S2(lane->id));
625d0438bd6SAntoine Tenart 
626d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_TX_SLEW_RATE(lane->id));
627d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_TX_SLEW_RATE_EMPH(0x3) |
628d0438bd6SAntoine Tenart 	       MVEBU_COMPHY_TX_SLEW_RATE_SLC(0x3f);
629d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_TX_SLEW_RATE(lane->id));
630d0438bd6SAntoine Tenart 
631d0438bd6SAntoine Tenart 	/* Impedance calibration */
632d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_IMP_CAL(lane->id));
633d0438bd6SAntoine Tenart 	val &= ~MVEBU_COMPHY_IMP_CAL_TX_EXT(0x1f);
634d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_IMP_CAL_TX_EXT(0xe) |
635d0438bd6SAntoine Tenart 	       MVEBU_COMPHY_IMP_CAL_TX_EXT_EN;
636d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_IMP_CAL(lane->id));
637d0438bd6SAntoine Tenart 
638d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_GEN1_S5(lane->id));
639d0438bd6SAntoine Tenart 	val &= ~MVEBU_COMPHY_GEN1_S5_ICP(0xf);
640d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_GEN1_S5(lane->id));
641d0438bd6SAntoine Tenart 
642d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_GEN1_S1(lane->id));
643d0438bd6SAntoine Tenart 	val &= ~(MVEBU_COMPHY_GEN1_S1_RX_MUL_PI(0x7) |
644d0438bd6SAntoine Tenart 		 MVEBU_COMPHY_GEN1_S1_RX_MUL_PF(0x7) |
645d0438bd6SAntoine Tenart 		 MVEBU_COMPHY_GEN1_S1_RX_MUL_FI(0x3) |
646d0438bd6SAntoine Tenart 		 MVEBU_COMPHY_GEN1_S1_RX_MUL_FF(0x3));
647d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_GEN1_S1_RX_DFE_EN |
648d0438bd6SAntoine Tenart 	       MVEBU_COMPHY_GEN1_S1_RX_MUL_PI(0x2) |
649d0438bd6SAntoine Tenart 	       MVEBU_COMPHY_GEN1_S1_RX_MUL_PF(0x2) |
650d0438bd6SAntoine Tenart 	       MVEBU_COMPHY_GEN1_S1_RX_MUL_FF(0x1) |
651d0438bd6SAntoine Tenart 	       MVEBU_COMPHY_GEN1_S1_RX_DIV(0x3);
652d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_GEN1_S1(lane->id));
653d0438bd6SAntoine Tenart 
654d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_COEF(lane->id));
655d0438bd6SAntoine Tenart 	val &= ~(MVEBU_COMPHY_COEF_DFE_EN | MVEBU_COMPHY_COEF_DFE_CTRL);
656d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_COEF(lane->id));
657d0438bd6SAntoine Tenart 
658d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_GEN1_S4(lane->id));
659d0438bd6SAntoine Tenart 	val &= ~MVEBU_COMPHY_GEN1_S4_DFE_RES(0x3);
660d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_GEN1_S4_DFE_RES(0x1);
661d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_GEN1_S4(lane->id));
662d0438bd6SAntoine Tenart 
663d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_GEN1_S3(lane->id));
664d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_GEN1_S3_FBCK_SEL;
665d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_GEN1_S3(lane->id));
666d0438bd6SAntoine Tenart 
667d0438bd6SAntoine Tenart 	/* rx training timer */
668d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_TRAINING5(lane->id));
669d0438bd6SAntoine Tenart 	val &= ~MVEBU_COMPHY_TRAINING5_RX_TIMER(0x3ff);
670d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_TRAINING5_RX_TIMER(0x13);
671d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_TRAINING5(lane->id));
672d0438bd6SAntoine Tenart 
673d0438bd6SAntoine Tenart 	/* tx train peak to peak hold */
674d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_TRAINING0(lane->id));
675d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_TRAINING0_P2P_HOLD;
676d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_TRAINING0(lane->id));
677d0438bd6SAntoine Tenart 
678d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_TX_PRESET(lane->id));
679d0438bd6SAntoine Tenart 	val &= ~MVEBU_COMPHY_TX_PRESET_INDEX(0xf);
680d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_TX_PRESET_INDEX(0x2);	/* preset coeff */
681d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_TX_PRESET(lane->id));
682d0438bd6SAntoine Tenart 
683d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_FRAME_DETECT3(lane->id));
684d0438bd6SAntoine Tenart 	val &= ~MVEBU_COMPHY_FRAME_DETECT3_LOST_TIMEOUT_EN;
685d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_FRAME_DETECT3(lane->id));
686d0438bd6SAntoine Tenart 
687d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_TX_TRAIN_PRESET(lane->id));
688d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_TX_TRAIN_PRESET_16B_AUTO_EN |
689d0438bd6SAntoine Tenart 	       MVEBU_COMPHY_TX_TRAIN_PRESET_PRBS11;
690d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_TX_TRAIN_PRESET(lane->id));
691d0438bd6SAntoine Tenart 
692d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_FRAME_DETECT0(lane->id));
693d0438bd6SAntoine Tenart 	val &= ~MVEBU_COMPHY_FRAME_DETECT0_PATN(0x1ff);
694d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_FRAME_DETECT0_PATN(0x88);
695d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_FRAME_DETECT0(lane->id));
696d0438bd6SAntoine Tenart 
697d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_DME(lane->id));
698d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_DME_ETH_MODE;
699d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_DME(lane->id));
700d0438bd6SAntoine Tenart 
701d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_VDD_CAL0(lane->id));
702d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_VDD_CAL0_CONT_MODE;
703d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_VDD_CAL0(lane->id));
704d0438bd6SAntoine Tenart 
705d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_SP_CALIB(lane->id));
706d0438bd6SAntoine Tenart 	val &= ~MVEBU_SP_CALIB_SAMPLER(0x3);
707d0438bd6SAntoine Tenart 	val |= MVEBU_SP_CALIB_SAMPLER(0x3) |
708d0438bd6SAntoine Tenart 	       MVEBU_SP_CALIB_SAMPLER_EN;
709d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_SP_CALIB(lane->id));
710d0438bd6SAntoine Tenart 	val &= ~MVEBU_SP_CALIB_SAMPLER_EN;
711d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_SP_CALIB(lane->id));
712d0438bd6SAntoine Tenart 
713d0438bd6SAntoine Tenart 	/* External rx regulator */
714d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_EXT_SELV(lane->id));
715d0438bd6SAntoine Tenart 	val &= ~MVEBU_COMPHY_EXT_SELV_RX_SAMPL(0x1f);
716d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_EXT_SELV_RX_SAMPL(0x1a);
717d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_EXT_SELV(lane->id));
718d0438bd6SAntoine Tenart 
719cccc43b8SGrygorii Strashko 	return mvebu_comphy_init_plls(lane);
720d0438bd6SAntoine Tenart }
721d0438bd6SAntoine Tenart 
mvebu_comphy_power_on_legacy(struct phy * phy)722eb6a1fcbSGrzegorz Jaszczyk static int mvebu_comphy_power_on_legacy(struct phy *phy)
723d0438bd6SAntoine Tenart {
724d0438bd6SAntoine Tenart 	struct mvebu_comphy_lane *lane = phy_get_drvdata(phy);
725d0438bd6SAntoine Tenart 	struct mvebu_comphy_priv *priv = lane->priv;
726caef3e0bSAntoine Tenart 	int ret, mux;
727caef3e0bSAntoine Tenart 	u32 val;
728d0438bd6SAntoine Tenart 
729cccc43b8SGrygorii Strashko 	mux = mvebu_comphy_get_mux(lane->id, lane->port,
730cccc43b8SGrygorii Strashko 				   lane->mode, lane->submode);
731d0438bd6SAntoine Tenart 	if (mux < 0)
732d0438bd6SAntoine Tenart 		return -ENOTSUPP;
733d0438bd6SAntoine Tenart 
73417fb745dSAntoine Tenart 	regmap_read(priv->regmap, MVEBU_COMPHY_PIPE_SELECTOR, &val);
73517fb745dSAntoine Tenart 	val &= ~(0xf << MVEBU_COMPHY_PIPE_SELECTOR_PIPE(lane->id));
73617fb745dSAntoine Tenart 	regmap_write(priv->regmap, MVEBU_COMPHY_PIPE_SELECTOR, val);
73717fb745dSAntoine Tenart 
738d0438bd6SAntoine Tenart 	regmap_read(priv->regmap, MVEBU_COMPHY_SELECTOR, &val);
739d0438bd6SAntoine Tenart 	val &= ~(0xf << MVEBU_COMPHY_SELECTOR_PHY(lane->id));
740d0438bd6SAntoine Tenart 	val |= mux << MVEBU_COMPHY_SELECTOR_PHY(lane->id);
741d0438bd6SAntoine Tenart 	regmap_write(priv->regmap, MVEBU_COMPHY_SELECTOR, val);
742d0438bd6SAntoine Tenart 
743cccc43b8SGrygorii Strashko 	switch (lane->submode) {
744cccc43b8SGrygorii Strashko 	case PHY_INTERFACE_MODE_SGMII:
745cccc43b8SGrygorii Strashko 	case PHY_INTERFACE_MODE_2500BASEX:
746cccc43b8SGrygorii Strashko 		ret = mvebu_comphy_set_mode_sgmii(phy);
747d0438bd6SAntoine Tenart 		break;
748f2a857aaSMatt Pelland 	case PHY_INTERFACE_MODE_RXAUI:
749f2a857aaSMatt Pelland 		ret = mvebu_comphy_set_mode_rxaui(phy);
750f2a857aaSMatt Pelland 		break;
751e0f909bcSRussell King 	case PHY_INTERFACE_MODE_10GBASER:
752e0f909bcSRussell King 		ret = mvebu_comphy_set_mode_10gbaser(phy);
753d0438bd6SAntoine Tenart 		break;
754d0438bd6SAntoine Tenart 	default:
755d0438bd6SAntoine Tenart 		return -ENOTSUPP;
756d0438bd6SAntoine Tenart 	}
757d0438bd6SAntoine Tenart 
758d0438bd6SAntoine Tenart 	/* digital reset */
759d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));
760d0438bd6SAntoine Tenart 	val |= MVEBU_COMPHY_SERDES_CFG1_RF_RESET;
761d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));
762d0438bd6SAntoine Tenart 
763d0438bd6SAntoine Tenart 	return ret;
764d0438bd6SAntoine Tenart }
765d0438bd6SAntoine Tenart 
mvebu_comphy_power_on(struct phy * phy)766eb6a1fcbSGrzegorz Jaszczyk static int mvebu_comphy_power_on(struct phy *phy)
767eb6a1fcbSGrzegorz Jaszczyk {
768eb6a1fcbSGrzegorz Jaszczyk 	struct mvebu_comphy_lane *lane = phy_get_drvdata(phy);
769eb6a1fcbSGrzegorz Jaszczyk 	struct mvebu_comphy_priv *priv = lane->priv;
770eb6a1fcbSGrzegorz Jaszczyk 	int fw_mode, fw_speed;
771eb6a1fcbSGrzegorz Jaszczyk 	u32 fw_param = 0;
772eb6a1fcbSGrzegorz Jaszczyk 	int ret;
773eb6a1fcbSGrzegorz Jaszczyk 
774eb6a1fcbSGrzegorz Jaszczyk 	fw_mode = mvebu_comphy_get_fw_mode(lane->id, lane->port,
775eb6a1fcbSGrzegorz Jaszczyk 					   lane->mode, lane->submode);
776eb6a1fcbSGrzegorz Jaszczyk 	if (fw_mode < 0)
777eb6a1fcbSGrzegorz Jaszczyk 		goto try_legacy;
778eb6a1fcbSGrzegorz Jaszczyk 
779eb6a1fcbSGrzegorz Jaszczyk 	/* Try SMC flow first */
780eb6a1fcbSGrzegorz Jaszczyk 	switch (lane->mode) {
781eb6a1fcbSGrzegorz Jaszczyk 	case PHY_MODE_ETHERNET:
782eb6a1fcbSGrzegorz Jaszczyk 		switch (lane->submode) {
783461324f0SGrzegorz Jaszczyk 		case PHY_INTERFACE_MODE_RXAUI:
784461324f0SGrzegorz Jaszczyk 			dev_dbg(priv->dev, "set lane %d to RXAUI mode\n",
785461324f0SGrzegorz Jaszczyk 				lane->id);
786461324f0SGrzegorz Jaszczyk 			fw_speed = 0;
787461324f0SGrzegorz Jaszczyk 			break;
788eb6a1fcbSGrzegorz Jaszczyk 		case PHY_INTERFACE_MODE_SGMII:
789eb6a1fcbSGrzegorz Jaszczyk 			dev_dbg(priv->dev, "set lane %d to 1000BASE-X mode\n",
790eb6a1fcbSGrzegorz Jaszczyk 				lane->id);
791eb6a1fcbSGrzegorz Jaszczyk 			fw_speed = COMPHY_FW_SPEED_1250;
792eb6a1fcbSGrzegorz Jaszczyk 			break;
793eb6a1fcbSGrzegorz Jaszczyk 		case PHY_INTERFACE_MODE_2500BASEX:
794eb6a1fcbSGrzegorz Jaszczyk 			dev_dbg(priv->dev, "set lane %d to 2500BASE-X mode\n",
795eb6a1fcbSGrzegorz Jaszczyk 				lane->id);
796eb6a1fcbSGrzegorz Jaszczyk 			fw_speed = COMPHY_FW_SPEED_3125;
797eb6a1fcbSGrzegorz Jaszczyk 			break;
798a1fb410aSMarek Behún 		case PHY_INTERFACE_MODE_5GBASER:
799a1fb410aSMarek Behún 			dev_dbg(priv->dev, "set lane %d to 5GBASE-R mode\n",
800a1fb410aSMarek Behún 				lane->id);
801a1fb410aSMarek Behún 			fw_speed = COMPHY_FW_SPEED_515625;
802a1fb410aSMarek Behún 			break;
803e0f909bcSRussell King 		case PHY_INTERFACE_MODE_10GBASER:
804e0f909bcSRussell King 			dev_dbg(priv->dev, "set lane %d to 10GBASE-R mode\n",
805eb6a1fcbSGrzegorz Jaszczyk 				lane->id);
806eb6a1fcbSGrzegorz Jaszczyk 			fw_speed = COMPHY_FW_SPEED_103125;
807eb6a1fcbSGrzegorz Jaszczyk 			break;
808eb6a1fcbSGrzegorz Jaszczyk 		default:
809eb6a1fcbSGrzegorz Jaszczyk 			dev_err(priv->dev, "unsupported Ethernet mode (%d)\n",
810eb6a1fcbSGrzegorz Jaszczyk 				lane->submode);
811eb6a1fcbSGrzegorz Jaszczyk 			return -ENOTSUPP;
812eb6a1fcbSGrzegorz Jaszczyk 		}
813eb6a1fcbSGrzegorz Jaszczyk 		fw_param = COMPHY_FW_PARAM_ETH(fw_mode, lane->port, fw_speed);
814eb6a1fcbSGrzegorz Jaszczyk 		break;
815c527a636SGrzegorz Jaszczyk 	case PHY_MODE_USB_HOST_SS:
816c527a636SGrzegorz Jaszczyk 	case PHY_MODE_USB_DEVICE_SS:
817c527a636SGrzegorz Jaszczyk 		dev_dbg(priv->dev, "set lane %d to USB3 mode\n", lane->id);
818c527a636SGrzegorz Jaszczyk 		fw_param = COMPHY_FW_PARAM(fw_mode, lane->port);
819c527a636SGrzegorz Jaszczyk 		break;
820ef0ac9f2SGrzegorz Jaszczyk 	case PHY_MODE_SATA:
821ef0ac9f2SGrzegorz Jaszczyk 		dev_dbg(priv->dev, "set lane %d to SATA mode\n", lane->id);
822ef0ac9f2SGrzegorz Jaszczyk 		fw_param = COMPHY_FW_PARAM(fw_mode, lane->port);
823ef0ac9f2SGrzegorz Jaszczyk 		break;
82465248876SGrzegorz Jaszczyk 	case PHY_MODE_PCIE:
82565248876SGrzegorz Jaszczyk 		dev_dbg(priv->dev, "set lane %d to PCIe mode (x%d)\n", lane->id,
82665248876SGrzegorz Jaszczyk 			lane->submode);
82765248876SGrzegorz Jaszczyk 		fw_param = COMPHY_FW_PARAM_PCIE(fw_mode, lane->port,
82865248876SGrzegorz Jaszczyk 						lane->submode);
82965248876SGrzegorz Jaszczyk 		break;
830eb6a1fcbSGrzegorz Jaszczyk 	default:
831eb6a1fcbSGrzegorz Jaszczyk 		dev_err(priv->dev, "unsupported PHY mode (%d)\n", lane->mode);
832eb6a1fcbSGrzegorz Jaszczyk 		return -ENOTSUPP;
833eb6a1fcbSGrzegorz Jaszczyk 	}
834eb6a1fcbSGrzegorz Jaszczyk 
835eb6a1fcbSGrzegorz Jaszczyk 	ret = mvebu_comphy_smc(COMPHY_SIP_POWER_ON, priv->cp_phys, lane->id,
836eb6a1fcbSGrzegorz Jaszczyk 			       fw_param);
837eb6a1fcbSGrzegorz Jaszczyk 	if (!ret)
838eb6a1fcbSGrzegorz Jaszczyk 		return ret;
839eb6a1fcbSGrzegorz Jaszczyk 
840ea17a0f1SPali Rohár 	if (ret == -EOPNOTSUPP)
841eb6a1fcbSGrzegorz Jaszczyk 		dev_err(priv->dev,
842eb6a1fcbSGrzegorz Jaszczyk 			"unsupported SMC call, try updating your firmware\n");
843eb6a1fcbSGrzegorz Jaszczyk 
844eb6a1fcbSGrzegorz Jaszczyk 	dev_warn(priv->dev,
845eb6a1fcbSGrzegorz Jaszczyk 		 "Firmware could not configure PHY %d with mode %d (ret: %d), trying legacy method\n",
846eb6a1fcbSGrzegorz Jaszczyk 		 lane->id, lane->mode, ret);
847eb6a1fcbSGrzegorz Jaszczyk 
848eb6a1fcbSGrzegorz Jaszczyk try_legacy:
849eb6a1fcbSGrzegorz Jaszczyk 	/* Fallback to Linux's implementation */
850eb6a1fcbSGrzegorz Jaszczyk 	return mvebu_comphy_power_on_legacy(phy);
851eb6a1fcbSGrzegorz Jaszczyk }
852eb6a1fcbSGrzegorz Jaszczyk 
mvebu_comphy_set_mode(struct phy * phy,enum phy_mode mode,int submode)85379a5a18aSGrygorii Strashko static int mvebu_comphy_set_mode(struct phy *phy,
85479a5a18aSGrygorii Strashko 				 enum phy_mode mode, int submode)
855d0438bd6SAntoine Tenart {
856d0438bd6SAntoine Tenart 	struct mvebu_comphy_lane *lane = phy_get_drvdata(phy);
857d0438bd6SAntoine Tenart 
858cccc43b8SGrygorii Strashko 	if (submode == PHY_INTERFACE_MODE_1000BASEX)
859cccc43b8SGrygorii Strashko 		submode = PHY_INTERFACE_MODE_SGMII;
860cccc43b8SGrygorii Strashko 
861eb6a1fcbSGrzegorz Jaszczyk 	if (mvebu_comphy_get_fw_mode(lane->id, lane->port, mode, submode) < 0)
862d0438bd6SAntoine Tenart 		return -EINVAL;
863d0438bd6SAntoine Tenart 
864d0438bd6SAntoine Tenart 	lane->mode = mode;
865cccc43b8SGrygorii Strashko 	lane->submode = submode;
86665248876SGrzegorz Jaszczyk 
86765248876SGrzegorz Jaszczyk 	/* PCIe submode represents the width */
86865248876SGrzegorz Jaszczyk 	if (mode == PHY_MODE_PCIE && !lane->submode)
86965248876SGrzegorz Jaszczyk 		lane->submode = 1;
87065248876SGrzegorz Jaszczyk 
871d0438bd6SAntoine Tenart 	return 0;
872d0438bd6SAntoine Tenart }
873d0438bd6SAntoine Tenart 
mvebu_comphy_power_off_legacy(struct phy * phy)874eb6a1fcbSGrzegorz Jaszczyk static int mvebu_comphy_power_off_legacy(struct phy *phy)
875d0438bd6SAntoine Tenart {
876d0438bd6SAntoine Tenart 	struct mvebu_comphy_lane *lane = phy_get_drvdata(phy);
877d0438bd6SAntoine Tenart 	struct mvebu_comphy_priv *priv = lane->priv;
878d0438bd6SAntoine Tenart 	u32 val;
879d0438bd6SAntoine Tenart 
880d0438bd6SAntoine Tenart 	val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));
881d0438bd6SAntoine Tenart 	val &= ~(MVEBU_COMPHY_SERDES_CFG1_RESET |
882d0438bd6SAntoine Tenart 		 MVEBU_COMPHY_SERDES_CFG1_CORE_RESET |
883d0438bd6SAntoine Tenart 		 MVEBU_COMPHY_SERDES_CFG1_RF_RESET);
884d0438bd6SAntoine Tenart 	writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));
885d0438bd6SAntoine Tenart 
886d0438bd6SAntoine Tenart 	regmap_read(priv->regmap, MVEBU_COMPHY_SELECTOR, &val);
887d0438bd6SAntoine Tenart 	val &= ~(0xf << MVEBU_COMPHY_SELECTOR_PHY(lane->id));
888d0438bd6SAntoine Tenart 	regmap_write(priv->regmap, MVEBU_COMPHY_SELECTOR, val);
889d0438bd6SAntoine Tenart 
89017fb745dSAntoine Tenart 	regmap_read(priv->regmap, MVEBU_COMPHY_PIPE_SELECTOR, &val);
89117fb745dSAntoine Tenart 	val &= ~(0xf << MVEBU_COMPHY_PIPE_SELECTOR_PIPE(lane->id));
89217fb745dSAntoine Tenart 	regmap_write(priv->regmap, MVEBU_COMPHY_PIPE_SELECTOR, val);
89317fb745dSAntoine Tenart 
894d0438bd6SAntoine Tenart 	return 0;
895d0438bd6SAntoine Tenart }
896d0438bd6SAntoine Tenart 
mvebu_comphy_power_off(struct phy * phy)897eb6a1fcbSGrzegorz Jaszczyk static int mvebu_comphy_power_off(struct phy *phy)
898eb6a1fcbSGrzegorz Jaszczyk {
899eb6a1fcbSGrzegorz Jaszczyk 	struct mvebu_comphy_lane *lane = phy_get_drvdata(phy);
900eb6a1fcbSGrzegorz Jaszczyk 	struct mvebu_comphy_priv *priv = lane->priv;
901eb6a1fcbSGrzegorz Jaszczyk 	int ret;
902eb6a1fcbSGrzegorz Jaszczyk 
903eb6a1fcbSGrzegorz Jaszczyk 	ret = mvebu_comphy_smc(COMPHY_SIP_POWER_OFF, priv->cp_phys,
904eb6a1fcbSGrzegorz Jaszczyk 			       lane->id, 0);
905eb6a1fcbSGrzegorz Jaszczyk 	if (!ret)
906eb6a1fcbSGrzegorz Jaszczyk 		return ret;
907eb6a1fcbSGrzegorz Jaszczyk 
908eb6a1fcbSGrzegorz Jaszczyk 	/* Fallback to Linux's implementation */
909eb6a1fcbSGrzegorz Jaszczyk 	return mvebu_comphy_power_off_legacy(phy);
910eb6a1fcbSGrzegorz Jaszczyk }
911eb6a1fcbSGrzegorz Jaszczyk 
912d0438bd6SAntoine Tenart static const struct phy_ops mvebu_comphy_ops = {
913d0438bd6SAntoine Tenart 	.power_on	= mvebu_comphy_power_on,
914d0438bd6SAntoine Tenart 	.power_off	= mvebu_comphy_power_off,
915d0438bd6SAntoine Tenart 	.set_mode	= mvebu_comphy_set_mode,
916d0438bd6SAntoine Tenart 	.owner		= THIS_MODULE,
917d0438bd6SAntoine Tenart };
918d0438bd6SAntoine Tenart 
mvebu_comphy_xlate(struct device * dev,struct of_phandle_args * args)919d0438bd6SAntoine Tenart static struct phy *mvebu_comphy_xlate(struct device *dev,
920d0438bd6SAntoine Tenart 				      struct of_phandle_args *args)
921d0438bd6SAntoine Tenart {
922d0438bd6SAntoine Tenart 	struct mvebu_comphy_lane *lane;
923d0438bd6SAntoine Tenart 	struct phy *phy;
924d0438bd6SAntoine Tenart 
925d0438bd6SAntoine Tenart 	if (WARN_ON(args->args[0] >= MVEBU_COMPHY_PORTS))
926d0438bd6SAntoine Tenart 		return ERR_PTR(-EINVAL);
927d0438bd6SAntoine Tenart 
928d0438bd6SAntoine Tenart 	phy = of_phy_simple_xlate(dev, args);
929d0438bd6SAntoine Tenart 	if (IS_ERR(phy))
930d0438bd6SAntoine Tenart 		return phy;
931d0438bd6SAntoine Tenart 
932d0438bd6SAntoine Tenart 	lane = phy_get_drvdata(phy);
933d0438bd6SAntoine Tenart 	lane->port = args->args[0];
934d0438bd6SAntoine Tenart 
935d0438bd6SAntoine Tenart 	return phy;
936d0438bd6SAntoine Tenart }
937d0438bd6SAntoine Tenart 
mvebu_comphy_init_clks(struct mvebu_comphy_priv * priv)9380629d57bSMiquel Raynal static int mvebu_comphy_init_clks(struct mvebu_comphy_priv *priv)
9390629d57bSMiquel Raynal {
9400629d57bSMiquel Raynal 	int ret;
9410629d57bSMiquel Raynal 
9420629d57bSMiquel Raynal 	priv->mg_domain_clk = devm_clk_get(priv->dev, "mg_clk");
9430629d57bSMiquel Raynal 	if (IS_ERR(priv->mg_domain_clk))
9440629d57bSMiquel Raynal 		return PTR_ERR(priv->mg_domain_clk);
9450629d57bSMiquel Raynal 
9460629d57bSMiquel Raynal 	ret = clk_prepare_enable(priv->mg_domain_clk);
9470629d57bSMiquel Raynal 	if (ret < 0)
9480629d57bSMiquel Raynal 		return ret;
9490629d57bSMiquel Raynal 
9500629d57bSMiquel Raynal 	priv->mg_core_clk = devm_clk_get(priv->dev, "mg_core_clk");
9510629d57bSMiquel Raynal 	if (IS_ERR(priv->mg_core_clk)) {
9520629d57bSMiquel Raynal 		ret = PTR_ERR(priv->mg_core_clk);
9530629d57bSMiquel Raynal 		goto dis_mg_domain_clk;
9540629d57bSMiquel Raynal 	}
9550629d57bSMiquel Raynal 
9560629d57bSMiquel Raynal 	ret = clk_prepare_enable(priv->mg_core_clk);
9570629d57bSMiquel Raynal 	if (ret < 0)
9580629d57bSMiquel Raynal 		goto dis_mg_domain_clk;
9590629d57bSMiquel Raynal 
9600629d57bSMiquel Raynal 	priv->axi_clk = devm_clk_get(priv->dev, "axi_clk");
9610629d57bSMiquel Raynal 	if (IS_ERR(priv->axi_clk)) {
9620629d57bSMiquel Raynal 		ret = PTR_ERR(priv->axi_clk);
9630629d57bSMiquel Raynal 		goto dis_mg_core_clk;
9640629d57bSMiquel Raynal 	}
9650629d57bSMiquel Raynal 
9660629d57bSMiquel Raynal 	ret = clk_prepare_enable(priv->axi_clk);
9670629d57bSMiquel Raynal 	if (ret < 0)
9680629d57bSMiquel Raynal 		goto dis_mg_core_clk;
9690629d57bSMiquel Raynal 
9700629d57bSMiquel Raynal 	return 0;
9710629d57bSMiquel Raynal 
9720629d57bSMiquel Raynal dis_mg_core_clk:
9730629d57bSMiquel Raynal 	clk_disable_unprepare(priv->mg_core_clk);
9740629d57bSMiquel Raynal 
9750629d57bSMiquel Raynal dis_mg_domain_clk:
9760629d57bSMiquel Raynal 	clk_disable_unprepare(priv->mg_domain_clk);
9770629d57bSMiquel Raynal 
9780629d57bSMiquel Raynal 	priv->mg_domain_clk = NULL;
9790629d57bSMiquel Raynal 	priv->mg_core_clk = NULL;
9800629d57bSMiquel Raynal 	priv->axi_clk = NULL;
9810629d57bSMiquel Raynal 
9820629d57bSMiquel Raynal 	return ret;
9830629d57bSMiquel Raynal };
9840629d57bSMiquel Raynal 
mvebu_comphy_disable_unprepare_clks(struct mvebu_comphy_priv * priv)9850629d57bSMiquel Raynal static void mvebu_comphy_disable_unprepare_clks(struct mvebu_comphy_priv *priv)
9860629d57bSMiquel Raynal {
9870629d57bSMiquel Raynal 	if (priv->axi_clk)
9880629d57bSMiquel Raynal 		clk_disable_unprepare(priv->axi_clk);
9890629d57bSMiquel Raynal 
9900629d57bSMiquel Raynal 	if (priv->mg_core_clk)
9910629d57bSMiquel Raynal 		clk_disable_unprepare(priv->mg_core_clk);
9920629d57bSMiquel Raynal 
9930629d57bSMiquel Raynal 	if (priv->mg_domain_clk)
9940629d57bSMiquel Raynal 		clk_disable_unprepare(priv->mg_domain_clk);
9950629d57bSMiquel Raynal }
9960629d57bSMiquel Raynal 
mvebu_comphy_probe(struct platform_device * pdev)997d0438bd6SAntoine Tenart static int mvebu_comphy_probe(struct platform_device *pdev)
998d0438bd6SAntoine Tenart {
999d0438bd6SAntoine Tenart 	struct mvebu_comphy_priv *priv;
1000d0438bd6SAntoine Tenart 	struct phy_provider *provider;
1001d0438bd6SAntoine Tenart 	struct device_node *child;
1002d0438bd6SAntoine Tenart 	struct resource *res;
10030629d57bSMiquel Raynal 	int ret;
1004d0438bd6SAntoine Tenart 
1005d0438bd6SAntoine Tenart 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
1006d0438bd6SAntoine Tenart 	if (!priv)
1007d0438bd6SAntoine Tenart 		return -ENOMEM;
1008d0438bd6SAntoine Tenart 
1009d0438bd6SAntoine Tenart 	priv->dev = &pdev->dev;
1010d0438bd6SAntoine Tenart 	priv->regmap =
1011d0438bd6SAntoine Tenart 		syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
1012d0438bd6SAntoine Tenart 						"marvell,system-controller");
1013d0438bd6SAntoine Tenart 	if (IS_ERR(priv->regmap))
1014d0438bd6SAntoine Tenart 		return PTR_ERR(priv->regmap);
101514626246SYangtao Li 	priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
1016c1c7acacSDan Carpenter 	if (IS_ERR(priv->base))
1017c1c7acacSDan Carpenter 		return PTR_ERR(priv->base);
1018d0438bd6SAntoine Tenart 
10190629d57bSMiquel Raynal 	/*
10200629d57bSMiquel Raynal 	 * Ignore error if clocks have not been initialized properly for DT
10210629d57bSMiquel Raynal 	 * compatibility reasons.
10220629d57bSMiquel Raynal 	 */
10230629d57bSMiquel Raynal 	ret = mvebu_comphy_init_clks(priv);
10240629d57bSMiquel Raynal 	if (ret) {
10250629d57bSMiquel Raynal 		if (ret == -EPROBE_DEFER)
10260629d57bSMiquel Raynal 			return ret;
10270629d57bSMiquel Raynal 		dev_warn(&pdev->dev, "cannot initialize clocks\n");
10280629d57bSMiquel Raynal 	}
10290629d57bSMiquel Raynal 
1030eb6a1fcbSGrzegorz Jaszczyk 	/*
1031eb6a1fcbSGrzegorz Jaszczyk 	 * Hack to retrieve a physical offset relative to this CP that will be
1032eb6a1fcbSGrzegorz Jaszczyk 	 * given to the firmware
1033eb6a1fcbSGrzegorz Jaszczyk 	 */
1034eb6a1fcbSGrzegorz Jaszczyk 	priv->cp_phys = res->start;
1035eb6a1fcbSGrzegorz Jaszczyk 
1036d0438bd6SAntoine Tenart 	for_each_available_child_of_node(pdev->dev.of_node, child) {
1037d0438bd6SAntoine Tenart 		struct mvebu_comphy_lane *lane;
1038d0438bd6SAntoine Tenart 		struct phy *phy;
1039d0438bd6SAntoine Tenart 		u32 val;
1040d0438bd6SAntoine Tenart 
1041d0438bd6SAntoine Tenart 		ret = of_property_read_u32(child, "reg", &val);
1042d0438bd6SAntoine Tenart 		if (ret < 0) {
1043d0438bd6SAntoine Tenart 			dev_err(&pdev->dev, "missing 'reg' property (%d)\n",
1044d0438bd6SAntoine Tenart 				ret);
1045d0438bd6SAntoine Tenart 			continue;
1046d0438bd6SAntoine Tenart 		}
1047d0438bd6SAntoine Tenart 
1048d0438bd6SAntoine Tenart 		if (val >= MVEBU_COMPHY_LANES) {
1049d0438bd6SAntoine Tenart 			dev_err(&pdev->dev, "invalid 'reg' property\n");
1050d0438bd6SAntoine Tenart 			continue;
1051d0438bd6SAntoine Tenart 		}
1052d0438bd6SAntoine Tenart 
1053d0438bd6SAntoine Tenart 		lane = devm_kzalloc(&pdev->dev, sizeof(*lane), GFP_KERNEL);
10545b43a20aSNishka Dasgupta 		if (!lane) {
10555b43a20aSNishka Dasgupta 			of_node_put(child);
10560629d57bSMiquel Raynal 			ret = -ENOMEM;
10570629d57bSMiquel Raynal 			goto disable_clks;
10585b43a20aSNishka Dasgupta 		}
1059d0438bd6SAntoine Tenart 
1060d0438bd6SAntoine Tenart 		phy = devm_phy_create(&pdev->dev, child, &mvebu_comphy_ops);
10615b43a20aSNishka Dasgupta 		if (IS_ERR(phy)) {
10625b43a20aSNishka Dasgupta 			of_node_put(child);
10630629d57bSMiquel Raynal 			ret = PTR_ERR(phy);
10640629d57bSMiquel Raynal 			goto disable_clks;
10655b43a20aSNishka Dasgupta 		}
1066d0438bd6SAntoine Tenart 
1067d0438bd6SAntoine Tenart 		lane->priv = priv;
1068d0438bd6SAntoine Tenart 		lane->mode = PHY_MODE_INVALID;
1069d4eda9d8SMiquel Raynal 		lane->submode = PHY_INTERFACE_MODE_NA;
1070d0438bd6SAntoine Tenart 		lane->id = val;
1071d0438bd6SAntoine Tenart 		lane->port = -1;
1072d0438bd6SAntoine Tenart 		phy_set_drvdata(phy, lane);
1073d0438bd6SAntoine Tenart 
1074d0438bd6SAntoine Tenart 		/*
10754e19a76eSMiquel Raynal 		 * All modes are supported in this driver so we could call
1076d0438bd6SAntoine Tenart 		 * mvebu_comphy_power_off(phy) here to avoid relying on the
10774e19a76eSMiquel Raynal 		 * bootloader/firmware configuration, but for compatibility
10784e19a76eSMiquel Raynal 		 * reasons we cannot de-configure the COMPHY without being sure
10794e19a76eSMiquel Raynal 		 * that the firmware is up-to-date and fully-featured.
1080d0438bd6SAntoine Tenart 		 */
1081d0438bd6SAntoine Tenart 	}
1082d0438bd6SAntoine Tenart 
1083d0438bd6SAntoine Tenart 	dev_set_drvdata(&pdev->dev, priv);
1084d0438bd6SAntoine Tenart 	provider = devm_of_phy_provider_register(&pdev->dev,
1085d0438bd6SAntoine Tenart 						 mvebu_comphy_xlate);
10860629d57bSMiquel Raynal 
1087d0438bd6SAntoine Tenart 	return PTR_ERR_OR_ZERO(provider);
10880629d57bSMiquel Raynal 
10890629d57bSMiquel Raynal disable_clks:
10900629d57bSMiquel Raynal 	mvebu_comphy_disable_unprepare_clks(priv);
10910629d57bSMiquel Raynal 
10920629d57bSMiquel Raynal 	return ret;
1093d0438bd6SAntoine Tenart }
1094d0438bd6SAntoine Tenart 
1095d0438bd6SAntoine Tenart static const struct of_device_id mvebu_comphy_of_match_table[] = {
1096d0438bd6SAntoine Tenart 	{ .compatible = "marvell,comphy-cp110" },
1097d0438bd6SAntoine Tenart 	{ },
1098d0438bd6SAntoine Tenart };
1099d0438bd6SAntoine Tenart MODULE_DEVICE_TABLE(of, mvebu_comphy_of_match_table);
1100d0438bd6SAntoine Tenart 
1101d0438bd6SAntoine Tenart static struct platform_driver mvebu_comphy_driver = {
1102d0438bd6SAntoine Tenart 	.probe	= mvebu_comphy_probe,
1103d0438bd6SAntoine Tenart 	.driver	= {
1104d0438bd6SAntoine Tenart 		.name = "mvebu-comphy",
1105d0438bd6SAntoine Tenart 		.of_match_table = mvebu_comphy_of_match_table,
1106d0438bd6SAntoine Tenart 	},
1107d0438bd6SAntoine Tenart };
1108d0438bd6SAntoine Tenart module_platform_driver(mvebu_comphy_driver);
1109d0438bd6SAntoine Tenart 
1110d0438bd6SAntoine Tenart MODULE_AUTHOR("Antoine Tenart <antoine.tenart@free-electrons.com>");
1111d0438bd6SAntoine Tenart MODULE_DESCRIPTION("Common PHY driver for mvebu SoCs");
1112d0438bd6SAntoine Tenart MODULE_LICENSE("GPL v2");
1113