blob: 32145afac1c13cd97b4e7b4f930c5137537ce76b [file] [log] [blame]
Jagan Teki70e882f2020-05-26 11:33:44 +08001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Rockchip USB2.0 PHY with Innosilicon IP block driver
4 *
5 * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd
6 * Copyright (C) 2020 Amarula Solutions(India)
7 */
8
9#include <common.h>
Xavier Drudis Ferranc3dd0612023-06-05 17:05:53 +020010#include <clk-uclass.h>
Jagan Teki70e882f2020-05-26 11:33:44 +080011#include <dm.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060012#include <asm/global_data.h>
Jagan Teki70e882f2020-05-26 11:33:44 +080013#include <dm/device_compat.h>
Xavier Drudis Ferranc3dd0612023-06-05 17:05:53 +020014#include <dm/device-internal.h>
Jagan Teki70e882f2020-05-26 11:33:44 +080015#include <dm/lists.h>
16#include <generic-phy.h>
17#include <reset.h>
18#include <syscon.h>
19#include <asm/gpio.h>
20#include <asm/io.h>
21#include <linux/iopoll.h>
22#include <asm/arch-rockchip/clock.h>
23
24DECLARE_GLOBAL_DATA_PTR;
25
26#define usleep_range(a, b) udelay((b))
27#define BIT_WRITEABLE_SHIFT 16
28
29enum rockchip_usb2phy_port_id {
30 USB2PHY_PORT_OTG,
31 USB2PHY_PORT_HOST,
32 USB2PHY_NUM_PORTS,
33};
34
35struct usb2phy_reg {
36 unsigned int offset;
37 unsigned int bitend;
38 unsigned int bitstart;
39 unsigned int disable;
40 unsigned int enable;
41};
42
43struct rockchip_usb2phy_port_cfg {
44 struct usb2phy_reg phy_sus;
45 struct usb2phy_reg bvalid_det_en;
46 struct usb2phy_reg bvalid_det_st;
47 struct usb2phy_reg bvalid_det_clr;
48 struct usb2phy_reg ls_det_en;
49 struct usb2phy_reg ls_det_st;
50 struct usb2phy_reg ls_det_clr;
51 struct usb2phy_reg utmi_avalid;
52 struct usb2phy_reg utmi_bvalid;
53 struct usb2phy_reg utmi_ls;
54 struct usb2phy_reg utmi_hstdet;
55};
56
57struct rockchip_usb2phy_cfg {
58 unsigned int reg;
59 const struct rockchip_usb2phy_port_cfg port_cfgs[USB2PHY_NUM_PORTS];
60};
61
62struct rockchip_usb2phy {
63 void *reg_base;
64 struct clk phyclk;
65 const struct rockchip_usb2phy_cfg *phy_cfg;
66};
67
68static inline int property_enable(void *reg_base,
69 const struct usb2phy_reg *reg, bool en)
70{
71 unsigned int val, mask, tmp;
72
73 tmp = en ? reg->enable : reg->disable;
74 mask = GENMASK(reg->bitend, reg->bitstart);
75 val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT);
76
77 return writel(val, reg_base + reg->offset);
78}
79
80static const
81struct rockchip_usb2phy_port_cfg *us2phy_get_port(struct phy *phy)
82{
83 struct udevice *parent = dev_get_parent(phy->dev);
84 struct rockchip_usb2phy *priv = dev_get_priv(parent);
85 const struct rockchip_usb2phy_cfg *phy_cfg = priv->phy_cfg;
86
87 return &phy_cfg->port_cfgs[phy->id];
88}
89
90static int rockchip_usb2phy_power_on(struct phy *phy)
91{
92 struct udevice *parent = dev_get_parent(phy->dev);
93 struct rockchip_usb2phy *priv = dev_get_priv(parent);
94 const struct rockchip_usb2phy_port_cfg *port_cfg = us2phy_get_port(phy);
95
96 property_enable(priv->reg_base, &port_cfg->phy_sus, false);
97
98 /* waiting for the utmi_clk to become stable */
99 usleep_range(1500, 2000);
100
101 return 0;
102}
103
104static int rockchip_usb2phy_power_off(struct phy *phy)
105{
106 struct udevice *parent = dev_get_parent(phy->dev);
107 struct rockchip_usb2phy *priv = dev_get_priv(parent);
108 const struct rockchip_usb2phy_port_cfg *port_cfg = us2phy_get_port(phy);
109
110 property_enable(priv->reg_base, &port_cfg->phy_sus, true);
111
112 return 0;
113}
114
115static int rockchip_usb2phy_init(struct phy *phy)
116{
117 struct udevice *parent = dev_get_parent(phy->dev);
118 struct rockchip_usb2phy *priv = dev_get_priv(parent);
119 const struct rockchip_usb2phy_port_cfg *port_cfg = us2phy_get_port(phy);
120 int ret;
121
122 ret = clk_enable(&priv->phyclk);
John Keeping86cd8342022-12-06 12:48:55 +0000123 if (ret && ret != -ENOSYS) {
Jagan Teki70e882f2020-05-26 11:33:44 +0800124 dev_err(phy->dev, "failed to enable phyclk (ret=%d)\n", ret);
125 return ret;
126 }
127
128 if (phy->id == USB2PHY_PORT_OTG) {
129 property_enable(priv->reg_base, &port_cfg->bvalid_det_clr, true);
130 property_enable(priv->reg_base, &port_cfg->bvalid_det_en, true);
131 } else if (phy->id == USB2PHY_PORT_HOST) {
132 property_enable(priv->reg_base, &port_cfg->bvalid_det_clr, true);
133 property_enable(priv->reg_base, &port_cfg->bvalid_det_en, true);
134 }
135
136 return 0;
137}
138
139static int rockchip_usb2phy_exit(struct phy *phy)
140{
141 struct udevice *parent = dev_get_parent(phy->dev);
142 struct rockchip_usb2phy *priv = dev_get_priv(parent);
143
144 clk_disable(&priv->phyclk);
145
146 return 0;
147}
148
149static int rockchip_usb2phy_of_xlate(struct phy *phy,
150 struct ofnode_phandle_args *args)
151{
152 const char *name = phy->dev->name;
153
154 if (!strcasecmp(name, "host-port"))
155 phy->id = USB2PHY_PORT_HOST;
156 else if (!strcasecmp(name, "otg-port"))
157 phy->id = USB2PHY_PORT_OTG;
158 else
159 dev_err(phy->dev, "improper %s device\n", name);
160
161 return 0;
162}
163
164static struct phy_ops rockchip_usb2phy_ops = {
165 .init = rockchip_usb2phy_init,
166 .exit = rockchip_usb2phy_exit,
167 .power_on = rockchip_usb2phy_power_on,
168 .power_off = rockchip_usb2phy_power_off,
169 .of_xlate = rockchip_usb2phy_of_xlate,
170};
171
Xavier Drudis Ferranc3dd0612023-06-05 17:05:53 +0200172static struct clk_ops rockchip_usb2phy_clk_ops = {
173};
174
Jagan Teki70e882f2020-05-26 11:33:44 +0800175static int rockchip_usb2phy_probe(struct udevice *dev)
176{
177 struct rockchip_usb2phy *priv = dev_get_priv(dev);
178 const struct rockchip_usb2phy_cfg *phy_cfgs;
179 unsigned int reg;
180 int index, ret;
181
182 priv->reg_base = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
183 if (IS_ERR(priv->reg_base))
184 return PTR_ERR(priv->reg_base);
185
Jagan Teki1b799512023-02-17 17:28:39 +0530186 ret = ofnode_read_u32_index(dev_ofnode(dev), "reg", 0, &reg);
Jagan Teki70e882f2020-05-26 11:33:44 +0800187 if (ret) {
188 dev_err(dev, "failed to read reg property (ret = %d)\n", ret);
189 return ret;
190 }
191
Jagan Teki1b799512023-02-17 17:28:39 +0530192 /* support address_cells=2 */
193 if (reg == 0) {
194 if (ofnode_read_u32_index(dev_ofnode(dev), "reg", 1, &reg)) {
195 dev_err(dev, "%s must have reg[1]\n",
196 ofnode_get_name(dev_ofnode(dev)));
197 return -EINVAL;
198 }
199 }
200
Jagan Teki70e882f2020-05-26 11:33:44 +0800201 phy_cfgs = (const struct rockchip_usb2phy_cfg *)
202 dev_get_driver_data(dev);
203 if (!phy_cfgs)
204 return -EINVAL;
205
206 /* find out a proper config which can be matched with dt. */
207 index = 0;
Eugen Hristev33642262023-05-15 12:59:49 +0300208 do {
Jagan Teki70e882f2020-05-26 11:33:44 +0800209 if (phy_cfgs[index].reg == reg) {
210 priv->phy_cfg = &phy_cfgs[index];
211 break;
212 }
213
214 ++index;
Eugen Hristev33642262023-05-15 12:59:49 +0300215 } while (phy_cfgs[index].reg);
Jagan Teki70e882f2020-05-26 11:33:44 +0800216
217 if (!priv->phy_cfg) {
218 dev_err(dev, "failed find proper phy-cfg\n");
219 return -EINVAL;
220 }
221
222 ret = clk_get_by_name(dev, "phyclk", &priv->phyclk);
223 if (ret) {
224 dev_err(dev, "failed to get the phyclk (ret=%d)\n", ret);
225 return ret;
226 }
227
228 return 0;
229}
230
231static int rockchip_usb2phy_bind(struct udevice *dev)
232{
233 struct udevice *usb2phy_dev;
234 ofnode node;
235 const char *name;
236 int ret = 0;
237
238 dev_for_each_subnode(node, dev) {
239 if (!ofnode_valid(node)) {
240 dev_info(dev, "subnode %s not found\n", dev->name);
Xavier Drudis Ferranc3dd0612023-06-05 17:05:53 +0200241 ret = -ENXIO;
242 goto bind_fail;
Jagan Teki70e882f2020-05-26 11:33:44 +0800243 }
244
245 name = ofnode_get_name(node);
246 dev_dbg(dev, "subnode %s\n", name);
247
248 ret = device_bind_driver_to_node(dev, "rockchip_usb2phy_port",
249 name, node, &usb2phy_dev);
250 if (ret) {
251 dev_err(dev,
252 "'%s' cannot bind 'rockchip_usb2phy_port'\n", name);
Xavier Drudis Ferranc3dd0612023-06-05 17:05:53 +0200253 goto bind_fail;
Jagan Teki70e882f2020-05-26 11:33:44 +0800254 }
255 }
256
Xavier Drudis Ferranc3dd0612023-06-05 17:05:53 +0200257 node = dev_ofnode(dev);
258 name = ofnode_get_name(node);
259 dev_dbg(dev, "clk for node %s\n", name);
260 ret = device_bind_driver_to_node(dev, "rockchip_usb2phy_clock",
261 name, node, &usb2phy_dev);
262 if (ret) {
263 dev_err(dev,
264 "'%s' cannot bind 'rockchip_usb2phy_clock'\n", name);
265 goto bind_fail;
266 }
267
268 return 0;
269
270bind_fail:
271 device_chld_unbind(dev, NULL);
272
Jagan Teki70e882f2020-05-26 11:33:44 +0800273 return ret;
274}
275
276static const struct rockchip_usb2phy_cfg rk3399_usb2phy_cfgs[] = {
277 {
278 .reg = 0xe450,
279 .port_cfgs = {
280 [USB2PHY_PORT_OTG] = {
281 .phy_sus = { 0xe454, 1, 0, 2, 1 },
282 .bvalid_det_en = { 0xe3c0, 3, 3, 0, 1 },
283 .bvalid_det_st = { 0xe3e0, 3, 3, 0, 1 },
284 .bvalid_det_clr = { 0xe3d0, 3, 3, 0, 1 },
285 .utmi_avalid = { 0xe2ac, 7, 7, 0, 1 },
286 .utmi_bvalid = { 0xe2ac, 12, 12, 0, 1 },
287 },
288 [USB2PHY_PORT_HOST] = {
289 .phy_sus = { 0xe458, 1, 0, 0x2, 0x1 },
290 .ls_det_en = { 0xe3c0, 6, 6, 0, 1 },
291 .ls_det_st = { 0xe3e0, 6, 6, 0, 1 },
292 .ls_det_clr = { 0xe3d0, 6, 6, 0, 1 },
293 .utmi_ls = { 0xe2ac, 22, 21, 0, 1 },
294 .utmi_hstdet = { 0xe2ac, 23, 23, 0, 1 }
295 }
296 },
297 },
298 {
299 .reg = 0xe460,
300 .port_cfgs = {
301 [USB2PHY_PORT_OTG] = {
302 .phy_sus = { 0xe464, 1, 0, 2, 1 },
303 .bvalid_det_en = { 0xe3c0, 8, 8, 0, 1 },
304 .bvalid_det_st = { 0xe3e0, 8, 8, 0, 1 },
305 .bvalid_det_clr = { 0xe3d0, 8, 8, 0, 1 },
306 .utmi_avalid = { 0xe2ac, 10, 10, 0, 1 },
307 .utmi_bvalid = { 0xe2ac, 16, 16, 0, 1 },
308 },
309 [USB2PHY_PORT_HOST] = {
310 .phy_sus = { 0xe468, 1, 0, 0x2, 0x1 },
311 .ls_det_en = { 0xe3c0, 11, 11, 0, 1 },
312 .ls_det_st = { 0xe3e0, 11, 11, 0, 1 },
313 .ls_det_clr = { 0xe3d0, 11, 11, 0, 1 },
314 .utmi_ls = { 0xe2ac, 26, 25, 0, 1 },
315 .utmi_hstdet = { 0xe2ac, 27, 27, 0, 1 }
316 }
317 },
318 },
319 { /* sentinel */ }
320};
321
Manoj Sai3a111672023-02-17 17:28:40 +0530322static const struct rockchip_usb2phy_cfg rk3568_phy_cfgs[] = {
323 {
324 .reg = 0xfe8a0000,
325 .port_cfgs = {
326 [USB2PHY_PORT_OTG] = {
327 .phy_sus = { 0x0000, 8, 0, 0x052, 0x1d1 },
328 .bvalid_det_en = { 0x0080, 2, 2, 0, 1 },
329 .bvalid_det_st = { 0x0084, 2, 2, 0, 1 },
330 .bvalid_det_clr = { 0x0088, 2, 2, 0, 1 },
331 .ls_det_en = { 0x0080, 0, 0, 0, 1 },
332 .ls_det_st = { 0x0084, 0, 0, 0, 1 },
333 .ls_det_clr = { 0x0088, 0, 0, 0, 1 },
334 .utmi_avalid = { 0x00c0, 10, 10, 0, 1 },
335 .utmi_bvalid = { 0x00c0, 9, 9, 0, 1 },
336 .utmi_ls = { 0x00c0, 5, 4, 0, 1 },
337 },
338 [USB2PHY_PORT_HOST] = {
339 .phy_sus = { 0x0004, 8, 0, 0x1d2, 0x1d1 },
340 .ls_det_en = { 0x0080, 1, 1, 0, 1 },
341 .ls_det_st = { 0x0084, 1, 1, 0, 1 },
342 .ls_det_clr = { 0x0088, 1, 1, 0, 1 },
343 .utmi_ls = { 0x00c0, 17, 16, 0, 1 },
344 .utmi_hstdet = { 0x00c0, 19, 19, 0, 1 }
345 }
346 },
347 },
348 {
349 .reg = 0xfe8b0000,
350 .port_cfgs = {
351 [USB2PHY_PORT_OTG] = {
352 .phy_sus = { 0x0000, 8, 0, 0x1d2, 0x1d1 },
353 .ls_det_en = { 0x0080, 0, 0, 0, 1 },
354 .ls_det_st = { 0x0084, 0, 0, 0, 1 },
355 .ls_det_clr = { 0x0088, 0, 0, 0, 1 },
356 .utmi_ls = { 0x00c0, 5, 4, 0, 1 },
357 .utmi_hstdet = { 0x00c0, 7, 7, 0, 1 }
358 },
359 [USB2PHY_PORT_HOST] = {
360 .phy_sus = { 0x0004, 8, 0, 0x1d2, 0x1d1 },
361 .ls_det_en = { 0x0080, 1, 1, 0, 1 },
362 .ls_det_st = { 0x0084, 1, 1, 0, 1 },
363 .ls_det_clr = { 0x0088, 1, 1, 0, 1 },
364 .utmi_ls = { 0x00c0, 17, 16, 0, 1 },
365 .utmi_hstdet = { 0x00c0, 19, 19, 0, 1 }
366 }
367 },
368 },
Eugen Hristev33642262023-05-15 12:59:49 +0300369 { /* sentinel */ }
370};
371
372static const struct rockchip_usb2phy_cfg rk3588_phy_cfgs[] = {
373 {
374 .reg = 0x0000,
375 .port_cfgs = {
376 [USB2PHY_PORT_OTG] = {
377 .phy_sus = { 0x000c, 11, 11, 0, 1 },
378 .ls_det_en = { 0x0080, 0, 0, 0, 1 },
379 .ls_det_st = { 0x0084, 0, 0, 0, 1 },
380 .ls_det_clr = { 0x0088, 0, 0, 0, 1 },
381 .utmi_ls = { 0x00c0, 10, 9, 0, 1 },
382 }
383 },
384 },
385 {
386 .reg = 0x4000,
387 .port_cfgs = {
388 [USB2PHY_PORT_OTG] = {
389 .phy_sus = { 0x000c, 11, 11, 0, 0 },
390 .ls_det_en = { 0x0080, 0, 0, 0, 1 },
391 .ls_det_st = { 0x0084, 0, 0, 0, 1 },
392 .ls_det_clr = { 0x0088, 0, 0, 0, 1 },
393 .utmi_ls = { 0x00c0, 10, 9, 0, 1 },
394 }
395 },
396 },
397 {
398 .reg = 0x8000,
399 .port_cfgs = {
400 [USB2PHY_PORT_HOST] = {
401 .phy_sus = { 0x0008, 2, 2, 0, 1 },
402 .ls_det_en = { 0x0080, 0, 0, 0, 1 },
403 .ls_det_st = { 0x0084, 0, 0, 0, 1 },
404 .ls_det_clr = { 0x0088, 0, 0, 0, 1 },
405 .utmi_ls = { 0x00c0, 10, 9, 0, 1 },
406 }
407 },
408 },
409 {
410 .reg = 0xc000,
411 .port_cfgs = {
412 [USB2PHY_PORT_HOST] = {
413 .phy_sus = { 0x0008, 2, 2, 0, 1 },
414 .ls_det_en = { 0x0080, 0, 0, 0, 1 },
415 .ls_det_st = { 0x0084, 0, 0, 0, 1 },
416 .ls_det_clr = { 0x0088, 0, 0, 0, 1 },
417 .utmi_ls = { 0x00c0, 10, 9, 0, 1 },
418 }
419 },
420 },
Manoj Sai3a111672023-02-17 17:28:40 +0530421 { /* sentinel */ }
422};
423
Jagan Teki70e882f2020-05-26 11:33:44 +0800424static const struct udevice_id rockchip_usb2phy_ids[] = {
425 {
426 .compatible = "rockchip,rk3399-usb2phy",
427 .data = (ulong)&rk3399_usb2phy_cfgs,
428 },
Manoj Sai3a111672023-02-17 17:28:40 +0530429 {
430 .compatible = "rockchip,rk3568-usb2phy",
431 .data = (ulong)&rk3568_phy_cfgs,
432 },
Eugen Hristev33642262023-05-15 12:59:49 +0300433 {
434 .compatible = "rockchip,rk3588-usb2phy",
435 .data = (ulong)&rk3588_phy_cfgs,
436 },
Jagan Teki70e882f2020-05-26 11:33:44 +0800437 { /* sentinel */ }
438};
439
440U_BOOT_DRIVER(rockchip_usb2phy_port) = {
441 .name = "rockchip_usb2phy_port",
442 .id = UCLASS_PHY,
443 .ops = &rockchip_usb2phy_ops,
444};
445
Xavier Drudis Ferranc3dd0612023-06-05 17:05:53 +0200446U_BOOT_DRIVER(rockchip_usb2phy_clock) = {
447 .name = "rockchip_usb2phy_clock",
448 .id = UCLASS_CLK,
449 .ops = &rockchip_usb2phy_clk_ops,
450};
451
Jagan Teki70e882f2020-05-26 11:33:44 +0800452U_BOOT_DRIVER(rockchip_usb2phy) = {
453 .name = "rockchip_usb2phy",
454 .id = UCLASS_PHY,
455 .of_match = rockchip_usb2phy_ids,
456 .probe = rockchip_usb2phy_probe,
457 .bind = rockchip_usb2phy_bind,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700458 .priv_auto = sizeof(struct rockchip_usb2phy),
Jagan Teki70e882f2020-05-26 11:33:44 +0800459};