1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Rockchip USB2.0 PHY with Innosilicon IP block driver
5 * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd
6 * Copyright (C) 2020 Amarula Solutions(India)
9 #include <clk-uclass.h>
11 #include <dm/device_compat.h>
12 #include <dm/device-internal.h>
14 #include <generic-phy.h>
17 #include <asm/arch-rockchip/clock.h>
19 #define usleep_range(a, b) udelay((b))
20 #define BIT_WRITEABLE_SHIFT 16
22 enum rockchip_usb2phy_port_id
{
31 unsigned int bitstart
;
36 struct rockchip_usb2phy_port_cfg
{
37 struct usb2phy_reg phy_sus
;
40 struct rockchip_usb2phy_cfg
{
42 struct usb2phy_reg clkout_ctl
;
43 const struct rockchip_usb2phy_port_cfg port_cfgs
[USB2PHY_NUM_PORTS
];
46 struct rockchip_usb2phy
{
47 struct regmap
*reg_base
;
49 const struct rockchip_usb2phy_cfg
*phy_cfg
;
52 static inline int property_enable(struct regmap
*base
,
53 const struct usb2phy_reg
*reg
, bool en
)
55 unsigned int val
, mask
, tmp
;
57 if (!reg
->offset
&& !reg
->enable
&& !reg
->disable
)
60 tmp
= en
? reg
->enable
: reg
->disable
;
61 mask
= GENMASK(reg
->bitend
, reg
->bitstart
);
62 val
= (tmp
<< reg
->bitstart
) | (mask
<< BIT_WRITEABLE_SHIFT
);
64 return regmap_write(base
, reg
->offset
, val
);
67 static inline bool property_enabled(struct regmap
*base
,
68 const struct usb2phy_reg
*reg
)
71 unsigned int tmp
, orig
;
72 unsigned int mask
= GENMASK(reg
->bitend
, reg
->bitstart
);
74 if (!reg
->offset
&& !reg
->enable
&& !reg
->disable
)
77 ret
= regmap_read(base
, reg
->offset
, &orig
);
81 tmp
= (orig
& mask
) >> reg
->bitstart
;
82 return tmp
!= reg
->disable
;
86 struct rockchip_usb2phy_port_cfg
*us2phy_get_port(struct phy
*phy
)
88 struct udevice
*parent
= dev_get_parent(phy
->dev
);
89 struct rockchip_usb2phy
*priv
= dev_get_priv(parent
);
90 const struct rockchip_usb2phy_cfg
*phy_cfg
= priv
->phy_cfg
;
92 return &phy_cfg
->port_cfgs
[phy
->id
];
95 static int rockchip_usb2phy_power_on(struct phy
*phy
)
97 struct udevice
*parent
= dev_get_parent(phy
->dev
);
98 struct rockchip_usb2phy
*priv
= dev_get_priv(parent
);
99 const struct rockchip_usb2phy_port_cfg
*port_cfg
= us2phy_get_port(phy
);
101 property_enable(priv
->reg_base
, &port_cfg
->phy_sus
, false);
103 /* waiting for the utmi_clk to become stable */
104 usleep_range(1500, 2000);
109 static int rockchip_usb2phy_power_off(struct phy
*phy
)
111 struct udevice
*parent
= dev_get_parent(phy
->dev
);
112 struct rockchip_usb2phy
*priv
= dev_get_priv(parent
);
113 const struct rockchip_usb2phy_port_cfg
*port_cfg
= us2phy_get_port(phy
);
115 property_enable(priv
->reg_base
, &port_cfg
->phy_sus
, true);
120 static int rockchip_usb2phy_init(struct phy
*phy
)
122 struct udevice
*parent
= dev_get_parent(phy
->dev
);
123 struct rockchip_usb2phy
*priv
= dev_get_priv(parent
);
126 ret
= clk_enable(&priv
->phyclk
);
127 if (ret
&& ret
!= -ENOSYS
) {
128 dev_err(phy
->dev
, "failed to enable phyclk (ret=%d)\n", ret
);
135 static int rockchip_usb2phy_exit(struct phy
*phy
)
137 struct udevice
*parent
= dev_get_parent(phy
->dev
);
138 struct rockchip_usb2phy
*priv
= dev_get_priv(parent
);
140 clk_disable(&priv
->phyclk
);
145 static int rockchip_usb2phy_of_xlate(struct phy
*phy
,
146 struct ofnode_phandle_args
*args
)
148 const char *name
= phy
->dev
->name
;
150 if (!strcasecmp(name
, "host-port"))
151 phy
->id
= USB2PHY_PORT_HOST
;
152 else if (!strcasecmp(name
, "otg-port"))
153 phy
->id
= USB2PHY_PORT_OTG
;
155 dev_err(phy
->dev
, "improper %s device\n", name
);
160 static struct phy_ops rockchip_usb2phy_ops
= {
161 .init
= rockchip_usb2phy_init
,
162 .exit
= rockchip_usb2phy_exit
,
163 .power_on
= rockchip_usb2phy_power_on
,
164 .power_off
= rockchip_usb2phy_power_off
,
165 .of_xlate
= rockchip_usb2phy_of_xlate
,
169 * round_rate() - Adjust a rate to the exact rate a clock can provide.
170 * @clk: The clock to manipulate.
171 * @rate: Desidered clock rate in Hz.
173 * Return: rounded rate in Hz, or -ve error code.
175 ulong
rockchip_usb2phy_clk_round_rate(struct clk
*clk
, ulong rate
)
181 * enable() - Enable a clock.
182 * @clk: The clock to manipulate.
184 * Return: zero on success, or -ve error code.
186 int rockchip_usb2phy_clk_enable(struct clk
*clk
)
188 struct udevice
*parent
= dev_get_parent(clk
->dev
);
189 struct rockchip_usb2phy
*priv
= dev_get_priv(parent
);
190 const struct rockchip_usb2phy_cfg
*phy_cfg
= priv
->phy_cfg
;
192 /* turn on 480m clk output if it is off */
193 if (!property_enabled(priv
->reg_base
, &phy_cfg
->clkout_ctl
)) {
194 property_enable(priv
->reg_base
, &phy_cfg
->clkout_ctl
, true);
196 /* waiting for the clk become stable */
197 usleep_range(1200, 1300);
204 * disable() - Disable a clock.
205 * @clk: The clock to manipulate.
207 * Return: zero on success, or -ve error code.
209 int rockchip_usb2phy_clk_disable(struct clk
*clk
)
211 struct udevice
*parent
= dev_get_parent(clk
->dev
);
212 struct rockchip_usb2phy
*priv
= dev_get_priv(parent
);
213 const struct rockchip_usb2phy_cfg
*phy_cfg
= priv
->phy_cfg
;
215 /* turn off 480m clk output */
216 property_enable(priv
->reg_base
, &phy_cfg
->clkout_ctl
, false);
221 static struct clk_ops rockchip_usb2phy_clk_ops
= {
222 .enable
= rockchip_usb2phy_clk_enable
,
223 .disable
= rockchip_usb2phy_clk_disable
,
224 .round_rate
= rockchip_usb2phy_clk_round_rate
227 static int rockchip_usb2phy_probe(struct udevice
*dev
)
229 struct rockchip_usb2phy
*priv
= dev_get_priv(dev
);
230 const struct rockchip_usb2phy_cfg
*phy_cfgs
;
234 if (dev_read_bool(dev
, "rockchip,usbgrf"))
236 syscon_regmap_lookup_by_phandle(dev
, "rockchip,usbgrf");
238 priv
->reg_base
= syscon_get_regmap(dev_get_parent(dev
));
239 if (IS_ERR(priv
->reg_base
))
240 return PTR_ERR(priv
->reg_base
);
242 ret
= ofnode_read_u32_index(dev_ofnode(dev
), "reg", 0, ®
);
244 dev_err(dev
, "failed to read reg property (ret = %d)\n", ret
);
248 /* support address_cells=2 */
249 if (dev_read_addr_cells(dev
) == 2 && reg
== 0) {
250 if (ofnode_read_u32_index(dev_ofnode(dev
), "reg", 1, ®
)) {
251 dev_err(dev
, "%s must have reg[1]\n",
252 ofnode_get_name(dev_ofnode(dev
)));
257 phy_cfgs
= (const struct rockchip_usb2phy_cfg
*)
258 dev_get_driver_data(dev
);
262 /* find out a proper config which can be matched with dt. */
265 if (phy_cfgs
[index
].reg
== reg
) {
266 priv
->phy_cfg
= &phy_cfgs
[index
];
271 } while (phy_cfgs
[index
].reg
);
273 if (!priv
->phy_cfg
) {
274 dev_err(dev
, "failed find proper phy-cfg\n");
278 ret
= clk_get_by_name(dev
, "phyclk", &priv
->phyclk
);
280 dev_err(dev
, "failed to get the phyclk (ret=%d)\n", ret
);
287 static int rockchip_usb2phy_bind(struct udevice
*dev
)
289 struct udevice
*usb2phy_dev
;
294 dev_for_each_subnode(node
, dev
) {
295 if (!ofnode_is_enabled(node
))
298 name
= ofnode_get_name(node
);
299 dev_dbg(dev
, "subnode %s\n", name
);
301 ret
= device_bind_driver_to_node(dev
, "rockchip_usb2phy_port",
302 name
, node
, &usb2phy_dev
);
305 "'%s' cannot bind 'rockchip_usb2phy_port'\n", name
);
310 node
= dev_ofnode(dev
);
311 name
= "clk_usbphy_480m";
312 dev_read_string_index(dev
, "clock-output-names", 0, &name
);
314 dev_dbg(dev
, "clk %s for node %s\n", name
, ofnode_get_name(node
));
316 ret
= device_bind_driver_to_node(dev
, "rockchip_usb2phy_clock",
317 name
, node
, &usb2phy_dev
);
320 "'%s' cannot bind 'rockchip_usb2phy_clock'\n", name
);
327 device_chld_unbind(dev
, NULL
);
332 static const struct rockchip_usb2phy_cfg rk3308_phy_cfgs
[] = {
335 .clkout_ctl
= { 0x0108, 4, 4, 1, 0 },
337 [USB2PHY_PORT_OTG
] = {
338 .phy_sus
= { 0x0100, 1, 0, 2, 1 },
340 [USB2PHY_PORT_HOST
] = {
341 .phy_sus
= { 0x0104, 1, 0, 2, 1 },
348 static const struct rockchip_usb2phy_cfg rk3328_usb2phy_cfgs
[] = {
351 .clkout_ctl
= { 0x0108, 4, 4, 1, 0 },
353 [USB2PHY_PORT_OTG
] = {
354 .phy_sus
= { 0x0100, 1, 0, 2, 1 },
356 [USB2PHY_PORT_HOST
] = {
357 .phy_sus
= { 0x0104, 1, 0, 2, 1 },
364 static const struct rockchip_usb2phy_cfg rk3399_usb2phy_cfgs
[] = {
367 .clkout_ctl
= { 0xe450, 4, 4, 1, 0 },
369 [USB2PHY_PORT_OTG
] = {
370 .phy_sus
= { 0xe454, 1, 0, 2, 1 },
372 [USB2PHY_PORT_HOST
] = {
373 .phy_sus
= { 0xe458, 1, 0, 2, 1 },
379 .clkout_ctl
= { 0xe460, 4, 4, 1, 0 },
381 [USB2PHY_PORT_OTG
] = {
382 .phy_sus
= { 0xe464, 1, 0, 2, 1 },
384 [USB2PHY_PORT_HOST
] = {
385 .phy_sus
= { 0xe468, 1, 0, 2, 1 },
392 static const struct rockchip_usb2phy_cfg rk3568_phy_cfgs
[] = {
395 .clkout_ctl
= { 0x0008, 4, 4, 1, 0 },
397 [USB2PHY_PORT_OTG
] = {
398 .phy_sus
= { 0x0000, 1, 0, 2, 1 },
400 [USB2PHY_PORT_HOST
] = {
401 .phy_sus
= { 0x0004, 1, 0, 2, 1 },
407 .clkout_ctl
= { 0x0008, 4, 4, 1, 0 },
409 [USB2PHY_PORT_OTG
] = {
410 .phy_sus
= { 0x0000, 1, 0, 2, 1 },
412 [USB2PHY_PORT_HOST
] = {
413 .phy_sus
= { 0x0004, 1, 0, 2, 1 },
420 static const struct rockchip_usb2phy_cfg rk3588_phy_cfgs
[] = {
423 .clkout_ctl
= { 0x0000, 0, 0, 1, 0 },
425 [USB2PHY_PORT_OTG
] = {
426 .phy_sus
= { 0x000c, 11, 11, 0, 1 },
432 .clkout_ctl
= { 0x0000, 0, 0, 1, 0 },
434 [USB2PHY_PORT_OTG
] = {
435 .phy_sus
= { 0x000c, 11, 11, 0, 1 },
441 .clkout_ctl
= { 0x0000, 0, 0, 1, 0 },
443 [USB2PHY_PORT_HOST
] = {
444 .phy_sus
= { 0x0008, 2, 2, 0, 1 },
450 .clkout_ctl
= { 0x0000, 0, 0, 1, 0 },
452 [USB2PHY_PORT_HOST
] = {
453 .phy_sus
= { 0x0008, 2, 2, 0, 1 },
460 static const struct udevice_id rockchip_usb2phy_ids
[] = {
462 .compatible
= "rockchip,rk3308-usb2phy",
463 .data
= (ulong
)&rk3308_phy_cfgs
,
466 .compatible
= "rockchip,rk3328-usb2phy",
467 .data
= (ulong
)&rk3328_usb2phy_cfgs
,
470 .compatible
= "rockchip,rk3399-usb2phy",
471 .data
= (ulong
)&rk3399_usb2phy_cfgs
,
474 .compatible
= "rockchip,rk3568-usb2phy",
475 .data
= (ulong
)&rk3568_phy_cfgs
,
478 .compatible
= "rockchip,rk3588-usb2phy",
479 .data
= (ulong
)&rk3588_phy_cfgs
,
484 U_BOOT_DRIVER(rockchip_usb2phy_port
) = {
485 .name
= "rockchip_usb2phy_port",
487 .ops
= &rockchip_usb2phy_ops
,
490 U_BOOT_DRIVER(rockchip_usb2phy_clock
) = {
491 .name
= "rockchip_usb2phy_clock",
493 .ops
= &rockchip_usb2phy_clk_ops
,
496 U_BOOT_DRIVER(rockchip_usb2phy
) = {
497 .name
= "rockchip_usb2phy",
499 .of_match
= rockchip_usb2phy_ids
,
500 .probe
= rockchip_usb2phy_probe
,
501 .bind
= rockchip_usb2phy_bind
,
502 .priv_auto
= sizeof(struct rockchip_usb2phy
),