blob: 9c1dcfae52456c68c6600c027dbc810bcb5b824e [file] [log] [blame]
Tom Rini624d2ca2018-05-20 09:47:45 -04001// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
Patrice Chotard3b291212018-04-27 11:01:55 +02002/*
3 * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
4 */
5
Patrick Delaunay0d5fbad2020-11-06 19:01:51 +01006#define LOG_CATEGORY UCLASS_PHY
7
Patrice Chotard3b291212018-04-27 11:01:55 +02008#include <common.h>
9#include <clk.h>
10#include <div64.h>
11#include <dm.h>
12#include <fdtdec.h>
13#include <generic-phy.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060014#include <log.h>
Patrice Chotard3b291212018-04-27 11:01:55 +020015#include <reset.h>
16#include <syscon.h>
17#include <usb.h>
18#include <asm/io.h>
Simon Glass336d4612020-02-03 07:36:16 -070019#include <dm/device_compat.h>
Patrice Chotard3b291212018-04-27 11:01:55 +020020#include <linux/bitops.h>
Simon Glassc05ed002020-05-10 11:40:11 -060021#include <linux/delay.h>
Patrice Chotard3b291212018-04-27 11:01:55 +020022#include <power/regulator.h>
23
24/* USBPHYC registers */
25#define STM32_USBPHYC_PLL 0x0
26#define STM32_USBPHYC_MISC 0x8
27
28/* STM32_USBPHYC_PLL bit fields */
29#define PLLNDIV GENMASK(6, 0)
30#define PLLNDIV_SHIFT 0
31#define PLLFRACIN GENMASK(25, 10)
32#define PLLFRACIN_SHIFT 10
33#define PLLEN BIT(26)
34#define PLLSTRB BIT(27)
35#define PLLSTRBYP BIT(28)
36#define PLLFRACCTL BIT(29)
37#define PLLDITHEN0 BIT(30)
38#define PLLDITHEN1 BIT(31)
39
40/* STM32_USBPHYC_MISC bit fields */
41#define SWITHOST BIT(0)
42
43#define MAX_PHYS 2
44
Patrick Delaunay901f6952019-03-29 15:42:13 +010045/* max 100 us for PLL lock and 100 us for PHY init */
46#define PLL_INIT_TIME_US 200
Patrice Chotard3b291212018-04-27 11:01:55 +020047#define PLL_PWR_DOWN_TIME_US 5
48#define PLL_FVCO 2880 /* in MHz */
49#define PLL_INFF_MIN_RATE 19200000 /* in Hz */
50#define PLL_INFF_MAX_RATE 38400000 /* in Hz */
51
52struct pll_params {
53 u8 ndiv;
54 u16 frac;
55};
56
57struct stm32_usbphyc {
58 fdt_addr_t base;
59 struct clk clk;
Patrick Delaunayc50151d2019-03-29 15:42:11 +010060 struct udevice *vdda1v1;
61 struct udevice *vdda1v8;
Patrice Chotard3b291212018-04-27 11:01:55 +020062 struct stm32_usbphyc_phy {
63 struct udevice *vdd;
Patrick Delaunayc4801382020-10-15 14:50:57 +020064 struct udevice *vbus;
Patrice Chotard3b291212018-04-27 11:01:55 +020065 bool init;
66 bool powered;
67 } phys[MAX_PHYS];
68};
69
Patrick Delaunaye1904ab2019-03-29 15:42:12 +010070static void stm32_usbphyc_get_pll_params(u32 clk_rate,
71 struct pll_params *pll_params)
Patrice Chotard3b291212018-04-27 11:01:55 +020072{
73 unsigned long long fvco, ndiv, frac;
74
75 /*
76 * | FVCO = INFF*2*(NDIV + FRACT/2^16 ) when DITHER_DISABLE[1] = 1
77 * | FVCO = 2880MHz
78 * | NDIV = integer part of input bits to set the LDF
79 * | FRACT = fractional part of input bits to set the LDF
80 * => PLLNDIV = integer part of (FVCO / (INFF*2))
81 * => PLLFRACIN = fractional part of(FVCO / INFF*2) * 2^16
82 * <=> PLLFRACIN = ((FVCO / (INFF*2)) - PLLNDIV) * 2^16
83 */
84 fvco = (unsigned long long)PLL_FVCO * 1000000; /* In Hz */
85
86 ndiv = fvco;
87 do_div(ndiv, (clk_rate * 2));
88 pll_params->ndiv = (u8)ndiv;
89
90 frac = fvco * (1 << 16);
91 do_div(frac, (clk_rate * 2));
92 frac = frac - (ndiv * (1 << 16));
93 pll_params->frac = (u16)frac;
94}
95
96static int stm32_usbphyc_pll_init(struct stm32_usbphyc *usbphyc)
97{
98 struct pll_params pll_params;
99 u32 clk_rate = clk_get_rate(&usbphyc->clk);
100 u32 usbphyc_pll;
101
102 if ((clk_rate < PLL_INFF_MIN_RATE) || (clk_rate > PLL_INFF_MAX_RATE)) {
Patrick Delaunay0d5fbad2020-11-06 19:01:51 +0100103 log_debug("input clk freq (%dHz) out of range\n",
104 clk_rate);
Patrice Chotard3b291212018-04-27 11:01:55 +0200105 return -EINVAL;
106 }
107
108 stm32_usbphyc_get_pll_params(clk_rate, &pll_params);
109
110 usbphyc_pll = PLLDITHEN1 | PLLDITHEN0 | PLLSTRBYP;
111 usbphyc_pll |= ((pll_params.ndiv << PLLNDIV_SHIFT) & PLLNDIV);
112
113 if (pll_params.frac) {
114 usbphyc_pll |= PLLFRACCTL;
115 usbphyc_pll |= ((pll_params.frac << PLLFRACIN_SHIFT)
116 & PLLFRACIN);
117 }
118
119 writel(usbphyc_pll, usbphyc->base + STM32_USBPHYC_PLL);
120
Patrick Delaunay0d5fbad2020-11-06 19:01:51 +0100121 log_debug("input clk freq=%dHz, ndiv=%d, frac=%d\n",
122 clk_rate, pll_params.ndiv, pll_params.frac);
Patrice Chotard3b291212018-04-27 11:01:55 +0200123
124 return 0;
125}
126
127static bool stm32_usbphyc_is_init(struct stm32_usbphyc *usbphyc)
128{
129 int i;
130
131 for (i = 0; i < MAX_PHYS; i++) {
132 if (usbphyc->phys[i].init)
133 return true;
134 }
135
136 return false;
137}
138
139static bool stm32_usbphyc_is_powered(struct stm32_usbphyc *usbphyc)
140{
141 int i;
142
143 for (i = 0; i < MAX_PHYS; i++) {
144 if (usbphyc->phys[i].powered)
145 return true;
146 }
147
148 return false;
149}
150
151static int stm32_usbphyc_phy_init(struct phy *phy)
152{
153 struct stm32_usbphyc *usbphyc = dev_get_priv(phy->dev);
154 struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys + phy->id;
155 bool pllen = readl(usbphyc->base + STM32_USBPHYC_PLL) & PLLEN ?
156 true : false;
157 int ret;
158
Patrick Delaunay0d5fbad2020-11-06 19:01:51 +0100159 dev_dbg(phy->dev, "phy ID = %lu\n", phy->id);
Patrice Chotard3b291212018-04-27 11:01:55 +0200160 /* Check if one phy port has already configured the pll */
161 if (pllen && stm32_usbphyc_is_init(usbphyc))
162 goto initialized;
163
Patrick Delaunaye1904ab2019-03-29 15:42:12 +0100164 if (usbphyc->vdda1v1) {
165 ret = regulator_set_enable(usbphyc->vdda1v1, true);
166 if (ret)
167 return ret;
168 }
169
170 if (usbphyc->vdda1v8) {
171 ret = regulator_set_enable(usbphyc->vdda1v8, true);
172 if (ret)
173 return ret;
174 }
175
Patrice Chotard3b291212018-04-27 11:01:55 +0200176 if (pllen) {
177 clrbits_le32(usbphyc->base + STM32_USBPHYC_PLL, PLLEN);
178 udelay(PLL_PWR_DOWN_TIME_US);
179 }
180
181 ret = stm32_usbphyc_pll_init(usbphyc);
182 if (ret)
183 return ret;
184
185 setbits_le32(usbphyc->base + STM32_USBPHYC_PLL, PLLEN);
186
Patrick Delaunay901f6952019-03-29 15:42:13 +0100187 /* We must wait PLL_INIT_TIME_US before using PHY */
188 udelay(PLL_INIT_TIME_US);
Patrice Chotard3b291212018-04-27 11:01:55 +0200189
190 if (!(readl(usbphyc->base + STM32_USBPHYC_PLL) & PLLEN))
191 return -EIO;
192
193initialized:
194 usbphyc_phy->init = true;
195
196 return 0;
197}
198
199static int stm32_usbphyc_phy_exit(struct phy *phy)
200{
201 struct stm32_usbphyc *usbphyc = dev_get_priv(phy->dev);
202 struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys + phy->id;
Patrick Delaunaye1904ab2019-03-29 15:42:12 +0100203 int ret;
Patrice Chotard3b291212018-04-27 11:01:55 +0200204
Patrick Delaunay0d5fbad2020-11-06 19:01:51 +0100205 dev_dbg(phy->dev, "phy ID = %lu\n", phy->id);
Patrice Chotard3b291212018-04-27 11:01:55 +0200206 usbphyc_phy->init = false;
207
208 /* Check if other phy port requires pllen */
209 if (stm32_usbphyc_is_init(usbphyc))
210 return 0;
211
212 clrbits_le32(usbphyc->base + STM32_USBPHYC_PLL, PLLEN);
213
214 /*
215 * We must wait PLL_PWR_DOWN_TIME_US before checking that PLLEN
216 * bit is still clear
217 */
218 udelay(PLL_PWR_DOWN_TIME_US);
219
220 if (readl(usbphyc->base + STM32_USBPHYC_PLL) & PLLEN)
221 return -EIO;
222
Patrick Delaunaye1904ab2019-03-29 15:42:12 +0100223 if (usbphyc->vdda1v1) {
224 ret = regulator_set_enable(usbphyc->vdda1v1, false);
225 if (ret)
226 return ret;
227 }
228
229 if (usbphyc->vdda1v8) {
230 ret = regulator_set_enable(usbphyc->vdda1v8, false);
231 if (ret)
232 return ret;
233 }
234
Patrice Chotard3b291212018-04-27 11:01:55 +0200235 return 0;
236}
237
238static int stm32_usbphyc_phy_power_on(struct phy *phy)
239{
240 struct stm32_usbphyc *usbphyc = dev_get_priv(phy->dev);
241 struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys + phy->id;
242 int ret;
243
Patrick Delaunay0d5fbad2020-11-06 19:01:51 +0100244 dev_dbg(phy->dev, "phy ID = %lu\n", phy->id);
Patrick Delaunaye1904ab2019-03-29 15:42:12 +0100245 if (usbphyc_phy->vdd) {
246 ret = regulator_set_enable(usbphyc_phy->vdd, true);
Patrice Chotard3b291212018-04-27 11:01:55 +0200247 if (ret)
248 return ret;
249 }
Patrick Delaunayc4801382020-10-15 14:50:57 +0200250 if (usbphyc_phy->vbus) {
251 ret = regulator_set_enable(usbphyc_phy->vbus, true);
252 if (ret)
253 return ret;
254 }
Patrice Chotard3b291212018-04-27 11:01:55 +0200255
256 usbphyc_phy->powered = true;
257
258 return 0;
259}
260
261static int stm32_usbphyc_phy_power_off(struct phy *phy)
262{
263 struct stm32_usbphyc *usbphyc = dev_get_priv(phy->dev);
264 struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys + phy->id;
265 int ret;
266
Patrick Delaunay0d5fbad2020-11-06 19:01:51 +0100267 dev_dbg(phy->dev, "phy ID = %lu\n", phy->id);
Patrice Chotard3b291212018-04-27 11:01:55 +0200268 usbphyc_phy->powered = false;
269
270 if (stm32_usbphyc_is_powered(usbphyc))
271 return 0;
272
Patrick Delaunayc4801382020-10-15 14:50:57 +0200273 if (usbphyc_phy->vbus) {
274 ret = regulator_set_enable(usbphyc_phy->vbus, false);
275 if (ret)
276 return ret;
277 }
Patrick Delaunaye1904ab2019-03-29 15:42:12 +0100278 if (usbphyc_phy->vdd) {
Patrick Delaunay9f9191a2020-07-03 19:13:02 +0200279 ret = regulator_set_enable_if_allowed(usbphyc_phy->vdd, false);
Patrice Chotard3b291212018-04-27 11:01:55 +0200280 if (ret)
281 return ret;
282 }
283
284 return 0;
285}
286
Patrick Delaunayc4801382020-10-15 14:50:57 +0200287static int stm32_usbphyc_get_regulator(ofnode node,
Patrice Chotard3b291212018-04-27 11:01:55 +0200288 char *supply_name,
289 struct udevice **regulator)
290{
291 struct ofnode_phandle_args regulator_phandle;
292 int ret;
293
294 ret = ofnode_parse_phandle_with_args(node, supply_name,
295 NULL, 0, 0,
296 &regulator_phandle);
Patrick Delaunayc4801382020-10-15 14:50:57 +0200297 if (ret)
Patrice Chotard3b291212018-04-27 11:01:55 +0200298 return ret;
Patrice Chotard3b291212018-04-27 11:01:55 +0200299
300 ret = uclass_get_device_by_ofnode(UCLASS_REGULATOR,
301 regulator_phandle.node,
302 regulator);
Patrick Delaunayc4801382020-10-15 14:50:57 +0200303 if (ret)
Patrice Chotard3b291212018-04-27 11:01:55 +0200304 return ret;
Patrice Chotard3b291212018-04-27 11:01:55 +0200305
306 return 0;
307}
308
309static int stm32_usbphyc_of_xlate(struct phy *phy,
310 struct ofnode_phandle_args *args)
311{
Patrick Delaunay1655f2d2019-03-29 15:42:10 +0100312 if (args->args_count < 1)
313 return -ENODEV;
Patrice Chotard3b291212018-04-27 11:01:55 +0200314
315 if (args->args[0] >= MAX_PHYS)
316 return -ENODEV;
317
Patrick Delaunay1655f2d2019-03-29 15:42:10 +0100318 phy->id = args->args[0];
319
320 if ((phy->id == 0 && args->args_count != 1) ||
321 (phy->id == 1 && args->args_count != 2)) {
Sean Anderson0aeaca62020-09-15 10:45:06 -0400322 dev_err(phy->dev, "invalid number of cells for phy port%ld\n",
Patrick Delaunay1655f2d2019-03-29 15:42:10 +0100323 phy->id);
324 return -EINVAL;
325 }
Patrice Chotard3b291212018-04-27 11:01:55 +0200326
327 return 0;
328}
329
330static const struct phy_ops stm32_usbphyc_phy_ops = {
331 .init = stm32_usbphyc_phy_init,
332 .exit = stm32_usbphyc_phy_exit,
333 .power_on = stm32_usbphyc_phy_power_on,
334 .power_off = stm32_usbphyc_phy_power_off,
335 .of_xlate = stm32_usbphyc_of_xlate,
336};
337
338static int stm32_usbphyc_probe(struct udevice *dev)
339{
340 struct stm32_usbphyc *usbphyc = dev_get_priv(dev);
341 struct reset_ctl reset;
Patrick Delaunay5b4fa852021-09-14 14:31:16 +0200342 ofnode node, connector;
Patrick Delaunay5d816162021-09-14 14:31:17 +0200343 int ret;
Patrice Chotard3b291212018-04-27 11:01:55 +0200344
345 usbphyc->base = dev_read_addr(dev);
346 if (usbphyc->base == FDT_ADDR_T_NONE)
347 return -EINVAL;
348
349 /* Enable clock */
350 ret = clk_get_by_index(dev, 0, &usbphyc->clk);
351 if (ret)
352 return ret;
353
354 ret = clk_enable(&usbphyc->clk);
355 if (ret)
356 return ret;
357
358 /* Reset */
359 ret = reset_get_by_index(dev, 0, &reset);
360 if (!ret) {
361 reset_assert(&reset);
362 udelay(2);
363 reset_deassert(&reset);
364 }
365
Patrick Delaunayc50151d2019-03-29 15:42:11 +0100366 /* get usbphyc regulator */
367 ret = device_get_supply_regulator(dev, "vdda1v1-supply",
368 &usbphyc->vdda1v1);
369 if (ret) {
370 dev_err(dev, "Can't get vdda1v1-supply regulator\n");
371 return ret;
372 }
373
374 ret = device_get_supply_regulator(dev, "vdda1v8-supply",
375 &usbphyc->vdda1v8);
376 if (ret) {
377 dev_err(dev, "Can't get vdda1v8-supply regulator\n");
378 return ret;
379 }
380
Patrick Delaunay5d816162021-09-14 14:31:17 +0200381 /* parse all PHY subnodes to populate regulator associated to each PHY port */
382 dev_for_each_subnode(node, dev) {
383 fdt_addr_t phy_id;
384 struct stm32_usbphyc_phy *usbphyc_phy;
Patrice Chotard3b291212018-04-27 11:01:55 +0200385
Patrick Delaunay5d816162021-09-14 14:31:17 +0200386 phy_id = ofnode_read_u32_default(node, "reg", FDT_ADDR_T_NONE);
387 if (phy_id >= MAX_PHYS) {
388 dev_err(dev, "invalid reg value %lx for %s\n",
389 phy_id, ofnode_get_name(node));
390 return -ENOENT;
391 }
392 usbphyc_phy = usbphyc->phys + phy_id;
Patrice Chotard3b291212018-04-27 11:01:55 +0200393 usbphyc_phy->init = false;
394 usbphyc_phy->powered = false;
Patrick Delaunayc4801382020-10-15 14:50:57 +0200395 ret = stm32_usbphyc_get_regulator(node, "phy-supply",
Patrice Chotard3b291212018-04-27 11:01:55 +0200396 &usbphyc_phy->vdd);
Patrick Delaunayc4801382020-10-15 14:50:57 +0200397 if (ret) {
398 dev_err(dev, "Can't get phy-supply regulator\n");
Patrice Chotard3b291212018-04-27 11:01:55 +0200399 return ret;
Patrick Delaunayc4801382020-10-15 14:50:57 +0200400 }
401
Patrick Delaunay5b4fa852021-09-14 14:31:16 +0200402 usbphyc_phy->vbus = NULL;
403 connector = ofnode_find_subnode(node, "connector");
404 if (ofnode_valid(connector)) {
405 ret = stm32_usbphyc_get_regulator(connector, "vbus-supply",
406 &usbphyc_phy->vbus);
407 }
Patrice Chotard3b291212018-04-27 11:01:55 +0200408 }
409
410 /* Check if second port has to be used for host controller */
411 if (dev_read_bool(dev, "st,port2-switch-to-host"))
412 setbits_le32(usbphyc->base + STM32_USBPHYC_MISC, SWITHOST);
413
414 return 0;
415}
416
417static const struct udevice_id stm32_usbphyc_of_match[] = {
418 { .compatible = "st,stm32mp1-usbphyc", },
419 { },
420};
421
422U_BOOT_DRIVER(stm32_usb_phyc) = {
423 .name = "stm32-usbphyc",
424 .id = UCLASS_PHY,
425 .of_match = stm32_usbphyc_of_match,
426 .ops = &stm32_usbphyc_phy_ops,
427 .probe = stm32_usbphyc_probe,
Simon Glass41575d82020-12-03 16:55:17 -0700428 .priv_auto = sizeof(struct stm32_usbphyc),
Patrice Chotard3b291212018-04-27 11:01:55 +0200429};