blob: 29a35ae5ffb96333ea68b388b9da650c68936ff2 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +02002/*
Nishanth Menoneaa39c62023-11-01 15:56:03 -05003 * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com/
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +02004 * Written by Jean-Jacques Hiblot <jjhiblot@ti.com>
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +02005 */
6
Tom Riniabb9a042024-05-18 20:20:43 -06007#include <common.h>
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +02008#include <dm.h>
9#include <dm/device.h>
10#include <generic-phy.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060011#include <asm/global_data.h>
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +020012#include <asm/io.h>
13#include <asm/arch/sys_proto.h>
14#include <syscon.h>
15#include <regmap.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060016#include <linux/bitops.h>
Simon Glassdbd79542020-05-10 11:40:11 -060017#include <linux/delay.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070018#include <linux/err.h>
Simon Glassbdd5f812023-09-14 18:21:46 -060019#include <linux/printk.h>
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +020020
21/* PLLCTRL Registers */
22#define PLL_STATUS 0x00000004
23#define PLL_GO 0x00000008
24#define PLL_CONFIGURATION1 0x0000000C
25#define PLL_CONFIGURATION2 0x00000010
26#define PLL_CONFIGURATION3 0x00000014
27#define PLL_CONFIGURATION4 0x00000020
28
29#define PLL_REGM_MASK 0x001FFE00
30#define PLL_REGM_SHIFT 9
31#define PLL_REGM_F_MASK 0x0003FFFF
32#define PLL_REGM_F_SHIFT 0
33#define PLL_REGN_MASK 0x000001FE
34#define PLL_REGN_SHIFT 1
35#define PLL_SELFREQDCO_MASK 0x0000000E
36#define PLL_SELFREQDCO_SHIFT 1
37#define PLL_SD_MASK 0x0003FC00
38#define PLL_SD_SHIFT 10
39#define SET_PLL_GO 0x1
40#define PLL_TICOPWDN BIT(16)
41#define PLL_LDOPWDN BIT(15)
42#define PLL_LOCK 0x2
43#define PLL_IDLE 0x1
44
45/* Software rest for the SATA PLL (in CTRL_CORE_SMA_SW_0 register)*/
46#define SATA_PLL_SOFT_RESET (1<<18)
47
48/* PHY POWER CONTROL Register */
Roger Quadrosed555622019-11-06 16:21:18 +020049#define PIPE3_PHY_PWRCTL_CLK_CMD_MASK GENMASK(21, 14)
50#define PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT 14
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +020051
Roger Quadrosed555622019-11-06 16:21:18 +020052#define PIPE3_PHY_PWRCTL_CLK_FREQ_MASK GENMASK(31, 22)
53#define PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT 22
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +020054
Roger Quadrosed555622019-11-06 16:21:18 +020055#define PIPE3_PHY_RX_POWERON (0x1 << PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT)
56#define PIPE3_PHY_TX_POWERON (0x2 << PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT)
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +020057
Roger Quadros80c69c62019-11-06 16:21:17 +020058/* PHY RX Registers */
59#define PIPE3_PHY_RX_ANA_PROGRAMMABILITY 0x0000000C
60#define INTERFACE_MASK GENMASK(31, 27)
61#define INTERFACE_SHIFT 27
62#define INTERFACE_MODE_USBSS BIT(4)
63#define INTERFACE_MODE_SATA_1P5 BIT(3)
64#define INTERFACE_MODE_SATA_3P0 BIT(2)
65#define INTERFACE_MODE_PCIE BIT(0)
66
67#define LOSD_MASK GENMASK(17, 14)
68#define LOSD_SHIFT 14
69#define MEM_PLLDIV GENMASK(6, 5)
70
71#define PIPE3_PHY_RX_TRIM 0x0000001C
72#define MEM_DLL_TRIM_SEL_MASK GENMASK(31, 30)
73#define MEM_DLL_TRIM_SHIFT 30
74
75#define PIPE3_PHY_RX_DLL 0x00000024
76#define MEM_DLL_PHINT_RATE_MASK GENMASK(31, 30)
77#define MEM_DLL_PHINT_RATE_SHIFT 30
78
79#define PIPE3_PHY_RX_DIGITAL_MODES 0x00000028
80#define MEM_HS_RATE_MASK GENMASK(28, 27)
81#define MEM_HS_RATE_SHIFT 27
82#define MEM_OVRD_HS_RATE BIT(26)
83#define MEM_OVRD_HS_RATE_SHIFT 26
84#define MEM_CDR_FASTLOCK BIT(23)
85#define MEM_CDR_FASTLOCK_SHIFT 23
86#define MEM_CDR_LBW_MASK GENMASK(22, 21)
87#define MEM_CDR_LBW_SHIFT 21
88#define MEM_CDR_STEPCNT_MASK GENMASK(20, 19)
89#define MEM_CDR_STEPCNT_SHIFT 19
90#define MEM_CDR_STL_MASK GENMASK(18, 16)
91#define MEM_CDR_STL_SHIFT 16
92#define MEM_CDR_THR_MASK GENMASK(15, 13)
93#define MEM_CDR_THR_SHIFT 13
94#define MEM_CDR_THR_MODE BIT(12)
95#define MEM_CDR_THR_MODE_SHIFT 12
96#define MEM_CDR_2NDO_SDM_MODE BIT(11)
97#define MEM_CDR_2NDO_SDM_MODE_SHIFT 11
98
99#define PIPE3_PHY_RX_EQUALIZER 0x00000038
100#define MEM_EQLEV_MASK GENMASK(31, 16)
101#define MEM_EQLEV_SHIFT 16
102#define MEM_EQFTC_MASK GENMASK(15, 11)
103#define MEM_EQFTC_SHIFT 11
104#define MEM_EQCTL_MASK GENMASK(10, 7)
105#define MEM_EQCTL_SHIFT 7
106#define MEM_OVRD_EQLEV BIT(2)
107#define MEM_OVRD_EQLEV_SHIFT 2
108#define MEM_OVRD_EQFTC BIT(1)
109#define MEM_OVRD_EQFTC_SHIFT 1
110
111#define SATA_PHY_RX_IO_AND_A2D_OVERRIDES 0x44
112#define MEM_CDR_LOS_SOURCE_MASK GENMASK(10, 9)
113#define MEM_CDR_LOS_SOURCE_SHIFT 9
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +0200114
115#define PLL_IDLE_TIME 100 /* in milliseconds */
116#define PLL_LOCK_TIME 100 /* in milliseconds */
117
Roger Quadroscf608642019-11-06 16:21:16 +0200118enum pipe3_mode { PIPE3_MODE_PCIE = 1,
119 PIPE3_MODE_SATA,
120 PIPE3_MODE_USBSS };
121
Roger Quadros80c69c62019-11-06 16:21:17 +0200122struct pipe3_settings {
123 u8 ana_interface;
124 u8 ana_losd;
125 u8 dig_fastlock;
126 u8 dig_lbw;
127 u8 dig_stepcnt;
128 u8 dig_stl;
129 u8 dig_thr;
130 u8 dig_thr_mode;
131 u8 dig_2ndo_sdm_mode;
132 u8 dig_hs_rate;
133 u8 dig_ovrd_hs_rate;
134 u8 dll_trim_sel;
135 u8 dll_phint_rate;
136 u8 eq_lev;
137 u8 eq_ftc;
138 u8 eq_ctl;
139 u8 eq_ovrd_lev;
140 u8 eq_ovrd_ftc;
141};
142
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +0200143struct omap_pipe3 {
144 void __iomem *pll_ctrl_base;
Roger Quadros80c69c62019-11-06 16:21:17 +0200145 void __iomem *phy_rx;
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +0200146 void __iomem *power_reg;
147 void __iomem *pll_reset_reg;
148 struct pipe3_dpll_map *dpll_map;
Roger Quadroscf608642019-11-06 16:21:16 +0200149 enum pipe3_mode mode;
Roger Quadros80c69c62019-11-06 16:21:17 +0200150 struct pipe3_settings settings;
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +0200151};
152
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +0200153struct pipe3_dpll_params {
154 u16 m;
155 u8 n;
156 u8 freq:3;
157 u8 sd;
158 u32 mf;
159};
160
161struct pipe3_dpll_map {
162 unsigned long rate;
163 struct pipe3_dpll_params params;
164};
165
Roger Quadroscf608642019-11-06 16:21:16 +0200166struct pipe3_data {
167 enum pipe3_mode mode;
168 struct pipe3_dpll_map *dpll_map;
Roger Quadros80c69c62019-11-06 16:21:17 +0200169 struct pipe3_settings settings;
Roger Quadroscf608642019-11-06 16:21:16 +0200170};
171
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +0200172static inline u32 omap_pipe3_readl(void __iomem *addr, unsigned offset)
173{
174 return readl(addr + offset);
175}
176
177static inline void omap_pipe3_writel(void __iomem *addr, unsigned offset,
178 u32 data)
179{
180 writel(data, addr + offset);
181}
182
183static struct pipe3_dpll_params *omap_pipe3_get_dpll_params(struct omap_pipe3
184 *pipe3)
185{
186 u32 rate;
187 struct pipe3_dpll_map *dpll_map = pipe3->dpll_map;
188
189 rate = get_sys_clk_freq();
190
191 for (; dpll_map->rate; dpll_map++) {
192 if (rate == dpll_map->rate)
193 return &dpll_map->params;
194 }
195
196 printf("%s: No DPLL configuration for %u Hz SYS CLK\n",
197 __func__, rate);
198 return NULL;
199}
200
201static int omap_pipe3_wait_lock(struct omap_pipe3 *pipe3)
202{
203 u32 val;
204 int timeout = PLL_LOCK_TIME;
205
206 do {
207 mdelay(1);
208 val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_STATUS);
209 if (val & PLL_LOCK)
210 break;
211 } while (--timeout);
212
213 if (!(val & PLL_LOCK)) {
214 printf("%s: DPLL failed to lock\n", __func__);
215 return -EBUSY;
216 }
217
218 return 0;
219}
220
221static int omap_pipe3_dpll_program(struct omap_pipe3 *pipe3)
222{
223 u32 val;
224 struct pipe3_dpll_params *dpll_params;
225
226 dpll_params = omap_pipe3_get_dpll_params(pipe3);
227 if (!dpll_params) {
228 printf("%s: Invalid DPLL parameters\n", __func__);
229 return -EINVAL;
230 }
231
232 val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_CONFIGURATION1);
233 val &= ~PLL_REGN_MASK;
234 val |= dpll_params->n << PLL_REGN_SHIFT;
235 omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_CONFIGURATION1, val);
236
237 val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_CONFIGURATION2);
Vignesh R5b22df52018-11-29 10:57:38 +0100238 val &= ~(PLL_SELFREQDCO_MASK | PLL_IDLE);
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +0200239 val |= dpll_params->freq << PLL_SELFREQDCO_SHIFT;
240 omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_CONFIGURATION2, val);
241
242 val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_CONFIGURATION1);
243 val &= ~PLL_REGM_MASK;
244 val |= dpll_params->m << PLL_REGM_SHIFT;
245 omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_CONFIGURATION1, val);
246
247 val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_CONFIGURATION4);
248 val &= ~PLL_REGM_F_MASK;
249 val |= dpll_params->mf << PLL_REGM_F_SHIFT;
250 omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_CONFIGURATION4, val);
251
252 val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_CONFIGURATION3);
253 val &= ~PLL_SD_MASK;
254 val |= dpll_params->sd << PLL_SD_SHIFT;
255 omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_CONFIGURATION3, val);
256
257 omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_GO, SET_PLL_GO);
258
259 return omap_pipe3_wait_lock(pipe3);
260}
261
262static void omap_control_pipe3_power(struct omap_pipe3 *pipe3, int on)
263{
264 u32 val, rate;
265
266 val = readl(pipe3->power_reg);
267
268 rate = get_sys_clk_freq();
269 rate = rate/1000000;
270
271 if (on) {
Roger Quadrosed555622019-11-06 16:21:18 +0200272 val &= ~(PIPE3_PHY_PWRCTL_CLK_CMD_MASK |
273 PIPE3_PHY_PWRCTL_CLK_FREQ_MASK);
274 val |= rate << PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT;
275 writel(val, pipe3->power_reg);
276
277 /* Power up TX before RX for SATA & USB */
278 val |= PIPE3_PHY_TX_POWERON;
279 writel(val, pipe3->power_reg);
280
281 val |= PIPE3_PHY_RX_POWERON;
282 writel(val, pipe3->power_reg);
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +0200283 } else {
Roger Quadrosed555622019-11-06 16:21:18 +0200284 val &= ~PIPE3_PHY_PWRCTL_CLK_CMD_MASK;
285 writel(val, pipe3->power_reg);
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +0200286 }
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +0200287}
288
Roger Quadros80c69c62019-11-06 16:21:17 +0200289static void ti_pipe3_calibrate(struct omap_pipe3 *phy)
290{
291 u32 val;
292 struct pipe3_settings *s = &phy->settings;
293
294 val = omap_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_ANA_PROGRAMMABILITY);
295 val &= ~(INTERFACE_MASK | LOSD_MASK | MEM_PLLDIV);
296 val = (s->ana_interface << INTERFACE_SHIFT | s->ana_losd << LOSD_SHIFT);
297 omap_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_ANA_PROGRAMMABILITY, val);
298
299 val = omap_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_DIGITAL_MODES);
300 val &= ~(MEM_HS_RATE_MASK | MEM_OVRD_HS_RATE | MEM_CDR_FASTLOCK |
301 MEM_CDR_LBW_MASK | MEM_CDR_STEPCNT_MASK | MEM_CDR_STL_MASK |
302 MEM_CDR_THR_MASK | MEM_CDR_THR_MODE | MEM_CDR_2NDO_SDM_MODE);
303 val |= s->dig_hs_rate << MEM_HS_RATE_SHIFT |
304 s->dig_ovrd_hs_rate << MEM_OVRD_HS_RATE_SHIFT |
305 s->dig_fastlock << MEM_CDR_FASTLOCK_SHIFT |
306 s->dig_lbw << MEM_CDR_LBW_SHIFT |
307 s->dig_stepcnt << MEM_CDR_STEPCNT_SHIFT |
308 s->dig_stl << MEM_CDR_STL_SHIFT |
309 s->dig_thr << MEM_CDR_THR_SHIFT |
310 s->dig_thr_mode << MEM_CDR_THR_MODE_SHIFT |
311 s->dig_2ndo_sdm_mode << MEM_CDR_2NDO_SDM_MODE_SHIFT;
312 omap_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_DIGITAL_MODES, val);
313
314 val = omap_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_TRIM);
315 val &= ~MEM_DLL_TRIM_SEL_MASK;
316 val |= s->dll_trim_sel << MEM_DLL_TRIM_SHIFT;
317 omap_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_TRIM, val);
318
319 val = omap_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_DLL);
320 val &= ~MEM_DLL_PHINT_RATE_MASK;
321 val |= s->dll_phint_rate << MEM_DLL_PHINT_RATE_SHIFT;
322 omap_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_DLL, val);
323
324 val = omap_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_EQUALIZER);
325 val &= ~(MEM_EQLEV_MASK | MEM_EQFTC_MASK | MEM_EQCTL_MASK |
326 MEM_OVRD_EQLEV | MEM_OVRD_EQFTC);
327 val |= s->eq_lev << MEM_EQLEV_SHIFT |
328 s->eq_ftc << MEM_EQFTC_SHIFT |
329 s->eq_ctl << MEM_EQCTL_SHIFT |
330 s->eq_ovrd_lev << MEM_OVRD_EQLEV_SHIFT |
331 s->eq_ovrd_ftc << MEM_OVRD_EQFTC_SHIFT;
332 omap_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_EQUALIZER, val);
333
334 if (phy->mode == PIPE3_MODE_SATA) {
335 val = omap_pipe3_readl(phy->phy_rx,
336 SATA_PHY_RX_IO_AND_A2D_OVERRIDES);
337 val &= ~MEM_CDR_LOS_SOURCE_MASK;
338 omap_pipe3_writel(phy->phy_rx, SATA_PHY_RX_IO_AND_A2D_OVERRIDES,
339 val);
340 }
341}
342
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +0200343static int pipe3_init(struct phy *phy)
344{
345 int ret;
346 u32 val;
347 struct omap_pipe3 *pipe3 = dev_get_priv(phy->dev);
348
349 /* Program the DPLL only if not locked */
350 val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_STATUS);
351 if (!(val & PLL_LOCK)) {
352 ret = omap_pipe3_dpll_program(pipe3);
353 if (ret)
354 return ret;
Roger Quadros80c69c62019-11-06 16:21:17 +0200355
356 ti_pipe3_calibrate(pipe3);
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +0200357 } else {
358 /* else just bring it out of IDLE mode */
359 val = omap_pipe3_readl(pipe3->pll_ctrl_base,
360 PLL_CONFIGURATION2);
361 if (val & PLL_IDLE) {
362 val &= ~PLL_IDLE;
363 omap_pipe3_writel(pipe3->pll_ctrl_base,
364 PLL_CONFIGURATION2, val);
365 ret = omap_pipe3_wait_lock(pipe3);
366 if (ret)
367 return ret;
368 }
369 }
370 return 0;
371}
372
373static int pipe3_power_on(struct phy *phy)
374{
375 struct omap_pipe3 *pipe3 = dev_get_priv(phy->dev);
376
377 /* Power up the PHY */
378 omap_control_pipe3_power(pipe3, 1);
379
380 return 0;
381}
382
383static int pipe3_power_off(struct phy *phy)
384{
385 struct omap_pipe3 *pipe3 = dev_get_priv(phy->dev);
386
387 /* Power down the PHY */
388 omap_control_pipe3_power(pipe3, 0);
389
390 return 0;
391}
392
393static int pipe3_exit(struct phy *phy)
394{
395 u32 val;
396 int timeout = PLL_IDLE_TIME;
397 struct omap_pipe3 *pipe3 = dev_get_priv(phy->dev);
398
399 pipe3_power_off(phy);
400
401 /* Put DPLL in IDLE mode */
402 val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_CONFIGURATION2);
403 val |= PLL_IDLE;
404 omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_CONFIGURATION2, val);
405
406 /* wait for LDO and Oscillator to power down */
407 do {
408 mdelay(1);
409 val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_STATUS);
410 if ((val & PLL_TICOPWDN) && (val & PLL_LDOPWDN))
411 break;
412 } while (--timeout);
413
414 if (!(val & PLL_TICOPWDN) || !(val & PLL_LDOPWDN)) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900415 pr_err("%s: Failed to power down DPLL: PLL_STATUS 0x%x\n",
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +0200416 __func__, val);
417 return -EBUSY;
418 }
419
Vignesh R5b22df52018-11-29 10:57:38 +0100420 if (pipe3->pll_reset_reg) {
421 val = readl(pipe3->pll_reset_reg);
422 writel(val | SATA_PLL_SOFT_RESET, pipe3->pll_reset_reg);
423 mdelay(1);
424 writel(val & ~SATA_PLL_SOFT_RESET, pipe3->pll_reset_reg);
425 }
426
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +0200427 return 0;
428}
429
430static void *get_reg(struct udevice *dev, const char *name)
431{
432 struct udevice *syscon;
433 struct regmap *regmap;
434 const fdt32_t *cell;
435 int len, err;
436 void *base;
437
438 err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
439 name, &syscon);
440 if (err) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900441 pr_err("unable to find syscon device for %s (%d)\n",
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +0200442 name, err);
443 return NULL;
444 }
445
446 regmap = syscon_get_regmap(syscon);
447 if (IS_ERR(regmap)) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900448 pr_err("unable to find regmap for %s (%ld)\n",
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +0200449 name, PTR_ERR(regmap));
450 return NULL;
451 }
452
Simon Glass7a494432017-05-17 17:18:09 -0600453 cell = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), name,
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +0200454 &len);
455 if (len < 2*sizeof(fdt32_t)) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900456 pr_err("offset not available for %s\n", name);
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +0200457 return NULL;
458 }
459
460 base = regmap_get_range(regmap, 0);
461 if (!base)
462 return NULL;
463
464 return fdtdec_get_number(cell + 1, 1) + base;
465}
466
467static int pipe3_phy_probe(struct udevice *dev)
468{
469 fdt_addr_t addr;
470 fdt_size_t sz;
471 struct omap_pipe3 *pipe3 = dev_get_priv(dev);
Roger Quadroscf608642019-11-06 16:21:16 +0200472 struct pipe3_data *data;
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +0200473
Roger Quadros80c69c62019-11-06 16:21:17 +0200474 /* PHY_RX */
475 addr = devfdt_get_addr_size_index(dev, 0, &sz);
476 if (addr == FDT_ADDR_T_NONE) {
477 pr_err("missing phy_rx address\n");
478 return -EINVAL;
479 }
480
481 pipe3->phy_rx = map_physmem(addr, sz, MAP_NOCACHE);
482 if (!pipe3->phy_rx) {
483 pr_err("unable to remap phy_rx\n");
484 return -EINVAL;
485 }
486
487 /* PLLCTRL */
Simon Glassba1dea42017-05-17 17:18:05 -0600488 addr = devfdt_get_addr_size_index(dev, 2, &sz);
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +0200489 if (addr == FDT_ADDR_T_NONE) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900490 pr_err("missing pll ctrl address\n");
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +0200491 return -EINVAL;
492 }
493
494 pipe3->pll_ctrl_base = map_physmem(addr, sz, MAP_NOCACHE);
495 if (!pipe3->pll_ctrl_base) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900496 pr_err("unable to remap pll ctrl\n");
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +0200497 return -EINVAL;
498 }
499
500 pipe3->power_reg = get_reg(dev, "syscon-phy-power");
501 if (!pipe3->power_reg)
502 return -EINVAL;
503
Roger Quadroscf608642019-11-06 16:21:16 +0200504 data = (struct pipe3_data *)dev_get_driver_data(dev);
505 pipe3->mode = data->mode;
506 pipe3->dpll_map = data->dpll_map;
Roger Quadros80c69c62019-11-06 16:21:17 +0200507 pipe3->settings = data->settings;
Roger Quadroscf608642019-11-06 16:21:16 +0200508
509 if (pipe3->mode == PIPE3_MODE_SATA) {
Vignesh R5b22df52018-11-29 10:57:38 +0100510 pipe3->pll_reset_reg = get_reg(dev, "syscon-pllreset");
511 if (!pipe3->pll_reset_reg)
512 return -EINVAL;
513 }
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +0200514
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +0200515 return 0;
516}
517
518static struct pipe3_dpll_map dpll_map_sata[] = {
Roger Quadros5015e922019-11-06 16:21:15 +0200519 {12000000, {625, 4, 4, 6, 0} }, /* 12 MHz */
520 {16800000, {625, 6, 4, 7, 0} }, /* 16.8 MHz */
521 {19200000, {625, 7, 4, 6, 0} }, /* 19.2 MHz */
522 {20000000, {750, 9, 4, 6, 0} }, /* 20 MHz */
523 {26000000, {750, 12, 4, 6, 0} }, /* 26 MHz */
524 {38400000, {625, 15, 4, 6, 0} }, /* 38.4 MHz */
525 { }, /* Terminator */
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +0200526};
527
Vignesh R5b22df52018-11-29 10:57:38 +0100528static struct pipe3_dpll_map dpll_map_usb[] = {
529 {12000000, {1250, 5, 4, 20, 0} }, /* 12 MHz */
530 {16800000, {3125, 20, 4, 20, 0} }, /* 16.8 MHz */
531 {19200000, {1172, 8, 4, 20, 65537} }, /* 19.2 MHz */
532 {20000000, {1000, 7, 4, 10, 0} }, /* 20 MHz */
533 {26000000, {1250, 12, 4, 20, 0} }, /* 26 MHz */
534 {38400000, {3125, 47, 4, 20, 92843} }, /* 38.4 MHz */
535 { }, /* Terminator */
536};
537
Roger Quadroscf608642019-11-06 16:21:16 +0200538static struct pipe3_data data_usb = {
539 .mode = PIPE3_MODE_USBSS,
540 .dpll_map = dpll_map_usb,
Roger Quadros80c69c62019-11-06 16:21:17 +0200541 .settings = {
542 /* DRA75x TRM Table 26-17. Preferred USB3_PHY_RX SCP Register Settings */
543 .ana_interface = INTERFACE_MODE_USBSS,
544 .ana_losd = 0xa,
545 .dig_fastlock = 1,
546 .dig_lbw = 3,
547 .dig_stepcnt = 0,
548 .dig_stl = 0x3,
549 .dig_thr = 1,
550 .dig_thr_mode = 1,
551 .dig_2ndo_sdm_mode = 0,
552 .dig_hs_rate = 0,
553 .dig_ovrd_hs_rate = 1,
554 .dll_trim_sel = 0x2,
555 .dll_phint_rate = 0x3,
556 .eq_lev = 0,
557 .eq_ftc = 0,
558 .eq_ctl = 0x9,
559 .eq_ovrd_lev = 0,
560 .eq_ovrd_ftc = 0,
561 },
Roger Quadroscf608642019-11-06 16:21:16 +0200562};
563
564static struct pipe3_data data_sata = {
565 .mode = PIPE3_MODE_SATA,
566 .dpll_map = dpll_map_sata,
Roger Quadros80c69c62019-11-06 16:21:17 +0200567 .settings = {
568 /* DRA75x TRM Table 26-9. Preferred SATA_PHY_RX SCP Register Settings */
569 .ana_interface = INTERFACE_MODE_SATA_3P0,
570 .ana_losd = 0x5,
571 .dig_fastlock = 1,
572 .dig_lbw = 3,
573 .dig_stepcnt = 0,
574 .dig_stl = 0x3,
575 .dig_thr = 1,
576 .dig_thr_mode = 1,
577 .dig_2ndo_sdm_mode = 0,
578 .dig_hs_rate = 0, /* Not in TRM preferred settings */
579 .dig_ovrd_hs_rate = 0, /* Not in TRM preferred settings */
580 .dll_trim_sel = 0x1,
581 .dll_phint_rate = 0x2, /* for 1.5 GHz DPLL clock */
582 .eq_lev = 0,
583 .eq_ftc = 0x1f,
584 .eq_ctl = 0,
585 .eq_ovrd_lev = 1,
586 .eq_ovrd_ftc = 1,
587 },
Roger Quadroscf608642019-11-06 16:21:16 +0200588};
589
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +0200590static const struct udevice_id pipe3_phy_ids[] = {
Roger Quadroscf608642019-11-06 16:21:16 +0200591 { .compatible = "ti,phy-pipe3-sata", .data = (ulong)&data_sata },
592 { .compatible = "ti,omap-usb3", .data = (ulong)&data_usb},
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +0200593 { }
594};
595
596static struct phy_ops pipe3_phy_ops = {
597 .init = pipe3_init,
598 .power_on = pipe3_power_on,
599 .power_off = pipe3_power_off,
600 .exit = pipe3_exit,
601};
602
603U_BOOT_DRIVER(pipe3_phy) = {
604 .name = "pipe3_phy",
605 .id = UCLASS_PHY,
606 .of_match = pipe3_phy_ids,
607 .ops = &pipe3_phy_ops,
608 .probe = pipe3_phy_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700609 .priv_auto = sizeof(struct omap_pipe3),
Jean-Jacques Hiblot73e95eb2017-04-24 11:51:29 +0200610};