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