1 // 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 <clk-uclass.h>
10 #include <dm.h>
11 #include <dm/device_compat.h>
12 #include <dm/device-internal.h>
13 #include <dm/lists.h>
14 #include <generic-phy.h>
15 #include <regmap.h>
16 #include <syscon.h>
17 #include <asm/arch-rockchip/clock.h>
18 
19 #define usleep_range(a, b) udelay((b))
20 #define BIT_WRITEABLE_SHIFT	16
21 
22 enum rockchip_usb2phy_port_id {
23 	USB2PHY_PORT_OTG,
24 	USB2PHY_PORT_HOST,
25 	USB2PHY_NUM_PORTS,
26 };
27 
28 struct usb2phy_reg {
29 	unsigned int	offset;
30 	unsigned int	bitend;
31 	unsigned int	bitstart;
32 	unsigned int	disable;
33 	unsigned int	enable;
34 };
35 
36 struct rockchip_usb2phy_port_cfg {
37 	struct usb2phy_reg	phy_sus;
38 };
39 
40 struct rockchip_usb2phy_cfg {
41 	unsigned int reg;
42 	struct usb2phy_reg	clkout_ctl;
43 	struct usb2phy_reg	clkout_ctl_phy;
44 	const struct rockchip_usb2phy_port_cfg port_cfgs[USB2PHY_NUM_PORTS];
45 };
46 
47 struct rockchip_usb2phy {
48 	struct regmap *reg_base;
49 	struct regmap *phy_base;
50 	struct clk phyclk;
51 	const struct rockchip_usb2phy_cfg *phy_cfg;
52 };
53 
property_enable(struct regmap * base,const struct usb2phy_reg * reg,bool en)54 static inline int property_enable(struct regmap *base,
55 				  const struct usb2phy_reg *reg, bool en)
56 {
57 	unsigned int val, mask, tmp;
58 
59 	if (!reg->offset && !reg->enable && !reg->disable)
60 		return 0;
61 
62 	tmp = en ? reg->enable : reg->disable;
63 	mask = GENMASK(reg->bitend, reg->bitstart);
64 	val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT);
65 
66 	return regmap_write(base, reg->offset, val);
67 }
68 
property_enabled(struct regmap * base,const struct usb2phy_reg * reg)69 static inline bool property_enabled(struct regmap *base,
70 				    const struct usb2phy_reg *reg)
71 {
72 	int ret;
73 	unsigned int tmp, orig;
74 	unsigned int mask = GENMASK(reg->bitend, reg->bitstart);
75 
76 	if (!reg->offset && !reg->enable && !reg->disable)
77 		return false;
78 
79 	ret = regmap_read(base, reg->offset, &orig);
80 	if (ret)
81 		return false;
82 
83 	tmp = (orig & mask) >> reg->bitstart;
84 	return tmp != reg->disable;
85 }
86 
87 static const
us2phy_get_port(struct phy * phy)88 struct rockchip_usb2phy_port_cfg *us2phy_get_port(struct phy *phy)
89 {
90 	struct udevice *parent = dev_get_parent(phy->dev);
91 	struct rockchip_usb2phy *priv = dev_get_priv(parent);
92 	const struct rockchip_usb2phy_cfg *phy_cfg = priv->phy_cfg;
93 
94 	return &phy_cfg->port_cfgs[phy->id];
95 }
96 
rockchip_usb2phy_power_on(struct phy * phy)97 static int rockchip_usb2phy_power_on(struct phy *phy)
98 {
99 	struct udevice *parent = dev_get_parent(phy->dev);
100 	struct rockchip_usb2phy *priv = dev_get_priv(parent);
101 	const struct rockchip_usb2phy_port_cfg *port_cfg = us2phy_get_port(phy);
102 
103 	property_enable(priv->reg_base, &port_cfg->phy_sus, false);
104 
105 	/* waiting for the utmi_clk to become stable */
106 	usleep_range(1500, 2000);
107 
108 	return 0;
109 }
110 
rockchip_usb2phy_power_off(struct phy * phy)111 static int rockchip_usb2phy_power_off(struct phy *phy)
112 {
113 	struct udevice *parent = dev_get_parent(phy->dev);
114 	struct rockchip_usb2phy *priv = dev_get_priv(parent);
115 	const struct rockchip_usb2phy_port_cfg *port_cfg = us2phy_get_port(phy);
116 
117 	property_enable(priv->reg_base, &port_cfg->phy_sus, true);
118 
119 	return 0;
120 }
121 
rockchip_usb2phy_init(struct phy * phy)122 static int rockchip_usb2phy_init(struct phy *phy)
123 {
124 	struct udevice *parent = dev_get_parent(phy->dev);
125 	struct rockchip_usb2phy *priv = dev_get_priv(parent);
126 	int ret;
127 
128 	ret = clk_enable(&priv->phyclk);
129 	if (ret && ret != -ENOSYS) {
130 		dev_err(phy->dev, "failed to enable phyclk (ret=%d)\n", ret);
131 		return ret;
132 	}
133 
134 	return 0;
135 }
136 
rockchip_usb2phy_exit(struct phy * phy)137 static int rockchip_usb2phy_exit(struct phy *phy)
138 {
139 	struct udevice *parent = dev_get_parent(phy->dev);
140 	struct rockchip_usb2phy *priv = dev_get_priv(parent);
141 
142 	clk_disable(&priv->phyclk);
143 
144 	return 0;
145 }
146 
rockchip_usb2phy_of_xlate(struct phy * phy,struct ofnode_phandle_args * args)147 static int rockchip_usb2phy_of_xlate(struct phy *phy,
148 				     struct ofnode_phandle_args *args)
149 {
150 	const char *name = phy->dev->name;
151 
152 	if (!strcasecmp(name, "host-port"))
153 		phy->id = USB2PHY_PORT_HOST;
154 	else if (!strcasecmp(name, "otg-port"))
155 		phy->id = USB2PHY_PORT_OTG;
156 	else
157 		dev_err(phy->dev, "improper %s device\n", name);
158 
159 	return 0;
160 }
161 
162 static struct phy_ops rockchip_usb2phy_ops = {
163 	.init = rockchip_usb2phy_init,
164 	.exit = rockchip_usb2phy_exit,
165 	.power_on = rockchip_usb2phy_power_on,
166 	.power_off = rockchip_usb2phy_power_off,
167 	.of_xlate = rockchip_usb2phy_of_xlate,
168 };
169 
rockchip_usb2phy_clkout_ctl(struct clk * clk,struct regmap ** base,const struct usb2phy_reg ** clkout_ctl)170 static void rockchip_usb2phy_clkout_ctl(struct clk *clk, struct regmap **base,
171 					const struct usb2phy_reg **clkout_ctl)
172 {
173 	struct udevice *parent = dev_get_parent(clk->dev);
174 	struct rockchip_usb2phy *priv = dev_get_priv(parent);
175 	const struct rockchip_usb2phy_cfg *phy_cfg = priv->phy_cfg;
176 
177 	if (priv->phy_cfg->clkout_ctl_phy.enable) {
178 		*base = priv->phy_base;
179 		*clkout_ctl = &phy_cfg->clkout_ctl_phy;
180 	} else {
181 		*base = priv->reg_base;
182 		*clkout_ctl = &phy_cfg->clkout_ctl;
183 	}
184 }
185 
186 /**
187  * round_rate() - Adjust a rate to the exact rate a clock can provide.
188  * @clk:	The clock to manipulate.
189  * @rate:	Desidered clock rate in Hz.
190  *
191  * Return: rounded rate in Hz, or -ve error code.
192  */
rockchip_usb2phy_clk_round_rate(struct clk * clk,ulong rate)193 ulong rockchip_usb2phy_clk_round_rate(struct clk *clk, ulong rate)
194 {
195 	return 480000000;
196 }
197 
198 /**
199  * enable() - Enable a clock.
200  * @clk:	The clock to manipulate.
201  *
202  * Return: zero on success, or -ve error code.
203  */
rockchip_usb2phy_clk_enable(struct clk * clk)204 int rockchip_usb2phy_clk_enable(struct clk *clk)
205 {
206 	const struct usb2phy_reg *clkout_ctl;
207 	struct regmap *base;
208 
209 	rockchip_usb2phy_clkout_ctl(clk, &base, &clkout_ctl);
210 
211 	/* turn on 480m clk output if it is off */
212 	if (!property_enabled(base, clkout_ctl)) {
213 		property_enable(base, clkout_ctl, true);
214 
215 		/* waiting for the clk become stable */
216 		usleep_range(1200, 1300);
217 	}
218 
219 	return 0;
220 }
221 
222 /**
223  * disable() - Disable a clock.
224  * @clk:	The clock to manipulate.
225  *
226  * Return: zero on success, or -ve error code.
227  */
rockchip_usb2phy_clk_disable(struct clk * clk)228 int rockchip_usb2phy_clk_disable(struct clk *clk)
229 {
230 	const struct usb2phy_reg *clkout_ctl;
231 	struct regmap *base;
232 
233 	rockchip_usb2phy_clkout_ctl(clk, &base, &clkout_ctl);
234 
235 	/* turn off 480m clk output */
236 	property_enable(base, clkout_ctl, false);
237 
238 	return 0;
239 }
240 
241 static struct clk_ops rockchip_usb2phy_clk_ops = {
242 	.enable = rockchip_usb2phy_clk_enable,
243 	.disable = rockchip_usb2phy_clk_disable,
244 	.round_rate = rockchip_usb2phy_clk_round_rate
245 };
246 
rockchip_usb2phy_probe(struct udevice * dev)247 static int rockchip_usb2phy_probe(struct udevice *dev)
248 {
249 	struct rockchip_usb2phy *priv = dev_get_priv(dev);
250 	const struct rockchip_usb2phy_cfg *phy_cfgs;
251 	unsigned int reg;
252 	int index, ret;
253 
254 	if (dev_read_bool(dev, "rockchip,usbgrf"))
255 		priv->reg_base =
256 			syscon_regmap_lookup_by_phandle(dev, "rockchip,usbgrf");
257 	else
258 		priv->reg_base = syscon_get_regmap(dev_get_parent(dev));
259 	if (IS_ERR(priv->reg_base))
260 		return PTR_ERR(priv->reg_base);
261 
262 	ret = ofnode_read_u32_index(dev_ofnode(dev), "reg", 0, &reg);
263 	if (ret) {
264 		dev_err(dev, "failed to read reg property (ret = %d)\n", ret);
265 		return ret;
266 	}
267 
268 	/* support address_cells=2 */
269 	if (dev_read_addr_cells(dev) == 2 && reg == 0) {
270 		if (ofnode_read_u32_index(dev_ofnode(dev), "reg", 1, &reg)) {
271 			dev_err(dev, "%s must have reg[1]\n",
272 				ofnode_get_name(dev_ofnode(dev)));
273 			return -EINVAL;
274 		}
275 	}
276 
277 	phy_cfgs = (const struct rockchip_usb2phy_cfg *)
278 					dev_get_driver_data(dev);
279 	if (!phy_cfgs)
280 		return -EINVAL;
281 
282 	/* find out a proper config which can be matched with dt. */
283 	index = 0;
284 	do {
285 		if (phy_cfgs[index].reg == reg) {
286 			priv->phy_cfg = &phy_cfgs[index];
287 			break;
288 		}
289 
290 		++index;
291 	} while (phy_cfgs[index].reg);
292 
293 	if (!priv->phy_cfg) {
294 		dev_err(dev, "failed find proper phy-cfg\n");
295 		return -EINVAL;
296 	}
297 
298 	ret = clk_get_by_name(dev, "phyclk", &priv->phyclk);
299 	if (ret) {
300 		dev_err(dev, "failed to get the phyclk (ret=%d)\n", ret);
301 		return ret;
302 	}
303 
304 	if (priv->phy_cfg->clkout_ctl_phy.enable)
305 		ret = regmap_init_mem_index(dev_ofnode(dev), &priv->phy_base, 0);
306 
307 	return ret;
308 }
309 
rockchip_usb2phy_bind(struct udevice * dev)310 static int rockchip_usb2phy_bind(struct udevice *dev)
311 {
312 	struct udevice *usb2phy_dev;
313 	ofnode node;
314 	const char *name;
315 	int ret = 0;
316 
317 	dev_for_each_subnode(node, dev) {
318 		if (!ofnode_is_enabled(node))
319 			continue;
320 
321 		name = ofnode_get_name(node);
322 		dev_dbg(dev, "subnode %s\n", name);
323 
324 		ret = device_bind_driver_to_node(dev, "rockchip_usb2phy_port",
325 						 name, node, &usb2phy_dev);
326 		if (ret) {
327 			dev_err(dev,
328 				"'%s' cannot bind 'rockchip_usb2phy_port'\n", name);
329 			goto bind_fail;
330 		}
331 	}
332 
333 	node = dev_ofnode(dev);
334 	name = "clk_usbphy_480m";
335 	dev_read_string_index(dev, "clock-output-names", 0, &name);
336 
337 	dev_dbg(dev, "clk %s for node %s\n", name, ofnode_get_name(node));
338 
339 	ret = device_bind_driver_to_node(dev, "rockchip_usb2phy_clock",
340 					 name, node, &usb2phy_dev);
341 	if (ret) {
342 		dev_err(dev,
343 			"'%s' cannot bind 'rockchip_usb2phy_clock'\n", name);
344 		goto bind_fail;
345 	}
346 
347 	return 0;
348 
349 bind_fail:
350 	device_chld_unbind(dev, NULL);
351 
352 	return ret;
353 }
354 
355 static const struct rockchip_usb2phy_cfg rk3308_phy_cfgs[] = {
356 	{
357 		.reg = 0x100,
358 		.clkout_ctl	= { 0x0108, 4, 4, 1, 0 },
359 		.port_cfgs	= {
360 			[USB2PHY_PORT_OTG] = {
361 				.phy_sus	= { 0x0100, 1, 0, 2, 1 },
362 			},
363 			[USB2PHY_PORT_HOST] = {
364 				.phy_sus	= { 0x0104, 1, 0, 2, 1 },
365 			}
366 		},
367 	},
368 	{ /* sentinel */ }
369 };
370 
371 static const struct rockchip_usb2phy_cfg rk3328_usb2phy_cfgs[] = {
372 	{
373 		.reg = 0x100,
374 		.clkout_ctl	= { 0x0108, 4, 4, 1, 0 },
375 		.port_cfgs	= {
376 			[USB2PHY_PORT_OTG] = {
377 				.phy_sus	= { 0x0100, 1, 0, 2, 1 },
378 			},
379 			[USB2PHY_PORT_HOST] = {
380 				.phy_sus	= { 0x0104, 1, 0, 2, 1 },
381 			}
382 		},
383 	},
384 	{ /* sentinel */ }
385 };
386 
387 static const struct rockchip_usb2phy_cfg rk3399_usb2phy_cfgs[] = {
388 	{
389 		.reg		= 0xe450,
390 		.clkout_ctl	= { 0xe450, 4, 4, 1, 0 },
391 		.port_cfgs	= {
392 			[USB2PHY_PORT_OTG] = {
393 				.phy_sus	= { 0xe454, 1, 0, 2, 1 },
394 			},
395 			[USB2PHY_PORT_HOST] = {
396 				.phy_sus	= { 0xe458, 1, 0, 2, 1 },
397 			}
398 		},
399 	},
400 	{
401 		.reg		= 0xe460,
402 		.clkout_ctl	= { 0xe460, 4, 4, 1, 0 },
403 		.port_cfgs	= {
404 			[USB2PHY_PORT_OTG] = {
405 				.phy_sus        = { 0xe464, 1, 0, 2, 1 },
406 			},
407 			[USB2PHY_PORT_HOST] = {
408 				.phy_sus	= { 0xe468, 1, 0, 2, 1 },
409 			}
410 		},
411 	},
412 	{ /* sentinel */ }
413 };
414 
415 static const struct rockchip_usb2phy_cfg rk3528_phy_cfgs[] = {
416 	{
417 		.reg		= 0xffdf0000,
418 		.clkout_ctl_phy	= { 0x041c, 7, 2, 0, 0x27 },
419 		.port_cfgs	= {
420 			[USB2PHY_PORT_OTG] = {
421 				.phy_sus	= { 0x004c, 1, 0, 2, 1 },
422 			},
423 			[USB2PHY_PORT_HOST] = {
424 				.phy_sus	= { 0x005c, 1, 0, 2, 1 },
425 			}
426 		},
427 	},
428 	{ /* sentinel */ }
429 };
430 
431 static const struct rockchip_usb2phy_cfg rk3568_phy_cfgs[] = {
432 	{
433 		.reg		= 0xfe8a0000,
434 		.clkout_ctl	= { 0x0008, 4, 4, 1, 0 },
435 		.port_cfgs	= {
436 			[USB2PHY_PORT_OTG] = {
437 				.phy_sus	= { 0x0000, 1, 0, 2, 1 },
438 			},
439 			[USB2PHY_PORT_HOST] = {
440 				.phy_sus	= { 0x0004, 1, 0, 2, 1 },
441 			}
442 		},
443 	},
444 	{
445 		.reg		= 0xfe8b0000,
446 		.clkout_ctl	= { 0x0008, 4, 4, 1, 0 },
447 		.port_cfgs	= {
448 			[USB2PHY_PORT_OTG] = {
449 				.phy_sus	= { 0x0000, 1, 0, 2, 1 },
450 			},
451 			[USB2PHY_PORT_HOST] = {
452 				.phy_sus	= { 0x0004, 1, 0, 2, 1 },
453 			}
454 		},
455 	},
456 	{ /* sentinel */ }
457 };
458 
459 static const struct rockchip_usb2phy_cfg rk3588_phy_cfgs[] = {
460 	{
461 		.reg		= 0x0000,
462 		.clkout_ctl	= { 0x0000, 0, 0, 1, 0 },
463 		.port_cfgs	= {
464 			[USB2PHY_PORT_OTG] = {
465 				.phy_sus	= { 0x000c, 11, 11, 0, 1 },
466 			}
467 		},
468 	},
469 	{
470 		.reg		= 0x4000,
471 		.clkout_ctl	= { 0x0000, 0, 0, 1, 0 },
472 		.port_cfgs	= {
473 			[USB2PHY_PORT_OTG] = {
474 				.phy_sus	= { 0x000c, 11, 11, 0, 1 },
475 			}
476 		},
477 	},
478 	{
479 		.reg		= 0x8000,
480 		.clkout_ctl	= { 0x0000, 0, 0, 1, 0 },
481 		.port_cfgs	= {
482 			[USB2PHY_PORT_HOST] = {
483 				.phy_sus	= { 0x0008, 2, 2, 0, 1 },
484 			}
485 		},
486 	},
487 	{
488 		.reg		= 0xc000,
489 		.clkout_ctl	= { 0x0000, 0, 0, 1, 0 },
490 		.port_cfgs	= {
491 			[USB2PHY_PORT_HOST] = {
492 				.phy_sus	= { 0x0008, 2, 2, 0, 1 },
493 			}
494 		},
495 	},
496 	{ /* sentinel */ }
497 };
498 
499 static const struct udevice_id rockchip_usb2phy_ids[] = {
500 	{
501 		.compatible = "rockchip,rk3308-usb2phy",
502 		.data = (ulong)&rk3308_phy_cfgs,
503 	},
504 	{
505 		.compatible = "rockchip,rk3328-usb2phy",
506 		.data = (ulong)&rk3328_usb2phy_cfgs,
507 	},
508 	{
509 		.compatible = "rockchip,rk3399-usb2phy",
510 		.data = (ulong)&rk3399_usb2phy_cfgs,
511 	},
512 	{
513 		.compatible = "rockchip,rk3528-usb2phy",
514 		.data = (ulong)&rk3528_phy_cfgs,
515 	},
516 	{
517 		.compatible = "rockchip,rk3568-usb2phy",
518 		.data = (ulong)&rk3568_phy_cfgs,
519 	},
520 	{
521 		.compatible = "rockchip,rk3588-usb2phy",
522 		.data = (ulong)&rk3588_phy_cfgs,
523 	},
524 	{ /* sentinel */ }
525 };
526 
527 U_BOOT_DRIVER(rockchip_usb2phy_port) = {
528 	.name		= "rockchip_usb2phy_port",
529 	.id		= UCLASS_PHY,
530 	.ops		= &rockchip_usb2phy_ops,
531 };
532 
533 U_BOOT_DRIVER(rockchip_usb2phy_clock) = {
534 	.name		= "rockchip_usb2phy_clock",
535 	.id		= UCLASS_CLK,
536 	.ops		= &rockchip_usb2phy_clk_ops,
537 };
538 
539 U_BOOT_DRIVER(rockchip_usb2phy) = {
540 	.name	= "rockchip_usb2phy",
541 	.id	= UCLASS_PHY,
542 	.of_match = rockchip_usb2phy_ids,
543 	.probe = rockchip_usb2phy_probe,
544 	.bind = rockchip_usb2phy_bind,
545 	.priv_auto	= sizeof(struct rockchip_usb2phy),
546 };
547