Merge git://git.denx.de/u-boot-video
[platform/kernel/u-boot.git] / drivers / phy / ti-pipe3-phy.c
1 /*
2  * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
3  * Written by Jean-Jacques Hiblot  <jjhiblot@ti.com>
4  *
5  * SPDX-License-Identifier:     GPL-2.0+
6  */
7
8 #include <common.h>
9 #include <dm.h>
10 #include <dm/device.h>
11 #include <generic-phy.h>
12 #include <asm/io.h>
13 #include <asm/arch/sys_proto.h>
14 #include <syscon.h>
15 #include <regmap.h>
16
17 /* PLLCTRL Registers */
18 #define PLL_STATUS              0x00000004
19 #define PLL_GO                  0x00000008
20 #define PLL_CONFIGURATION1      0x0000000C
21 #define PLL_CONFIGURATION2      0x00000010
22 #define PLL_CONFIGURATION3      0x00000014
23 #define PLL_CONFIGURATION4      0x00000020
24
25 #define PLL_REGM_MASK           0x001FFE00
26 #define PLL_REGM_SHIFT          9
27 #define PLL_REGM_F_MASK         0x0003FFFF
28 #define PLL_REGM_F_SHIFT        0
29 #define PLL_REGN_MASK           0x000001FE
30 #define PLL_REGN_SHIFT          1
31 #define PLL_SELFREQDCO_MASK     0x0000000E
32 #define PLL_SELFREQDCO_SHIFT    1
33 #define PLL_SD_MASK             0x0003FC00
34 #define PLL_SD_SHIFT            10
35 #define SET_PLL_GO              0x1
36 #define PLL_TICOPWDN            BIT(16)
37 #define PLL_LDOPWDN             BIT(15)
38 #define PLL_LOCK                0x2
39 #define PLL_IDLE                0x1
40
41 /* Software rest for the SATA PLL (in CTRL_CORE_SMA_SW_0 register)*/
42 #define SATA_PLL_SOFT_RESET (1<<18)
43
44 /* PHY POWER CONTROL Register */
45 #define OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK         0x003FC000
46 #define OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT        0xE
47
48 #define OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_MASK        0xFFC00000
49 #define OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT       0x16
50
51 #define OMAP_CTRL_PIPE3_PHY_TX_RX_POWERON       0x3
52 #define OMAP_CTRL_PIPE3_PHY_TX_RX_POWEROFF      0x0
53
54
55 #define PLL_IDLE_TIME   100     /* in milliseconds */
56 #define PLL_LOCK_TIME   100     /* in milliseconds */
57
58 struct omap_pipe3 {
59         void __iomem            *pll_ctrl_base;
60         void __iomem            *power_reg;
61         void __iomem            *pll_reset_reg;
62         struct pipe3_dpll_map   *dpll_map;
63 };
64
65
66 struct pipe3_dpll_params {
67         u16     m;
68         u8      n;
69         u8      freq:3;
70         u8      sd;
71         u32     mf;
72 };
73
74 struct pipe3_dpll_map {
75         unsigned long rate;
76         struct pipe3_dpll_params params;
77 };
78
79 static inline u32 omap_pipe3_readl(void __iomem *addr, unsigned offset)
80 {
81         return readl(addr + offset);
82 }
83
84 static inline void omap_pipe3_writel(void __iomem *addr, unsigned offset,
85                 u32 data)
86 {
87         writel(data, addr + offset);
88 }
89
90 static struct pipe3_dpll_params *omap_pipe3_get_dpll_params(struct omap_pipe3
91                                                                         *pipe3)
92 {
93         u32 rate;
94         struct pipe3_dpll_map *dpll_map = pipe3->dpll_map;
95
96         rate = get_sys_clk_freq();
97
98         for (; dpll_map->rate; dpll_map++) {
99                 if (rate == dpll_map->rate)
100                         return &dpll_map->params;
101         }
102
103         printf("%s: No DPLL configuration for %u Hz SYS CLK\n",
104                __func__, rate);
105         return NULL;
106 }
107
108 static int omap_pipe3_wait_lock(struct omap_pipe3 *pipe3)
109 {
110         u32 val;
111         int timeout = PLL_LOCK_TIME;
112
113         do {
114                 mdelay(1);
115                 val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_STATUS);
116                 if (val & PLL_LOCK)
117                         break;
118         } while (--timeout);
119
120         if (!(val & PLL_LOCK)) {
121                 printf("%s: DPLL failed to lock\n", __func__);
122                 return -EBUSY;
123         }
124
125         return 0;
126 }
127
128 static int omap_pipe3_dpll_program(struct omap_pipe3 *pipe3)
129 {
130         u32                     val;
131         struct pipe3_dpll_params *dpll_params;
132
133         dpll_params = omap_pipe3_get_dpll_params(pipe3);
134         if (!dpll_params) {
135                 printf("%s: Invalid DPLL parameters\n", __func__);
136                 return -EINVAL;
137         }
138
139         val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_CONFIGURATION1);
140         val &= ~PLL_REGN_MASK;
141         val |= dpll_params->n << PLL_REGN_SHIFT;
142         omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_CONFIGURATION1, val);
143
144         val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_CONFIGURATION2);
145         val &= ~PLL_SELFREQDCO_MASK;
146         val |= dpll_params->freq << PLL_SELFREQDCO_SHIFT;
147         omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_CONFIGURATION2, val);
148
149         val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_CONFIGURATION1);
150         val &= ~PLL_REGM_MASK;
151         val |= dpll_params->m << PLL_REGM_SHIFT;
152         omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_CONFIGURATION1, val);
153
154         val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_CONFIGURATION4);
155         val &= ~PLL_REGM_F_MASK;
156         val |= dpll_params->mf << PLL_REGM_F_SHIFT;
157         omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_CONFIGURATION4, val);
158
159         val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_CONFIGURATION3);
160         val &= ~PLL_SD_MASK;
161         val |= dpll_params->sd << PLL_SD_SHIFT;
162         omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_CONFIGURATION3, val);
163
164         omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_GO, SET_PLL_GO);
165
166         return omap_pipe3_wait_lock(pipe3);
167 }
168
169 static void omap_control_pipe3_power(struct omap_pipe3 *pipe3, int on)
170 {
171         u32 val, rate;
172
173         val = readl(pipe3->power_reg);
174
175         rate = get_sys_clk_freq();
176         rate = rate/1000000;
177
178         if (on) {
179                 val &= ~(OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK |
180                                 OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_MASK);
181                 val |= OMAP_CTRL_PIPE3_PHY_TX_RX_POWERON <<
182                         OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT;
183                 val |= rate <<
184                         OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT;
185         } else {
186                 val &= ~OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK;
187                 val |= OMAP_CTRL_PIPE3_PHY_TX_RX_POWEROFF <<
188                         OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT;
189         }
190
191         writel(val, pipe3->power_reg);
192 }
193
194 static int pipe3_init(struct phy *phy)
195 {
196         int ret;
197         u32 val;
198         struct omap_pipe3 *pipe3 = dev_get_priv(phy->dev);
199
200         /* Program the DPLL only if not locked */
201         val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_STATUS);
202         if (!(val & PLL_LOCK)) {
203                 ret = omap_pipe3_dpll_program(pipe3);
204                 if (ret)
205                         return ret;
206         } else {
207                 /* else just bring it out of IDLE mode */
208                 val = omap_pipe3_readl(pipe3->pll_ctrl_base,
209                                        PLL_CONFIGURATION2);
210                 if (val & PLL_IDLE) {
211                         val &= ~PLL_IDLE;
212                         omap_pipe3_writel(pipe3->pll_ctrl_base,
213                                           PLL_CONFIGURATION2, val);
214                         ret = omap_pipe3_wait_lock(pipe3);
215                         if (ret)
216                                 return ret;
217                 }
218         }
219         return 0;
220 }
221
222 static int pipe3_power_on(struct phy *phy)
223 {
224         struct omap_pipe3 *pipe3 = dev_get_priv(phy->dev);
225
226         /* Power up the PHY */
227         omap_control_pipe3_power(pipe3, 1);
228
229         return 0;
230 }
231
232 static int pipe3_power_off(struct phy *phy)
233 {
234         struct omap_pipe3 *pipe3 = dev_get_priv(phy->dev);
235
236         /* Power down the PHY */
237         omap_control_pipe3_power(pipe3, 0);
238
239         return 0;
240 }
241
242 static int pipe3_exit(struct phy *phy)
243 {
244         u32 val;
245         int timeout = PLL_IDLE_TIME;
246         struct omap_pipe3 *pipe3 = dev_get_priv(phy->dev);
247
248         pipe3_power_off(phy);
249
250         /* Put DPLL in IDLE mode */
251         val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_CONFIGURATION2);
252         val |= PLL_IDLE;
253         omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_CONFIGURATION2, val);
254
255         /* wait for LDO and Oscillator to power down */
256         do {
257                 mdelay(1);
258                 val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_STATUS);
259                 if ((val & PLL_TICOPWDN) && (val & PLL_LDOPWDN))
260                         break;
261         } while (--timeout);
262
263         if (!(val & PLL_TICOPWDN) || !(val & PLL_LDOPWDN)) {
264                 pr_err("%s: Failed to power down DPLL: PLL_STATUS 0x%x\n",
265                       __func__, val);
266                 return -EBUSY;
267         }
268
269         val = readl(pipe3->pll_reset_reg);
270         writel(val | SATA_PLL_SOFT_RESET, pipe3->pll_reset_reg);
271         mdelay(1);
272         writel(val & ~SATA_PLL_SOFT_RESET, pipe3->pll_reset_reg);
273         return 0;
274 }
275
276 static void *get_reg(struct udevice *dev, const char *name)
277 {
278         struct udevice *syscon;
279         struct regmap *regmap;
280         const fdt32_t *cell;
281         int len, err;
282         void *base;
283
284         err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
285                                            name, &syscon);
286         if (err) {
287                 pr_err("unable to find syscon device for %s (%d)\n",
288                       name, err);
289                 return NULL;
290         }
291
292         regmap = syscon_get_regmap(syscon);
293         if (IS_ERR(regmap)) {
294                 pr_err("unable to find regmap for %s (%ld)\n",
295                       name, PTR_ERR(regmap));
296                 return NULL;
297         }
298
299         cell = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), name,
300                            &len);
301         if (len < 2*sizeof(fdt32_t)) {
302                 pr_err("offset not available for %s\n", name);
303                 return NULL;
304         }
305
306         base = regmap_get_range(regmap, 0);
307         if (!base)
308                 return NULL;
309
310         return fdtdec_get_number(cell + 1, 1) + base;
311 }
312
313 static int pipe3_phy_probe(struct udevice *dev)
314 {
315         fdt_addr_t addr;
316         fdt_size_t sz;
317         struct omap_pipe3 *pipe3 = dev_get_priv(dev);
318
319         addr = devfdt_get_addr_size_index(dev, 2, &sz);
320         if (addr == FDT_ADDR_T_NONE) {
321                 pr_err("missing pll ctrl address\n");
322                 return -EINVAL;
323         }
324
325         pipe3->pll_ctrl_base = map_physmem(addr, sz, MAP_NOCACHE);
326         if (!pipe3->pll_ctrl_base) {
327                 pr_err("unable to remap pll ctrl\n");
328                 return -EINVAL;
329         }
330
331         pipe3->power_reg = get_reg(dev, "syscon-phy-power");
332         if (!pipe3->power_reg)
333                 return -EINVAL;
334
335         pipe3->pll_reset_reg = get_reg(dev, "syscon-pllreset");
336         if (!pipe3->pll_reset_reg)
337                 return -EINVAL;
338
339         pipe3->dpll_map = (struct pipe3_dpll_map *)dev_get_driver_data(dev);
340
341         return 0;
342 }
343
344 static struct pipe3_dpll_map dpll_map_sata[] = {
345         {12000000, {1000, 7, 4, 6, 0} },        /* 12 MHz */
346         {16800000, {714, 7, 4, 6, 0} },         /* 16.8 MHz */
347         {19200000, {625, 7, 4, 6, 0} },         /* 19.2 MHz */
348         {20000000, {600, 7, 4, 6, 0} },         /* 20 MHz */
349         {26000000, {461, 7, 4, 6, 0} },         /* 26 MHz */
350         {38400000, {312, 7, 4, 6, 0} },         /* 38.4 MHz */
351         { },                                    /* Terminator */
352 };
353
354 static const struct udevice_id pipe3_phy_ids[] = {
355         { .compatible = "ti,phy-pipe3-sata", .data = (ulong)&dpll_map_sata },
356         { }
357 };
358
359 static struct phy_ops pipe3_phy_ops = {
360         .init = pipe3_init,
361         .power_on = pipe3_power_on,
362         .power_off = pipe3_power_off,
363         .exit = pipe3_exit,
364 };
365
366 U_BOOT_DRIVER(pipe3_phy) = {
367         .name   = "pipe3_phy",
368         .id     = UCLASS_PHY,
369         .of_match = pipe3_phy_ids,
370         .ops = &pipe3_phy_ops,
371         .probe = pipe3_phy_probe,
372         .priv_auto_alloc_size = sizeof(struct omap_pipe3),
373 };