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