xref: /openbmc/u-boot/drivers/phy/phy-rcar-gen2.c (revision b71d9e8b)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Renesas RCar Gen2 USB PHY driver
4  *
5  * Copyright (C) 2018 Marek Vasut <marek.vasut@gmail.com>
6  */
7 
8 #include <common.h>
9 #include <clk.h>
10 #include <div64.h>
11 #include <dm.h>
12 #include <fdtdec.h>
13 #include <generic-phy.h>
14 #include <reset.h>
15 #include <syscon.h>
16 #include <usb.h>
17 #include <asm/io.h>
18 #include <linux/bitops.h>
19 #include <power/regulator.h>
20 
21 #define USBHS_LPSTS			0x02
22 #define USBHS_UGCTRL			0x80
23 #define USBHS_UGCTRL2			0x84
24 #define USBHS_UGSTS			0x88	/* From technical update */
25 
26 /* Low Power Status register (LPSTS) */
27 #define USBHS_LPSTS_SUSPM		0x4000
28 
29 /* USB General control register (UGCTRL) */
30 #define USBHS_UGCTRL_CONNECT		BIT(2)
31 #define USBHS_UGCTRL_PLLRESET		BIT(0)
32 
33 /* USB General control register 2 (UGCTRL2) */
34 #define USBHS_UGCTRL2_USB2SEL		0x80000000
35 #define USBHS_UGCTRL2_USB2SEL_PCI	0x00000000
36 #define USBHS_UGCTRL2_USB2SEL_USB30	0x80000000
37 #define USBHS_UGCTRL2_USB0SEL		0x00000030
38 #define USBHS_UGCTRL2_USB0SEL_PCI	0x00000010
39 #define USBHS_UGCTRL2_USB0SEL_HS_USB	0x00000030
40 
41 /* USB General status register (UGSTS) */
42 #define USBHS_UGSTS_LOCK		0x00000100 /* From technical update */
43 
44 #define PHYS_PER_CHANNEL	2
45 
46 struct rcar_gen2_phy {
47 	fdt_addr_t	regs;
48 	struct clk	clk;
49 };
50 
rcar_gen2_phy_phy_init(struct phy * phy)51 static int rcar_gen2_phy_phy_init(struct phy *phy)
52 {
53 	struct rcar_gen2_phy *priv = dev_get_priv(phy->dev);
54 	u16 chan = phy->id & 0xffff;
55 	u16 mode = (phy->id >> 16) & 0xffff;
56 	u32 clrmask, setmask;
57 
58 	if (chan == 0) {
59 		clrmask = USBHS_UGCTRL2_USB0SEL;
60 		setmask = mode ? USBHS_UGCTRL2_USB0SEL_HS_USB :
61 				 USBHS_UGCTRL2_USB0SEL_PCI;
62 	} else {
63 		clrmask = USBHS_UGCTRL2_USB2SEL;
64 		setmask = mode ? USBHS_UGCTRL2_USB2SEL_USB30 :
65 				 USBHS_UGCTRL2_USB2SEL_PCI;
66 	}
67 	clrsetbits_le32(priv->regs + USBHS_UGCTRL2, clrmask, setmask);
68 
69 	return 0;
70 }
71 
rcar_gen2_phy_phy_power_on(struct phy * phy)72 static int rcar_gen2_phy_phy_power_on(struct phy *phy)
73 {
74 	struct rcar_gen2_phy *priv = dev_get_priv(phy->dev);
75 	int i;
76 	u32 value;
77 
78 	/* Power on USBHS PHY */
79 	clrbits_le32(priv->regs + USBHS_UGCTRL, USBHS_UGCTRL_PLLRESET);
80 
81 	setbits_le16(priv->regs + USBHS_LPSTS, USBHS_LPSTS_SUSPM);
82 
83 	for (i = 0; i < 20; i++) {
84 		value = readl(priv->regs + USBHS_UGSTS);
85 		if ((value & USBHS_UGSTS_LOCK) == USBHS_UGSTS_LOCK) {
86 			setbits_le32(priv->regs + USBHS_UGCTRL,
87 				     USBHS_UGCTRL_CONNECT);
88 			return 0;
89 		}
90 		udelay(1);
91 	}
92 
93 	return -ETIMEDOUT;
94 }
95 
rcar_gen2_phy_phy_power_off(struct phy * phy)96 static int rcar_gen2_phy_phy_power_off(struct phy *phy)
97 {
98 	struct rcar_gen2_phy *priv = dev_get_priv(phy->dev);
99 
100 	/* Power off USBHS PHY */
101 	clrbits_le32(priv->regs + USBHS_UGCTRL, USBHS_UGCTRL_CONNECT);
102 
103 	clrbits_le16(priv->regs + USBHS_LPSTS, USBHS_LPSTS_SUSPM);
104 
105 	setbits_le32(priv->regs + USBHS_UGCTRL, USBHS_UGCTRL_PLLRESET);
106 
107 	return 0;
108 }
109 
rcar_gen2_phy_of_xlate(struct phy * phy,struct ofnode_phandle_args * args)110 static int rcar_gen2_phy_of_xlate(struct phy *phy,
111 				  struct ofnode_phandle_args *args)
112 {
113 	if (args->args_count != 2) {
114 		dev_err(phy->dev, "Invalid DT PHY argument count: %d\n",
115 			args->args_count);
116 		return -EINVAL;
117 	}
118 
119 	if (args->args[0] != 0 && args->args[0] != 2) {
120 		dev_err(phy->dev, "Invalid DT PHY channel: %d\n",
121 			args->args[0]);
122 		return -EINVAL;
123 	}
124 
125 	if (args->args[1] != 0 && args->args[1] != 1) {
126 		dev_err(phy->dev, "Invalid DT PHY mode: %d\n",
127 			args->args[1]);
128 		return -EINVAL;
129 	}
130 
131 	if (args->args_count)
132 		phy->id = args->args[0] | (args->args[1] << 16);
133 	else
134 		phy->id = 0;
135 
136 	return 0;
137 }
138 
139 static const struct phy_ops rcar_gen2_phy_phy_ops = {
140 	.init		= rcar_gen2_phy_phy_init,
141 	.power_on	= rcar_gen2_phy_phy_power_on,
142 	.power_off	= rcar_gen2_phy_phy_power_off,
143 	.of_xlate	= rcar_gen2_phy_of_xlate,
144 };
145 
rcar_gen2_phy_probe(struct udevice * dev)146 static int rcar_gen2_phy_probe(struct udevice *dev)
147 {
148 	struct rcar_gen2_phy *priv = dev_get_priv(dev);
149 	int ret;
150 
151 	priv->regs = dev_read_addr(dev);
152 	if (priv->regs == FDT_ADDR_T_NONE)
153 		return -EINVAL;
154 
155 	/* Enable clock */
156 	ret = clk_get_by_index(dev, 0, &priv->clk);
157 	if (ret)
158 		return ret;
159 
160 	ret = clk_enable(&priv->clk);
161 	if (ret)
162 		return ret;
163 
164 	return 0;
165 }
166 
rcar_gen2_phy_remove(struct udevice * dev)167 static int rcar_gen2_phy_remove(struct udevice *dev)
168 {
169 	struct rcar_gen2_phy *priv = dev_get_priv(dev);
170 
171 	clk_disable(&priv->clk);
172 	clk_free(&priv->clk);
173 
174 	return 0;
175 }
176 
177 static const struct udevice_id rcar_gen2_phy_of_match[] = {
178 	{ .compatible = "renesas,rcar-gen2-usb-phy", },
179 	{ },
180 };
181 
182 U_BOOT_DRIVER(rcar_gen2_phy) = {
183 	.name		= "rcar-gen2-phy",
184 	.id		= UCLASS_PHY,
185 	.of_match	= rcar_gen2_phy_of_match,
186 	.ops		= &rcar_gen2_phy_phy_ops,
187 	.probe		= rcar_gen2_phy_probe,
188 	.remove		= rcar_gen2_phy_remove,
189 	.priv_auto_alloc_size = sizeof(struct rcar_gen2_phy),
190 };
191