1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2014 STMicroelectronics |
4 | * |
5 | * STMicroelectronics PHY driver MiPHY28lp (for SoC STiH407). |
6 | * |
7 | * Author: Alexandre Torgue <alexandre.torgue@st.com> |
8 | */ |
9 | |
10 | #include <linux/platform_device.h> |
11 | #include <linux/io.h> |
12 | #include <linux/iopoll.h> |
13 | #include <linux/kernel.h> |
14 | #include <linux/module.h> |
15 | #include <linux/of.h> |
16 | #include <linux/of_platform.h> |
17 | #include <linux/of_address.h> |
18 | #include <linux/clk.h> |
19 | #include <linux/phy/phy.h> |
20 | #include <linux/delay.h> |
21 | #include <linux/mfd/syscon.h> |
22 | #include <linux/regmap.h> |
23 | #include <linux/reset.h> |
24 | |
25 | #include <dt-bindings/phy/phy.h> |
26 | |
27 | /* MiPHY registers */ |
28 | #define MIPHY_CONF_RESET 0x00 |
29 | #define RST_APPLI_SW BIT(0) |
30 | #define RST_CONF_SW BIT(1) |
31 | #define RST_MACRO_SW BIT(2) |
32 | |
33 | #define MIPHY_RESET 0x01 |
34 | #define RST_PLL_SW BIT(0) |
35 | #define RST_COMP_SW BIT(2) |
36 | |
37 | #define MIPHY_STATUS_1 0x02 |
38 | #define PHY_RDY BIT(0) |
39 | #define HFC_RDY BIT(1) |
40 | #define HFC_PLL BIT(2) |
41 | |
42 | #define MIPHY_CONTROL 0x04 |
43 | #define TERM_EN_SW BIT(2) |
44 | #define DIS_LINK_RST BIT(3) |
45 | #define AUTO_RST_RX BIT(4) |
46 | #define PX_RX_POL BIT(5) |
47 | |
48 | #define MIPHY_BOUNDARY_SEL 0x0a |
49 | #define TX_SEL BIT(6) |
50 | #define SSC_SEL BIT(4) |
51 | #define GENSEL_SEL BIT(0) |
52 | |
53 | #define MIPHY_BOUNDARY_1 0x0b |
54 | #define MIPHY_BOUNDARY_2 0x0c |
55 | #define SSC_EN_SW BIT(2) |
56 | |
57 | #define MIPHY_PLL_CLKREF_FREQ 0x0d |
58 | #define MIPHY_SPEED 0x0e |
59 | #define TX_SPDSEL_80DEC 0 |
60 | #define TX_SPDSEL_40DEC 1 |
61 | #define TX_SPDSEL_20DEC 2 |
62 | #define RX_SPDSEL_80DEC 0 |
63 | #define RX_SPDSEL_40DEC (1 << 2) |
64 | #define RX_SPDSEL_20DEC (2 << 2) |
65 | |
66 | #define MIPHY_CONF 0x0f |
67 | #define MIPHY_CTRL_TEST_SEL 0x20 |
68 | #define MIPHY_CTRL_TEST_1 0x21 |
69 | #define MIPHY_CTRL_TEST_2 0x22 |
70 | #define MIPHY_CTRL_TEST_3 0x23 |
71 | #define MIPHY_CTRL_TEST_4 0x24 |
72 | #define MIPHY_FEEDBACK_TEST 0x25 |
73 | #define MIPHY_DEBUG_BUS 0x26 |
74 | #define MIPHY_DEBUG_STATUS_MSB 0x27 |
75 | #define MIPHY_DEBUG_STATUS_LSB 0x28 |
76 | #define MIPHY_PWR_RAIL_1 0x29 |
77 | #define MIPHY_PWR_RAIL_2 0x2a |
78 | #define MIPHY_SYNCHAR_CONTROL 0x30 |
79 | |
80 | #define MIPHY_COMP_FSM_1 0x3a |
81 | #define COMP_START BIT(6) |
82 | |
83 | #define MIPHY_COMP_FSM_6 0x3f |
84 | #define COMP_DONE BIT(7) |
85 | |
86 | #define MIPHY_COMP_POSTP 0x42 |
87 | #define MIPHY_TX_CTRL_1 0x49 |
88 | #define TX_REG_STEP_0V 0 |
89 | #define TX_REG_STEP_P_25MV 1 |
90 | #define TX_REG_STEP_P_50MV 2 |
91 | #define TX_REG_STEP_N_25MV 7 |
92 | #define TX_REG_STEP_N_50MV 6 |
93 | #define TX_REG_STEP_N_75MV 5 |
94 | |
95 | #define MIPHY_TX_CTRL_2 0x4a |
96 | #define TX_SLEW_SW_40_PS 0 |
97 | #define TX_SLEW_SW_80_PS 1 |
98 | #define TX_SLEW_SW_120_PS 2 |
99 | |
100 | #define MIPHY_TX_CTRL_3 0x4b |
101 | #define MIPHY_TX_CAL_MAN 0x4e |
102 | #define TX_SLEW_CAL_MAN_EN BIT(0) |
103 | |
104 | #define MIPHY_TST_BIAS_BOOST_2 0x62 |
105 | #define MIPHY_BIAS_BOOST_1 0x63 |
106 | #define MIPHY_BIAS_BOOST_2 0x64 |
107 | #define MIPHY_RX_DESBUFF_FDB_2 0x67 |
108 | #define MIPHY_RX_DESBUFF_FDB_3 0x68 |
109 | #define MIPHY_SIGDET_COMPENS1 0x69 |
110 | #define MIPHY_SIGDET_COMPENS2 0x6a |
111 | #define MIPHY_JITTER_PERIOD 0x6b |
112 | #define MIPHY_JITTER_AMPLITUDE_1 0x6c |
113 | #define MIPHY_JITTER_AMPLITUDE_2 0x6d |
114 | #define MIPHY_JITTER_AMPLITUDE_3 0x6e |
115 | #define MIPHY_RX_K_GAIN 0x78 |
116 | #define MIPHY_RX_BUFFER_CTRL 0x7a |
117 | #define VGA_GAIN BIT(0) |
118 | #define EQ_DC_GAIN BIT(2) |
119 | #define EQ_BOOST_GAIN BIT(3) |
120 | |
121 | #define MIPHY_RX_VGA_GAIN 0x7b |
122 | #define MIPHY_RX_EQU_GAIN_1 0x7f |
123 | #define MIPHY_RX_EQU_GAIN_2 0x80 |
124 | #define MIPHY_RX_EQU_GAIN_3 0x81 |
125 | #define MIPHY_RX_CAL_CTRL_1 0x97 |
126 | #define MIPHY_RX_CAL_CTRL_2 0x98 |
127 | |
128 | #define MIPHY_RX_CAL_OFFSET_CTRL 0x99 |
129 | #define CAL_OFFSET_VGA_64 (0x03 << 0) |
130 | #define CAL_OFFSET_THRESHOLD_64 (0x03 << 2) |
131 | #define VGA_OFFSET_POLARITY BIT(4) |
132 | #define OFFSET_COMPENSATION_EN BIT(6) |
133 | |
134 | #define MIPHY_RX_CAL_VGA_STEP 0x9a |
135 | #define MIPHY_RX_CAL_EYE_MIN 0x9d |
136 | #define MIPHY_RX_CAL_OPT_LENGTH 0x9f |
137 | #define MIPHY_RX_LOCK_CTRL_1 0xc1 |
138 | #define MIPHY_RX_LOCK_SETTINGS_OPT 0xc2 |
139 | #define MIPHY_RX_LOCK_STEP 0xc4 |
140 | |
141 | #define MIPHY_RX_SIGDET_SLEEP_OA 0xc9 |
142 | #define MIPHY_RX_SIGDET_SLEEP_SEL 0xca |
143 | #define MIPHY_RX_SIGDET_WAIT_SEL 0xcb |
144 | #define MIPHY_RX_SIGDET_DATA_SEL 0xcc |
145 | #define EN_ULTRA_LOW_POWER BIT(0) |
146 | #define EN_FIRST_HALF BIT(1) |
147 | #define EN_SECOND_HALF BIT(2) |
148 | #define EN_DIGIT_SIGNAL_CHECK BIT(3) |
149 | |
150 | #define MIPHY_RX_POWER_CTRL_1 0xcd |
151 | #define MIPHY_RX_POWER_CTRL_2 0xce |
152 | #define MIPHY_PLL_CALSET_CTRL 0xd3 |
153 | #define MIPHY_PLL_CALSET_1 0xd4 |
154 | #define MIPHY_PLL_CALSET_2 0xd5 |
155 | #define MIPHY_PLL_CALSET_3 0xd6 |
156 | #define MIPHY_PLL_CALSET_4 0xd7 |
157 | #define MIPHY_PLL_SBR_1 0xe3 |
158 | #define SET_NEW_CHANGE BIT(1) |
159 | |
160 | #define MIPHY_PLL_SBR_2 0xe4 |
161 | #define MIPHY_PLL_SBR_3 0xe5 |
162 | #define MIPHY_PLL_SBR_4 0xe6 |
163 | #define MIPHY_PLL_COMMON_MISC_2 0xe9 |
164 | #define START_ACT_FILT BIT(6) |
165 | |
166 | #define MIPHY_PLL_SPAREIN 0xeb |
167 | |
168 | /* |
169 | * On STiH407 the glue logic can be different among MiPHY devices; for example: |
170 | * MiPHY0: OSC_FORCE_EXT means: |
171 | * 0: 30MHz crystal clk - 1: 100MHz ext clk routed through MiPHY1 |
172 | * MiPHY1: OSC_FORCE_EXT means: |
173 | * 1: 30MHz crystal clk - 0: 100MHz ext clk routed through MiPHY1 |
174 | * Some devices have not the possibility to check if the osc is ready. |
175 | */ |
176 | #define MIPHY_OSC_FORCE_EXT BIT(3) |
177 | #define MIPHY_OSC_RDY BIT(5) |
178 | |
179 | #define MIPHY_CTRL_MASK 0x0f |
180 | #define MIPHY_CTRL_DEFAULT 0 |
181 | #define MIPHY_CTRL_SYNC_D_EN BIT(2) |
182 | |
183 | /* SATA / PCIe defines */ |
184 | #define SATA_CTRL_MASK 0x07 |
185 | #define PCIE_CTRL_MASK 0xff |
186 | #define SATA_CTRL_SELECT_SATA 1 |
187 | #define SATA_CTRL_SELECT_PCIE 0 |
188 | #define SYSCFG_PCIE_PCIE_VAL 0x80 |
189 | #define SATA_SPDMODE 1 |
190 | |
191 | #define MIPHY_SATA_BANK_NB 3 |
192 | #define MIPHY_PCIE_BANK_NB 2 |
193 | |
194 | enum { |
195 | SYSCFG_CTRL, |
196 | SYSCFG_STATUS, |
197 | SYSCFG_PCI, |
198 | SYSCFG_SATA, |
199 | SYSCFG_REG_MAX, |
200 | }; |
201 | |
202 | struct miphy28lp_phy { |
203 | struct phy *phy; |
204 | struct miphy28lp_dev *phydev; |
205 | void __iomem *base; |
206 | void __iomem *pipebase; |
207 | |
208 | bool osc_force_ext; |
209 | bool osc_rdy; |
210 | bool px_rx_pol_inv; |
211 | bool ssc; |
212 | bool tx_impedance; |
213 | |
214 | struct reset_control *miphy_rst; |
215 | |
216 | u32 sata_gen; |
217 | |
218 | /* Sysconfig registers offsets needed to configure the device */ |
219 | u32 syscfg_reg[SYSCFG_REG_MAX]; |
220 | u8 type; |
221 | }; |
222 | |
223 | struct miphy28lp_dev { |
224 | struct device *dev; |
225 | struct regmap *regmap; |
226 | struct mutex miphy_mutex; |
227 | struct miphy28lp_phy **phys; |
228 | int nphys; |
229 | }; |
230 | |
231 | struct miphy_initval { |
232 | u16 reg; |
233 | u16 val; |
234 | }; |
235 | |
236 | enum miphy_sata_gen { SATA_GEN1, SATA_GEN2, SATA_GEN3 }; |
237 | |
238 | static char *PHY_TYPE_name[] = { "sata-up" , "pcie-up" , "" , "usb3-up" }; |
239 | |
240 | struct pll_ratio { |
241 | int clk_ref; |
242 | int calset_1; |
243 | int calset_2; |
244 | int calset_3; |
245 | int calset_4; |
246 | int cal_ctrl; |
247 | }; |
248 | |
249 | static struct pll_ratio sata_pll_ratio = { |
250 | .clk_ref = 0x1e, |
251 | .calset_1 = 0xc8, |
252 | .calset_2 = 0x00, |
253 | .calset_3 = 0x00, |
254 | .calset_4 = 0x00, |
255 | .cal_ctrl = 0x00, |
256 | }; |
257 | |
258 | static struct pll_ratio pcie_pll_ratio = { |
259 | .clk_ref = 0x1e, |
260 | .calset_1 = 0xa6, |
261 | .calset_2 = 0xaa, |
262 | .calset_3 = 0xaa, |
263 | .calset_4 = 0x00, |
264 | .cal_ctrl = 0x00, |
265 | }; |
266 | |
267 | static struct pll_ratio usb3_pll_ratio = { |
268 | .clk_ref = 0x1e, |
269 | .calset_1 = 0xa6, |
270 | .calset_2 = 0xaa, |
271 | .calset_3 = 0xaa, |
272 | .calset_4 = 0x04, |
273 | .cal_ctrl = 0x00, |
274 | }; |
275 | |
276 | struct miphy28lp_pll_gen { |
277 | int bank; |
278 | int speed; |
279 | int bias_boost_1; |
280 | int bias_boost_2; |
281 | int tx_ctrl_1; |
282 | int tx_ctrl_2; |
283 | int tx_ctrl_3; |
284 | int rx_k_gain; |
285 | int rx_vga_gain; |
286 | int rx_equ_gain_1; |
287 | int rx_equ_gain_2; |
288 | int rx_equ_gain_3; |
289 | int rx_buff_ctrl; |
290 | }; |
291 | |
292 | static struct miphy28lp_pll_gen sata_pll_gen[] = { |
293 | { |
294 | .bank = 0x00, |
295 | .speed = TX_SPDSEL_80DEC | RX_SPDSEL_80DEC, |
296 | .bias_boost_1 = 0x00, |
297 | .bias_boost_2 = 0xae, |
298 | .tx_ctrl_2 = 0x53, |
299 | .tx_ctrl_3 = 0x00, |
300 | .rx_buff_ctrl = EQ_BOOST_GAIN | EQ_DC_GAIN | VGA_GAIN, |
301 | .rx_vga_gain = 0x00, |
302 | .rx_equ_gain_1 = 0x7d, |
303 | .rx_equ_gain_2 = 0x56, |
304 | .rx_equ_gain_3 = 0x00, |
305 | }, |
306 | { |
307 | .bank = 0x01, |
308 | .speed = TX_SPDSEL_40DEC | RX_SPDSEL_40DEC, |
309 | .bias_boost_1 = 0x00, |
310 | .bias_boost_2 = 0xae, |
311 | .tx_ctrl_2 = 0x72, |
312 | .tx_ctrl_3 = 0x20, |
313 | .rx_buff_ctrl = EQ_BOOST_GAIN | EQ_DC_GAIN | VGA_GAIN, |
314 | .rx_vga_gain = 0x00, |
315 | .rx_equ_gain_1 = 0x7d, |
316 | .rx_equ_gain_2 = 0x56, |
317 | .rx_equ_gain_3 = 0x00, |
318 | }, |
319 | { |
320 | .bank = 0x02, |
321 | .speed = TX_SPDSEL_20DEC | RX_SPDSEL_20DEC, |
322 | .bias_boost_1 = 0x00, |
323 | .bias_boost_2 = 0xae, |
324 | .tx_ctrl_2 = 0xc0, |
325 | .tx_ctrl_3 = 0x20, |
326 | .rx_buff_ctrl = EQ_BOOST_GAIN | EQ_DC_GAIN | VGA_GAIN, |
327 | .rx_vga_gain = 0x00, |
328 | .rx_equ_gain_1 = 0x7d, |
329 | .rx_equ_gain_2 = 0x56, |
330 | .rx_equ_gain_3 = 0x00, |
331 | }, |
332 | }; |
333 | |
334 | static struct miphy28lp_pll_gen pcie_pll_gen[] = { |
335 | { |
336 | .bank = 0x00, |
337 | .speed = TX_SPDSEL_40DEC | RX_SPDSEL_40DEC, |
338 | .bias_boost_1 = 0x00, |
339 | .bias_boost_2 = 0xa5, |
340 | .tx_ctrl_1 = TX_REG_STEP_N_25MV, |
341 | .tx_ctrl_2 = 0x71, |
342 | .tx_ctrl_3 = 0x60, |
343 | .rx_k_gain = 0x98, |
344 | .rx_buff_ctrl = EQ_BOOST_GAIN | EQ_DC_GAIN | VGA_GAIN, |
345 | .rx_vga_gain = 0x00, |
346 | .rx_equ_gain_1 = 0x79, |
347 | .rx_equ_gain_2 = 0x56, |
348 | }, |
349 | { |
350 | .bank = 0x01, |
351 | .speed = TX_SPDSEL_20DEC | RX_SPDSEL_20DEC, |
352 | .bias_boost_1 = 0x00, |
353 | .bias_boost_2 = 0xa5, |
354 | .tx_ctrl_1 = TX_REG_STEP_N_25MV, |
355 | .tx_ctrl_2 = 0x70, |
356 | .tx_ctrl_3 = 0x60, |
357 | .rx_k_gain = 0xcc, |
358 | .rx_buff_ctrl = EQ_BOOST_GAIN | EQ_DC_GAIN | VGA_GAIN, |
359 | .rx_vga_gain = 0x00, |
360 | .rx_equ_gain_1 = 0x78, |
361 | .rx_equ_gain_2 = 0x07, |
362 | }, |
363 | }; |
364 | |
365 | static inline void miphy28lp_set_reset(struct miphy28lp_phy *miphy_phy) |
366 | { |
367 | void __iomem *base = miphy_phy->base; |
368 | u8 val; |
369 | |
370 | /* Putting Macro in reset */ |
371 | writeb_relaxed(RST_APPLI_SW, base + MIPHY_CONF_RESET); |
372 | |
373 | val = RST_APPLI_SW | RST_CONF_SW; |
374 | writeb_relaxed(val, base + MIPHY_CONF_RESET); |
375 | |
376 | writeb_relaxed(RST_APPLI_SW, base + MIPHY_CONF_RESET); |
377 | |
378 | /* Bringing the MIPHY-CPU registers out of reset */ |
379 | if (miphy_phy->type == PHY_TYPE_PCIE) { |
380 | val = AUTO_RST_RX | TERM_EN_SW; |
381 | writeb_relaxed(val, base + MIPHY_CONTROL); |
382 | } else { |
383 | val = AUTO_RST_RX | TERM_EN_SW | DIS_LINK_RST; |
384 | writeb_relaxed(val, base + MIPHY_CONTROL); |
385 | } |
386 | } |
387 | |
388 | static inline void miphy28lp_pll_calibration(struct miphy28lp_phy *miphy_phy, |
389 | struct pll_ratio *pll_ratio) |
390 | { |
391 | void __iomem *base = miphy_phy->base; |
392 | u8 val; |
393 | |
394 | /* Applying PLL Settings */ |
395 | writeb_relaxed(0x1d, base + MIPHY_PLL_SPAREIN); |
396 | writeb_relaxed(pll_ratio->clk_ref, base + MIPHY_PLL_CLKREF_FREQ); |
397 | |
398 | /* PLL Ratio */ |
399 | writeb_relaxed(pll_ratio->calset_1, base + MIPHY_PLL_CALSET_1); |
400 | writeb_relaxed(pll_ratio->calset_2, base + MIPHY_PLL_CALSET_2); |
401 | writeb_relaxed(pll_ratio->calset_3, base + MIPHY_PLL_CALSET_3); |
402 | writeb_relaxed(pll_ratio->calset_4, base + MIPHY_PLL_CALSET_4); |
403 | writeb_relaxed(pll_ratio->cal_ctrl, base + MIPHY_PLL_CALSET_CTRL); |
404 | |
405 | writeb_relaxed(TX_SEL, base + MIPHY_BOUNDARY_SEL); |
406 | |
407 | val = (0x68 << 1) | TX_SLEW_CAL_MAN_EN; |
408 | writeb_relaxed(val, base + MIPHY_TX_CAL_MAN); |
409 | |
410 | val = VGA_OFFSET_POLARITY | CAL_OFFSET_THRESHOLD_64 | CAL_OFFSET_VGA_64; |
411 | |
412 | if (miphy_phy->type != PHY_TYPE_SATA) |
413 | val |= OFFSET_COMPENSATION_EN; |
414 | |
415 | writeb_relaxed(val, base + MIPHY_RX_CAL_OFFSET_CTRL); |
416 | |
417 | if (miphy_phy->type == PHY_TYPE_USB3) { |
418 | writeb_relaxed(0x00, base + MIPHY_CONF); |
419 | writeb_relaxed(0x70, base + MIPHY_RX_LOCK_STEP); |
420 | writeb_relaxed(EN_FIRST_HALF, base + MIPHY_RX_SIGDET_SLEEP_OA); |
421 | writeb_relaxed(EN_FIRST_HALF, base + MIPHY_RX_SIGDET_SLEEP_SEL); |
422 | writeb_relaxed(EN_FIRST_HALF, base + MIPHY_RX_SIGDET_WAIT_SEL); |
423 | |
424 | val = EN_DIGIT_SIGNAL_CHECK | EN_FIRST_HALF; |
425 | writeb_relaxed(val, base + MIPHY_RX_SIGDET_DATA_SEL); |
426 | } |
427 | |
428 | } |
429 | |
430 | static inline void miphy28lp_sata_config_gen(struct miphy28lp_phy *miphy_phy) |
431 | { |
432 | void __iomem *base = miphy_phy->base; |
433 | int i; |
434 | |
435 | for (i = 0; i < ARRAY_SIZE(sata_pll_gen); i++) { |
436 | struct miphy28lp_pll_gen *gen = &sata_pll_gen[i]; |
437 | |
438 | /* Banked settings */ |
439 | writeb_relaxed(gen->bank, base + MIPHY_CONF); |
440 | writeb_relaxed(gen->speed, base + MIPHY_SPEED); |
441 | writeb_relaxed(gen->bias_boost_1, base + MIPHY_BIAS_BOOST_1); |
442 | writeb_relaxed(gen->bias_boost_2, base + MIPHY_BIAS_BOOST_2); |
443 | |
444 | /* TX buffer Settings */ |
445 | writeb_relaxed(gen->tx_ctrl_2, base + MIPHY_TX_CTRL_2); |
446 | writeb_relaxed(gen->tx_ctrl_3, base + MIPHY_TX_CTRL_3); |
447 | |
448 | /* RX Buffer Settings */ |
449 | writeb_relaxed(gen->rx_buff_ctrl, base + MIPHY_RX_BUFFER_CTRL); |
450 | writeb_relaxed(gen->rx_vga_gain, base + MIPHY_RX_VGA_GAIN); |
451 | writeb_relaxed(gen->rx_equ_gain_1, base + MIPHY_RX_EQU_GAIN_1); |
452 | writeb_relaxed(gen->rx_equ_gain_2, base + MIPHY_RX_EQU_GAIN_2); |
453 | writeb_relaxed(gen->rx_equ_gain_3, base + MIPHY_RX_EQU_GAIN_3); |
454 | } |
455 | } |
456 | |
457 | static inline void miphy28lp_pcie_config_gen(struct miphy28lp_phy *miphy_phy) |
458 | { |
459 | void __iomem *base = miphy_phy->base; |
460 | int i; |
461 | |
462 | for (i = 0; i < ARRAY_SIZE(pcie_pll_gen); i++) { |
463 | struct miphy28lp_pll_gen *gen = &pcie_pll_gen[i]; |
464 | |
465 | /* Banked settings */ |
466 | writeb_relaxed(gen->bank, base + MIPHY_CONF); |
467 | writeb_relaxed(gen->speed, base + MIPHY_SPEED); |
468 | writeb_relaxed(gen->bias_boost_1, base + MIPHY_BIAS_BOOST_1); |
469 | writeb_relaxed(gen->bias_boost_2, base + MIPHY_BIAS_BOOST_2); |
470 | |
471 | /* TX buffer Settings */ |
472 | writeb_relaxed(gen->tx_ctrl_1, base + MIPHY_TX_CTRL_1); |
473 | writeb_relaxed(gen->tx_ctrl_2, base + MIPHY_TX_CTRL_2); |
474 | writeb_relaxed(gen->tx_ctrl_3, base + MIPHY_TX_CTRL_3); |
475 | |
476 | writeb_relaxed(gen->rx_k_gain, base + MIPHY_RX_K_GAIN); |
477 | |
478 | /* RX Buffer Settings */ |
479 | writeb_relaxed(gen->rx_buff_ctrl, base + MIPHY_RX_BUFFER_CTRL); |
480 | writeb_relaxed(gen->rx_vga_gain, base + MIPHY_RX_VGA_GAIN); |
481 | writeb_relaxed(gen->rx_equ_gain_1, base + MIPHY_RX_EQU_GAIN_1); |
482 | writeb_relaxed(gen->rx_equ_gain_2, base + MIPHY_RX_EQU_GAIN_2); |
483 | } |
484 | } |
485 | |
486 | static inline int miphy28lp_wait_compensation(struct miphy28lp_phy *miphy_phy) |
487 | { |
488 | u8 val; |
489 | |
490 | /* Waiting for Compensation to complete */ |
491 | return readb_relaxed_poll_timeout(miphy_phy->base + MIPHY_COMP_FSM_6, |
492 | val, val & COMP_DONE, 1, 5 * USEC_PER_SEC); |
493 | } |
494 | |
495 | |
496 | static inline int miphy28lp_compensation(struct miphy28lp_phy *miphy_phy, |
497 | struct pll_ratio *pll_ratio) |
498 | { |
499 | void __iomem *base = miphy_phy->base; |
500 | |
501 | /* Poll for HFC ready after reset release */ |
502 | /* Compensation measurement */ |
503 | writeb_relaxed(RST_PLL_SW | RST_COMP_SW, base + MIPHY_RESET); |
504 | |
505 | writeb_relaxed(0x00, base + MIPHY_PLL_COMMON_MISC_2); |
506 | writeb_relaxed(pll_ratio->clk_ref, base + MIPHY_PLL_CLKREF_FREQ); |
507 | writeb_relaxed(COMP_START, base + MIPHY_COMP_FSM_1); |
508 | |
509 | if (miphy_phy->type == PHY_TYPE_PCIE) |
510 | writeb_relaxed(RST_PLL_SW, base + MIPHY_RESET); |
511 | |
512 | writeb_relaxed(0x00, base + MIPHY_RESET); |
513 | writeb_relaxed(START_ACT_FILT, base + MIPHY_PLL_COMMON_MISC_2); |
514 | writeb_relaxed(SET_NEW_CHANGE, base + MIPHY_PLL_SBR_1); |
515 | |
516 | /* TX compensation offset to re-center TX impedance */ |
517 | writeb_relaxed(0x00, base + MIPHY_COMP_POSTP); |
518 | |
519 | if (miphy_phy->type == PHY_TYPE_PCIE) |
520 | return miphy28lp_wait_compensation(miphy_phy); |
521 | |
522 | return 0; |
523 | } |
524 | |
525 | static inline void miphy28_usb3_miphy_reset(struct miphy28lp_phy *miphy_phy) |
526 | { |
527 | void __iomem *base = miphy_phy->base; |
528 | u8 val; |
529 | |
530 | /* MIPHY Reset */ |
531 | writeb_relaxed(RST_APPLI_SW, base + MIPHY_CONF_RESET); |
532 | writeb_relaxed(0x00, base + MIPHY_CONF_RESET); |
533 | writeb_relaxed(RST_COMP_SW, base + MIPHY_RESET); |
534 | |
535 | val = RST_COMP_SW | RST_PLL_SW; |
536 | writeb_relaxed(val, base + MIPHY_RESET); |
537 | |
538 | writeb_relaxed(0x00, base + MIPHY_PLL_COMMON_MISC_2); |
539 | writeb_relaxed(0x1e, base + MIPHY_PLL_CLKREF_FREQ); |
540 | writeb_relaxed(COMP_START, base + MIPHY_COMP_FSM_1); |
541 | writeb_relaxed(RST_PLL_SW, base + MIPHY_RESET); |
542 | writeb_relaxed(0x00, base + MIPHY_RESET); |
543 | writeb_relaxed(START_ACT_FILT, base + MIPHY_PLL_COMMON_MISC_2); |
544 | writeb_relaxed(0x00, base + MIPHY_CONF); |
545 | writeb_relaxed(0x00, base + MIPHY_BOUNDARY_1); |
546 | writeb_relaxed(0x00, base + MIPHY_TST_BIAS_BOOST_2); |
547 | writeb_relaxed(0x00, base + MIPHY_CONF); |
548 | writeb_relaxed(SET_NEW_CHANGE, base + MIPHY_PLL_SBR_1); |
549 | writeb_relaxed(0xa5, base + MIPHY_DEBUG_BUS); |
550 | writeb_relaxed(0x00, base + MIPHY_CONF); |
551 | } |
552 | |
553 | static void miphy_sata_tune_ssc(struct miphy28lp_phy *miphy_phy) |
554 | { |
555 | void __iomem *base = miphy_phy->base; |
556 | u8 val; |
557 | |
558 | /* Compensate Tx impedance to avoid out of range values */ |
559 | /* |
560 | * Enable the SSC on PLL for all banks |
561 | * SSC Modulation @ 31 KHz and 4000 ppm modulation amp |
562 | */ |
563 | val = readb_relaxed(base + MIPHY_BOUNDARY_2); |
564 | val |= SSC_EN_SW; |
565 | writeb_relaxed(val, base + MIPHY_BOUNDARY_2); |
566 | |
567 | val = readb_relaxed(base + MIPHY_BOUNDARY_SEL); |
568 | val |= SSC_SEL; |
569 | writeb_relaxed(val, base + MIPHY_BOUNDARY_SEL); |
570 | |
571 | for (val = 0; val < MIPHY_SATA_BANK_NB; val++) { |
572 | writeb_relaxed(val, base + MIPHY_CONF); |
573 | |
574 | /* Add value to each reference clock cycle */ |
575 | /* and define the period length of the SSC */ |
576 | writeb_relaxed(0x3c, base + MIPHY_PLL_SBR_2); |
577 | writeb_relaxed(0x6c, base + MIPHY_PLL_SBR_3); |
578 | writeb_relaxed(0x81, base + MIPHY_PLL_SBR_4); |
579 | |
580 | /* Clear any previous request */ |
581 | writeb_relaxed(0x00, base + MIPHY_PLL_SBR_1); |
582 | |
583 | /* requests the PLL to take in account new parameters */ |
584 | writeb_relaxed(SET_NEW_CHANGE, base + MIPHY_PLL_SBR_1); |
585 | |
586 | /* To be sure there is no other pending requests */ |
587 | writeb_relaxed(0x00, base + MIPHY_PLL_SBR_1); |
588 | } |
589 | } |
590 | |
591 | static void miphy_pcie_tune_ssc(struct miphy28lp_phy *miphy_phy) |
592 | { |
593 | void __iomem *base = miphy_phy->base; |
594 | u8 val; |
595 | |
596 | /* Compensate Tx impedance to avoid out of range values */ |
597 | /* |
598 | * Enable the SSC on PLL for all banks |
599 | * SSC Modulation @ 31 KHz and 4000 ppm modulation amp |
600 | */ |
601 | val = readb_relaxed(base + MIPHY_BOUNDARY_2); |
602 | val |= SSC_EN_SW; |
603 | writeb_relaxed(val, base + MIPHY_BOUNDARY_2); |
604 | |
605 | val = readb_relaxed(base + MIPHY_BOUNDARY_SEL); |
606 | val |= SSC_SEL; |
607 | writeb_relaxed(val, base + MIPHY_BOUNDARY_SEL); |
608 | |
609 | for (val = 0; val < MIPHY_PCIE_BANK_NB; val++) { |
610 | writeb_relaxed(val, base + MIPHY_CONF); |
611 | |
612 | /* Validate Step component */ |
613 | writeb_relaxed(0x69, base + MIPHY_PLL_SBR_3); |
614 | writeb_relaxed(0x21, base + MIPHY_PLL_SBR_4); |
615 | |
616 | /* Validate Period component */ |
617 | writeb_relaxed(0x3c, base + MIPHY_PLL_SBR_2); |
618 | writeb_relaxed(0x21, base + MIPHY_PLL_SBR_4); |
619 | |
620 | /* Clear any previous request */ |
621 | writeb_relaxed(0x00, base + MIPHY_PLL_SBR_1); |
622 | |
623 | /* requests the PLL to take in account new parameters */ |
624 | writeb_relaxed(SET_NEW_CHANGE, base + MIPHY_PLL_SBR_1); |
625 | |
626 | /* To be sure there is no other pending requests */ |
627 | writeb_relaxed(0x00, base + MIPHY_PLL_SBR_1); |
628 | } |
629 | } |
630 | |
631 | static inline void miphy_tune_tx_impedance(struct miphy28lp_phy *miphy_phy) |
632 | { |
633 | /* Compensate Tx impedance to avoid out of range values */ |
634 | writeb_relaxed(0x02, miphy_phy->base + MIPHY_COMP_POSTP); |
635 | } |
636 | |
637 | static inline int miphy28lp_configure_sata(struct miphy28lp_phy *miphy_phy) |
638 | { |
639 | void __iomem *base = miphy_phy->base; |
640 | int err; |
641 | u8 val; |
642 | |
643 | /* Putting Macro in reset */ |
644 | miphy28lp_set_reset(miphy_phy); |
645 | |
646 | /* PLL calibration */ |
647 | miphy28lp_pll_calibration(miphy_phy, pll_ratio: &sata_pll_ratio); |
648 | |
649 | /* Banked settings Gen1/Gen2/Gen3 */ |
650 | miphy28lp_sata_config_gen(miphy_phy); |
651 | |
652 | /* Power control */ |
653 | /* Input bridge enable, manual input bridge control */ |
654 | writeb_relaxed(0x21, base + MIPHY_RX_POWER_CTRL_1); |
655 | |
656 | /* Macro out of reset */ |
657 | writeb_relaxed(0x00, base + MIPHY_CONF_RESET); |
658 | |
659 | /* Poll for HFC ready after reset release */ |
660 | /* Compensation measurement */ |
661 | err = miphy28lp_compensation(miphy_phy, pll_ratio: &sata_pll_ratio); |
662 | if (err) |
663 | return err; |
664 | |
665 | if (miphy_phy->px_rx_pol_inv) { |
666 | /* Invert Rx polarity */ |
667 | val = readb_relaxed(miphy_phy->base + MIPHY_CONTROL); |
668 | val |= PX_RX_POL; |
669 | writeb_relaxed(val, miphy_phy->base + MIPHY_CONTROL); |
670 | } |
671 | |
672 | if (miphy_phy->ssc) |
673 | miphy_sata_tune_ssc(miphy_phy); |
674 | |
675 | if (miphy_phy->tx_impedance) |
676 | miphy_tune_tx_impedance(miphy_phy); |
677 | |
678 | return 0; |
679 | } |
680 | |
681 | static inline int miphy28lp_configure_pcie(struct miphy28lp_phy *miphy_phy) |
682 | { |
683 | void __iomem *base = miphy_phy->base; |
684 | int err; |
685 | |
686 | /* Putting Macro in reset */ |
687 | miphy28lp_set_reset(miphy_phy); |
688 | |
689 | /* PLL calibration */ |
690 | miphy28lp_pll_calibration(miphy_phy, pll_ratio: &pcie_pll_ratio); |
691 | |
692 | /* Banked settings Gen1/Gen2 */ |
693 | miphy28lp_pcie_config_gen(miphy_phy); |
694 | |
695 | /* Power control */ |
696 | /* Input bridge enable, manual input bridge control */ |
697 | writeb_relaxed(0x21, base + MIPHY_RX_POWER_CTRL_1); |
698 | |
699 | /* Macro out of reset */ |
700 | writeb_relaxed(0x00, base + MIPHY_CONF_RESET); |
701 | |
702 | /* Poll for HFC ready after reset release */ |
703 | /* Compensation measurement */ |
704 | err = miphy28lp_compensation(miphy_phy, pll_ratio: &pcie_pll_ratio); |
705 | if (err) |
706 | return err; |
707 | |
708 | if (miphy_phy->ssc) |
709 | miphy_pcie_tune_ssc(miphy_phy); |
710 | |
711 | if (miphy_phy->tx_impedance) |
712 | miphy_tune_tx_impedance(miphy_phy); |
713 | |
714 | return 0; |
715 | } |
716 | |
717 | |
718 | static inline void miphy28lp_configure_usb3(struct miphy28lp_phy *miphy_phy) |
719 | { |
720 | void __iomem *base = miphy_phy->base; |
721 | u8 val; |
722 | |
723 | /* Putting Macro in reset */ |
724 | miphy28lp_set_reset(miphy_phy); |
725 | |
726 | /* PLL calibration */ |
727 | miphy28lp_pll_calibration(miphy_phy, pll_ratio: &usb3_pll_ratio); |
728 | |
729 | /* Writing The Speed Rate */ |
730 | writeb_relaxed(0x00, base + MIPHY_CONF); |
731 | |
732 | val = RX_SPDSEL_20DEC | TX_SPDSEL_20DEC; |
733 | writeb_relaxed(val, base + MIPHY_SPEED); |
734 | |
735 | /* RX Channel compensation and calibration */ |
736 | writeb_relaxed(0x1c, base + MIPHY_RX_LOCK_SETTINGS_OPT); |
737 | writeb_relaxed(0x51, base + MIPHY_RX_CAL_CTRL_1); |
738 | writeb_relaxed(0x70, base + MIPHY_RX_CAL_CTRL_2); |
739 | |
740 | val = OFFSET_COMPENSATION_EN | VGA_OFFSET_POLARITY | |
741 | CAL_OFFSET_THRESHOLD_64 | CAL_OFFSET_VGA_64; |
742 | writeb_relaxed(val, base + MIPHY_RX_CAL_OFFSET_CTRL); |
743 | writeb_relaxed(0x22, base + MIPHY_RX_CAL_VGA_STEP); |
744 | writeb_relaxed(0x0e, base + MIPHY_RX_CAL_OPT_LENGTH); |
745 | |
746 | val = EQ_DC_GAIN | VGA_GAIN; |
747 | writeb_relaxed(val, base + MIPHY_RX_BUFFER_CTRL); |
748 | writeb_relaxed(0x78, base + MIPHY_RX_EQU_GAIN_1); |
749 | writeb_relaxed(0x1b, base + MIPHY_SYNCHAR_CONTROL); |
750 | |
751 | /* TX compensation offset to re-center TX impedance */ |
752 | writeb_relaxed(0x02, base + MIPHY_COMP_POSTP); |
753 | |
754 | /* Enable GENSEL_SEL and SSC */ |
755 | /* TX_SEL=0 swing preemp forced by pipe registres */ |
756 | val = SSC_SEL | GENSEL_SEL; |
757 | writeb_relaxed(val, base + MIPHY_BOUNDARY_SEL); |
758 | |
759 | /* MIPHY Bias boost */ |
760 | writeb_relaxed(0x00, base + MIPHY_BIAS_BOOST_1); |
761 | writeb_relaxed(0xa7, base + MIPHY_BIAS_BOOST_2); |
762 | |
763 | /* SSC modulation */ |
764 | writeb_relaxed(SSC_EN_SW, base + MIPHY_BOUNDARY_2); |
765 | |
766 | /* MIPHY TX control */ |
767 | writeb_relaxed(0x00, base + MIPHY_CONF); |
768 | |
769 | /* Validate Step component */ |
770 | writeb_relaxed(0x5a, base + MIPHY_PLL_SBR_3); |
771 | writeb_relaxed(0xa0, base + MIPHY_PLL_SBR_4); |
772 | |
773 | /* Validate Period component */ |
774 | writeb_relaxed(0x3c, base + MIPHY_PLL_SBR_2); |
775 | writeb_relaxed(0xa1, base + MIPHY_PLL_SBR_4); |
776 | |
777 | /* Clear any previous request */ |
778 | writeb_relaxed(0x00, base + MIPHY_PLL_SBR_1); |
779 | |
780 | /* requests the PLL to take in account new parameters */ |
781 | writeb_relaxed(0x02, base + MIPHY_PLL_SBR_1); |
782 | |
783 | /* To be sure there is no other pending requests */ |
784 | writeb_relaxed(0x00, base + MIPHY_PLL_SBR_1); |
785 | |
786 | /* Rx PI controller settings */ |
787 | writeb_relaxed(0xca, base + MIPHY_RX_K_GAIN); |
788 | |
789 | /* MIPHY RX input bridge control */ |
790 | /* INPUT_BRIDGE_EN_SW=1, manual input bridge control[0]=1 */ |
791 | writeb_relaxed(0x21, base + MIPHY_RX_POWER_CTRL_1); |
792 | writeb_relaxed(0x29, base + MIPHY_RX_POWER_CTRL_1); |
793 | writeb_relaxed(0x1a, base + MIPHY_RX_POWER_CTRL_2); |
794 | |
795 | /* MIPHY Reset for usb3 */ |
796 | miphy28_usb3_miphy_reset(miphy_phy); |
797 | } |
798 | |
799 | static inline int miphy_is_ready(struct miphy28lp_phy *miphy_phy) |
800 | { |
801 | u8 mask = HFC_PLL | HFC_RDY; |
802 | u8 val; |
803 | |
804 | /* |
805 | * For PCIe and USB3 check only that PLL and HFC are ready |
806 | * For SATA check also that phy is ready! |
807 | */ |
808 | if (miphy_phy->type == PHY_TYPE_SATA) |
809 | mask |= PHY_RDY; |
810 | |
811 | return readb_relaxed_poll_timeout(miphy_phy->base + MIPHY_STATUS_1, |
812 | val, (val & mask) == mask, 1, |
813 | 5 * USEC_PER_SEC); |
814 | } |
815 | |
816 | static int miphy_osc_is_ready(struct miphy28lp_phy *miphy_phy) |
817 | { |
818 | struct miphy28lp_dev *miphy_dev = miphy_phy->phydev; |
819 | u32 val; |
820 | |
821 | if (!miphy_phy->osc_rdy) |
822 | return 0; |
823 | |
824 | if (!miphy_phy->syscfg_reg[SYSCFG_STATUS]) |
825 | return -EINVAL; |
826 | |
827 | return regmap_read_poll_timeout(miphy_dev->regmap, |
828 | miphy_phy->syscfg_reg[SYSCFG_STATUS], |
829 | val, val & MIPHY_OSC_RDY, 1, |
830 | 5 * USEC_PER_SEC); |
831 | } |
832 | |
833 | static int miphy28lp_get_resource_byname(struct device_node *child, |
834 | char *rname, struct resource *res) |
835 | { |
836 | int index; |
837 | |
838 | index = of_property_match_string(np: child, propname: "reg-names" , string: rname); |
839 | if (index < 0) |
840 | return -ENODEV; |
841 | |
842 | return of_address_to_resource(dev: child, index, r: res); |
843 | } |
844 | |
845 | static int miphy28lp_get_one_addr(struct device *dev, |
846 | struct device_node *child, char *rname, |
847 | void __iomem **base) |
848 | { |
849 | struct resource res; |
850 | int ret; |
851 | |
852 | ret = miphy28lp_get_resource_byname(child, rname, res: &res); |
853 | if (!ret) { |
854 | *base = devm_ioremap(dev, offset: res.start, size: resource_size(res: &res)); |
855 | if (!*base) { |
856 | dev_err(dev, "failed to ioremap %s address region\n" |
857 | , rname); |
858 | return -ENOENT; |
859 | } |
860 | } |
861 | |
862 | return 0; |
863 | } |
864 | |
865 | /* MiPHY reset and sysconf setup */ |
866 | static int miphy28lp_setup(struct miphy28lp_phy *miphy_phy, u32 miphy_val) |
867 | { |
868 | int err; |
869 | struct miphy28lp_dev *miphy_dev = miphy_phy->phydev; |
870 | |
871 | if (!miphy_phy->syscfg_reg[SYSCFG_CTRL]) |
872 | return -EINVAL; |
873 | |
874 | err = reset_control_assert(rstc: miphy_phy->miphy_rst); |
875 | if (err) { |
876 | dev_err(miphy_dev->dev, "unable to bring out of miphy reset\n" ); |
877 | return err; |
878 | } |
879 | |
880 | if (miphy_phy->osc_force_ext) |
881 | miphy_val |= MIPHY_OSC_FORCE_EXT; |
882 | |
883 | regmap_update_bits(map: miphy_dev->regmap, |
884 | reg: miphy_phy->syscfg_reg[SYSCFG_CTRL], |
885 | MIPHY_CTRL_MASK, val: miphy_val); |
886 | |
887 | err = reset_control_deassert(rstc: miphy_phy->miphy_rst); |
888 | if (err) { |
889 | dev_err(miphy_dev->dev, "unable to bring out of miphy reset\n" ); |
890 | return err; |
891 | } |
892 | |
893 | return miphy_osc_is_ready(miphy_phy); |
894 | } |
895 | |
896 | static int miphy28lp_init_sata(struct miphy28lp_phy *miphy_phy) |
897 | { |
898 | struct miphy28lp_dev *miphy_dev = miphy_phy->phydev; |
899 | int err, sata_conf = SATA_CTRL_SELECT_SATA; |
900 | |
901 | if ((!miphy_phy->syscfg_reg[SYSCFG_SATA]) || |
902 | (!miphy_phy->syscfg_reg[SYSCFG_PCI]) || |
903 | (!miphy_phy->base)) |
904 | return -EINVAL; |
905 | |
906 | dev_info(miphy_dev->dev, "sata-up mode, addr 0x%p\n" , miphy_phy->base); |
907 | |
908 | /* Configure the glue-logic */ |
909 | sata_conf |= ((miphy_phy->sata_gen - SATA_GEN1) << SATA_SPDMODE); |
910 | |
911 | regmap_update_bits(map: miphy_dev->regmap, |
912 | reg: miphy_phy->syscfg_reg[SYSCFG_SATA], |
913 | SATA_CTRL_MASK, val: sata_conf); |
914 | |
915 | regmap_update_bits(map: miphy_dev->regmap, reg: miphy_phy->syscfg_reg[SYSCFG_PCI], |
916 | PCIE_CTRL_MASK, SATA_CTRL_SELECT_PCIE); |
917 | |
918 | /* MiPHY path and clocking init */ |
919 | err = miphy28lp_setup(miphy_phy, MIPHY_CTRL_DEFAULT); |
920 | |
921 | if (err) { |
922 | dev_err(miphy_dev->dev, "SATA phy setup failed\n" ); |
923 | return err; |
924 | } |
925 | |
926 | /* initialize miphy */ |
927 | miphy28lp_configure_sata(miphy_phy); |
928 | |
929 | return miphy_is_ready(miphy_phy); |
930 | } |
931 | |
932 | static int miphy28lp_init_pcie(struct miphy28lp_phy *miphy_phy) |
933 | { |
934 | struct miphy28lp_dev *miphy_dev = miphy_phy->phydev; |
935 | int err; |
936 | |
937 | if ((!miphy_phy->syscfg_reg[SYSCFG_SATA]) || |
938 | (!miphy_phy->syscfg_reg[SYSCFG_PCI]) |
939 | || (!miphy_phy->base) || (!miphy_phy->pipebase)) |
940 | return -EINVAL; |
941 | |
942 | dev_info(miphy_dev->dev, "pcie-up mode, addr 0x%p\n" , miphy_phy->base); |
943 | |
944 | /* Configure the glue-logic */ |
945 | regmap_update_bits(map: miphy_dev->regmap, |
946 | reg: miphy_phy->syscfg_reg[SYSCFG_SATA], |
947 | SATA_CTRL_MASK, SATA_CTRL_SELECT_PCIE); |
948 | |
949 | regmap_update_bits(map: miphy_dev->regmap, reg: miphy_phy->syscfg_reg[SYSCFG_PCI], |
950 | PCIE_CTRL_MASK, SYSCFG_PCIE_PCIE_VAL); |
951 | |
952 | /* MiPHY path and clocking init */ |
953 | err = miphy28lp_setup(miphy_phy, MIPHY_CTRL_DEFAULT); |
954 | |
955 | if (err) { |
956 | dev_err(miphy_dev->dev, "PCIe phy setup failed\n" ); |
957 | return err; |
958 | } |
959 | |
960 | /* initialize miphy */ |
961 | err = miphy28lp_configure_pcie(miphy_phy); |
962 | if (err) |
963 | return err; |
964 | |
965 | /* PIPE Wrapper Configuration */ |
966 | writeb_relaxed(0x68, miphy_phy->pipebase + 0x104); /* Rise_0 */ |
967 | writeb_relaxed(0x61, miphy_phy->pipebase + 0x105); /* Rise_1 */ |
968 | writeb_relaxed(0x68, miphy_phy->pipebase + 0x108); /* Fall_0 */ |
969 | writeb_relaxed(0x61, miphy_phy->pipebase + 0x109); /* Fall-1 */ |
970 | writeb_relaxed(0x68, miphy_phy->pipebase + 0x10c); /* Threshold_0 */ |
971 | writeb_relaxed(0x60, miphy_phy->pipebase + 0x10d); /* Threshold_1 */ |
972 | |
973 | /* Wait for phy_ready */ |
974 | return miphy_is_ready(miphy_phy); |
975 | } |
976 | |
977 | static int miphy28lp_init_usb3(struct miphy28lp_phy *miphy_phy) |
978 | { |
979 | struct miphy28lp_dev *miphy_dev = miphy_phy->phydev; |
980 | int err; |
981 | |
982 | if ((!miphy_phy->base) || (!miphy_phy->pipebase)) |
983 | return -EINVAL; |
984 | |
985 | dev_info(miphy_dev->dev, "usb3-up mode, addr 0x%p\n" , miphy_phy->base); |
986 | |
987 | /* MiPHY path and clocking init */ |
988 | err = miphy28lp_setup(miphy_phy, MIPHY_CTRL_SYNC_D_EN); |
989 | if (err) { |
990 | dev_err(miphy_dev->dev, "USB3 phy setup failed\n" ); |
991 | return err; |
992 | } |
993 | |
994 | /* initialize miphy */ |
995 | miphy28lp_configure_usb3(miphy_phy); |
996 | |
997 | /* PIPE Wrapper Configuration */ |
998 | writeb_relaxed(0x68, miphy_phy->pipebase + 0x23); |
999 | writeb_relaxed(0x61, miphy_phy->pipebase + 0x24); |
1000 | writeb_relaxed(0x68, miphy_phy->pipebase + 0x26); |
1001 | writeb_relaxed(0x61, miphy_phy->pipebase + 0x27); |
1002 | writeb_relaxed(0x18, miphy_phy->pipebase + 0x29); |
1003 | writeb_relaxed(0x61, miphy_phy->pipebase + 0x2a); |
1004 | |
1005 | /* pipe Wrapper usb3 TX swing de-emph margin PREEMPH[7:4], SWING[3:0] */ |
1006 | writeb_relaxed(0X67, miphy_phy->pipebase + 0x68); |
1007 | writeb_relaxed(0x0d, miphy_phy->pipebase + 0x69); |
1008 | writeb_relaxed(0X67, miphy_phy->pipebase + 0x6a); |
1009 | writeb_relaxed(0X0d, miphy_phy->pipebase + 0x6b); |
1010 | writeb_relaxed(0X67, miphy_phy->pipebase + 0x6c); |
1011 | writeb_relaxed(0X0d, miphy_phy->pipebase + 0x6d); |
1012 | writeb_relaxed(0X67, miphy_phy->pipebase + 0x6e); |
1013 | writeb_relaxed(0X0d, miphy_phy->pipebase + 0x6f); |
1014 | |
1015 | return miphy_is_ready(miphy_phy); |
1016 | } |
1017 | |
1018 | static int miphy28lp_init(struct phy *phy) |
1019 | { |
1020 | struct miphy28lp_phy *miphy_phy = phy_get_drvdata(phy); |
1021 | struct miphy28lp_dev *miphy_dev = miphy_phy->phydev; |
1022 | int ret; |
1023 | |
1024 | mutex_lock(&miphy_dev->miphy_mutex); |
1025 | |
1026 | switch (miphy_phy->type) { |
1027 | |
1028 | case PHY_TYPE_SATA: |
1029 | ret = miphy28lp_init_sata(miphy_phy); |
1030 | break; |
1031 | case PHY_TYPE_PCIE: |
1032 | ret = miphy28lp_init_pcie(miphy_phy); |
1033 | break; |
1034 | case PHY_TYPE_USB3: |
1035 | ret = miphy28lp_init_usb3(miphy_phy); |
1036 | break; |
1037 | default: |
1038 | ret = -EINVAL; |
1039 | break; |
1040 | } |
1041 | |
1042 | mutex_unlock(lock: &miphy_dev->miphy_mutex); |
1043 | |
1044 | return ret; |
1045 | } |
1046 | |
1047 | static int miphy28lp_get_addr(struct miphy28lp_phy *miphy_phy) |
1048 | { |
1049 | struct miphy28lp_dev *miphy_dev = miphy_phy->phydev; |
1050 | struct device_node *phynode = miphy_phy->phy->dev.of_node; |
1051 | int err; |
1052 | |
1053 | if ((miphy_phy->type != PHY_TYPE_SATA) && |
1054 | (miphy_phy->type != PHY_TYPE_PCIE) && |
1055 | (miphy_phy->type != PHY_TYPE_USB3)) { |
1056 | return -EINVAL; |
1057 | } |
1058 | |
1059 | err = miphy28lp_get_one_addr(dev: miphy_dev->dev, child: phynode, |
1060 | rname: PHY_TYPE_name[miphy_phy->type - PHY_TYPE_SATA], |
1061 | base: &miphy_phy->base); |
1062 | if (err) |
1063 | return err; |
1064 | |
1065 | if ((miphy_phy->type == PHY_TYPE_PCIE) || |
1066 | (miphy_phy->type == PHY_TYPE_USB3)) { |
1067 | err = miphy28lp_get_one_addr(dev: miphy_dev->dev, child: phynode, rname: "pipew" , |
1068 | base: &miphy_phy->pipebase); |
1069 | if (err) |
1070 | return err; |
1071 | } |
1072 | |
1073 | return 0; |
1074 | } |
1075 | |
1076 | static struct phy *miphy28lp_xlate(struct device *dev, |
1077 | const struct of_phandle_args *args) |
1078 | { |
1079 | struct miphy28lp_dev *miphy_dev = dev_get_drvdata(dev); |
1080 | struct miphy28lp_phy *miphy_phy = NULL; |
1081 | struct device_node *phynode = args->np; |
1082 | int ret, index = 0; |
1083 | |
1084 | if (args->args_count != 1) { |
1085 | dev_err(dev, "Invalid number of cells in 'phy' property\n" ); |
1086 | return ERR_PTR(error: -EINVAL); |
1087 | } |
1088 | |
1089 | for (index = 0; index < miphy_dev->nphys; index++) |
1090 | if (phynode == miphy_dev->phys[index]->phy->dev.of_node) { |
1091 | miphy_phy = miphy_dev->phys[index]; |
1092 | break; |
1093 | } |
1094 | |
1095 | if (!miphy_phy) { |
1096 | dev_err(dev, "Failed to find appropriate phy\n" ); |
1097 | return ERR_PTR(error: -EINVAL); |
1098 | } |
1099 | |
1100 | miphy_phy->type = args->args[0]; |
1101 | |
1102 | ret = miphy28lp_get_addr(miphy_phy); |
1103 | if (ret < 0) |
1104 | return ERR_PTR(error: ret); |
1105 | |
1106 | return miphy_phy->phy; |
1107 | } |
1108 | |
1109 | static const struct phy_ops miphy28lp_ops = { |
1110 | .init = miphy28lp_init, |
1111 | .owner = THIS_MODULE, |
1112 | }; |
1113 | |
1114 | static int miphy28lp_probe_resets(struct device_node *node, |
1115 | struct miphy28lp_phy *miphy_phy) |
1116 | { |
1117 | struct miphy28lp_dev *miphy_dev = miphy_phy->phydev; |
1118 | int err; |
1119 | |
1120 | miphy_phy->miphy_rst = |
1121 | of_reset_control_get_shared(node, id: "miphy-sw-rst" ); |
1122 | |
1123 | if (IS_ERR(ptr: miphy_phy->miphy_rst)) { |
1124 | dev_err(miphy_dev->dev, |
1125 | "miphy soft reset control not defined\n" ); |
1126 | return PTR_ERR(ptr: miphy_phy->miphy_rst); |
1127 | } |
1128 | |
1129 | err = reset_control_deassert(rstc: miphy_phy->miphy_rst); |
1130 | if (err) { |
1131 | dev_err(miphy_dev->dev, "unable to bring out of miphy reset\n" ); |
1132 | return err; |
1133 | } |
1134 | |
1135 | return 0; |
1136 | } |
1137 | |
1138 | static int miphy28lp_of_probe(struct device_node *np, |
1139 | struct miphy28lp_phy *miphy_phy) |
1140 | { |
1141 | int i; |
1142 | u32 ctrlreg; |
1143 | |
1144 | miphy_phy->osc_force_ext = |
1145 | of_property_read_bool(np, propname: "st,osc-force-ext" ); |
1146 | |
1147 | miphy_phy->osc_rdy = of_property_read_bool(np, propname: "st,osc-rdy" ); |
1148 | |
1149 | miphy_phy->px_rx_pol_inv = |
1150 | of_property_read_bool(np, propname: "st,px_rx_pol_inv" ); |
1151 | |
1152 | miphy_phy->ssc = of_property_read_bool(np, propname: "st,ssc-on" ); |
1153 | |
1154 | miphy_phy->tx_impedance = |
1155 | of_property_read_bool(np, propname: "st,tx-impedance-comp" ); |
1156 | |
1157 | of_property_read_u32(np, propname: "st,sata-gen" , out_value: &miphy_phy->sata_gen); |
1158 | if (!miphy_phy->sata_gen) |
1159 | miphy_phy->sata_gen = SATA_GEN1; |
1160 | |
1161 | for (i = 0; i < SYSCFG_REG_MAX; i++) { |
1162 | if (!of_property_read_u32_index(np, propname: "st,syscfg" , index: i, out_value: &ctrlreg)) |
1163 | miphy_phy->syscfg_reg[i] = ctrlreg; |
1164 | } |
1165 | |
1166 | return 0; |
1167 | } |
1168 | |
1169 | static int miphy28lp_probe(struct platform_device *pdev) |
1170 | { |
1171 | struct device_node *child, *np = pdev->dev.of_node; |
1172 | struct miphy28lp_dev *miphy_dev; |
1173 | struct phy_provider *provider; |
1174 | struct phy *phy; |
1175 | int ret, port = 0; |
1176 | |
1177 | miphy_dev = devm_kzalloc(dev: &pdev->dev, size: sizeof(*miphy_dev), GFP_KERNEL); |
1178 | if (!miphy_dev) |
1179 | return -ENOMEM; |
1180 | |
1181 | miphy_dev->nphys = of_get_child_count(np); |
1182 | miphy_dev->phys = devm_kcalloc(dev: &pdev->dev, n: miphy_dev->nphys, |
1183 | size: sizeof(*miphy_dev->phys), GFP_KERNEL); |
1184 | if (!miphy_dev->phys) |
1185 | return -ENOMEM; |
1186 | |
1187 | miphy_dev->regmap = syscon_regmap_lookup_by_phandle(np, property: "st,syscfg" ); |
1188 | if (IS_ERR(ptr: miphy_dev->regmap)) { |
1189 | dev_err(miphy_dev->dev, "No syscfg phandle specified\n" ); |
1190 | return PTR_ERR(ptr: miphy_dev->regmap); |
1191 | } |
1192 | |
1193 | miphy_dev->dev = &pdev->dev; |
1194 | |
1195 | dev_set_drvdata(dev: &pdev->dev, data: miphy_dev); |
1196 | |
1197 | mutex_init(&miphy_dev->miphy_mutex); |
1198 | |
1199 | for_each_child_of_node(np, child) { |
1200 | struct miphy28lp_phy *miphy_phy; |
1201 | |
1202 | miphy_phy = devm_kzalloc(dev: &pdev->dev, size: sizeof(*miphy_phy), |
1203 | GFP_KERNEL); |
1204 | if (!miphy_phy) { |
1205 | ret = -ENOMEM; |
1206 | goto put_child; |
1207 | } |
1208 | |
1209 | miphy_dev->phys[port] = miphy_phy; |
1210 | |
1211 | phy = devm_phy_create(dev: &pdev->dev, node: child, ops: &miphy28lp_ops); |
1212 | if (IS_ERR(ptr: phy)) { |
1213 | dev_err(&pdev->dev, "failed to create PHY\n" ); |
1214 | ret = PTR_ERR(ptr: phy); |
1215 | goto put_child; |
1216 | } |
1217 | |
1218 | miphy_dev->phys[port]->phy = phy; |
1219 | miphy_dev->phys[port]->phydev = miphy_dev; |
1220 | |
1221 | ret = miphy28lp_of_probe(np: child, miphy_phy); |
1222 | if (ret) |
1223 | goto put_child; |
1224 | |
1225 | ret = miphy28lp_probe_resets(node: child, miphy_phy: miphy_dev->phys[port]); |
1226 | if (ret) |
1227 | goto put_child; |
1228 | |
1229 | phy_set_drvdata(phy, data: miphy_dev->phys[port]); |
1230 | port++; |
1231 | |
1232 | } |
1233 | |
1234 | provider = devm_of_phy_provider_register(&pdev->dev, miphy28lp_xlate); |
1235 | return PTR_ERR_OR_ZERO(ptr: provider); |
1236 | put_child: |
1237 | of_node_put(node: child); |
1238 | return ret; |
1239 | } |
1240 | |
1241 | static const struct of_device_id miphy28lp_of_match[] = { |
1242 | {.compatible = "st,miphy28lp-phy" , }, |
1243 | {}, |
1244 | }; |
1245 | |
1246 | MODULE_DEVICE_TABLE(of, miphy28lp_of_match); |
1247 | |
1248 | static struct platform_driver miphy28lp_driver = { |
1249 | .probe = miphy28lp_probe, |
1250 | .driver = { |
1251 | .name = "miphy28lp-phy" , |
1252 | .of_match_table = miphy28lp_of_match, |
1253 | } |
1254 | }; |
1255 | |
1256 | module_platform_driver(miphy28lp_driver); |
1257 | |
1258 | MODULE_AUTHOR("Alexandre Torgue <alexandre.torgue@st.com>" ); |
1259 | MODULE_DESCRIPTION("STMicroelectronics miphy28lp driver" ); |
1260 | MODULE_LICENSE("GPL v2" ); |
1261 | |