xref: /openbsd-src/sys/dev/fdt/rkusbphy.c (revision b3b04c1d97c9824a95512d22467daa8ce67b03bd)
1 /*	$OpenBSD: rkusbphy.c,v 1.6 2024/11/24 22:46:54 kettenis Exp $ */
2 
3 /*
4  * Copyright (c) 2023 David Gwynne <dlg@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*
20  * Rockchip USB2PHY with Innosilicon IP
21  */
22 
23 #include <sys/param.h>
24 #include <sys/systm.h>
25 #include <sys/device.h>
26 
27 #include <machine/intr.h>
28 #include <machine/bus.h>
29 #include <machine/fdt.h>
30 
31 #include <dev/ofw/openfirm.h>
32 #include <dev/ofw/ofw_clock.h>
33 #include <dev/ofw/ofw_regulator.h>
34 #include <dev/ofw/ofw_misc.h>
35 #include <dev/ofw/fdt.h>
36 
37 /*
38  * chip stuff
39  */
40 
41 struct rkusbphy_reg {
42 	bus_size_t			r_offs;
43 	unsigned int			r_shift;
44 	uint32_t			r_mask;
45 	uint32_t			r_set;
46 };
47 
48 struct rkusbphy_port_regs {
49 	struct rkusbphy_reg		phy_enable;
50 };
51 
52 struct rkusbphy_regs {
53 	struct rkusbphy_reg		clk_enable;
54 
55 	struct rkusbphy_port_regs	otg;
56 	struct rkusbphy_port_regs	host;
57 };
58 
59 struct rkusbphy_chip {
60 	bus_addr_t			 c_base_addr;
61 	const struct rkusbphy_regs	*c_regs;
62 };
63 
64 /*
65  * RK3399 has two USB2PHY nodes that share a GRF.
66  */
67 
68 static const struct rkusbphy_regs rkusbphy_rk3399_usb0_regs = {
69 	/*				shift,	mask,	set */
70 	.clk_enable =	{ 0xe450,	4,	0x1,	0x0 },
71 
72 	.otg = {
73 		.phy_enable =	{ 0xe454,	0,	0x3,	0x2 },
74 	},
75 
76 	.host = {
77 		.phy_enable =	{ 0xe458,	0,	0x3,	0x2 },
78 	},
79 };
80 
81 static const struct rkusbphy_regs rkusbphy_rk3399_usb1_regs = {
82 	/*				shift,	mask,	set */
83 	.clk_enable =	{ 0xe460,	4,	0x1,	0x0 },
84 
85 	.otg = {
86 		.phy_enable =	{ 0xe464,	0,	0x3,	0x2 },
87 	},
88 
89 	.host = {
90 		.phy_enable =	{ 0xe468,	0,	0x3,	0x2 },
91 	},
92  };
93 
94 static const struct rkusbphy_chip rkusbphy_rk3399[] = {
95 	{
96 		.c_base_addr = 0xe450,
97 		.c_regs = &rkusbphy_rk3399_usb0_regs,
98 	},
99 	{
100 		.c_base_addr = 0xe460,
101 		.c_regs = &rkusbphy_rk3399_usb1_regs,
102 	},
103 };
104 
105 /*
106  * RK3568 has two USB2PHY nodes that have a GRF each. Each GRF has
107  * the same register layout.
108  */
109 
110 static const struct rkusbphy_regs rkusbphy_rk3568_regs = {
111 	/*				shift,	mask,	set */
112 	.clk_enable =	{ 0x0008,	4,	0x1,	0x0 },
113 
114 	.otg = {
115 		.phy_enable =	{ 0x0000,	0,	0x1ff,	0x1d2 },
116 	},
117 
118 	.host = {
119 		.phy_enable =	{ 0x0004,	0,	0x1ff,	0x1d2 },
120 	},
121 };
122 
123 static const struct rkusbphy_chip rkusbphy_rk3568[] = {
124 	{
125 		.c_base_addr = 0xfe8a0000,
126 		.c_regs = &rkusbphy_rk3568_regs,
127 	},
128 	{
129 		.c_base_addr = 0xfe8b0000,
130 		.c_regs = &rkusbphy_rk3568_regs,
131 	},
132 };
133 
134 static const struct rkusbphy_regs rkusbphy_rk3588_regs = {
135 	/*				shift,	mask,	set */
136 	.clk_enable =	{ 0x0000,	0,	0x1,	0x0 },
137 
138 	.otg = {
139 		.phy_enable =	{ 0x000c,	11,	0x1,	0x0 },
140 	},
141 
142 	.host = {
143 		.phy_enable =	{ 0x0008,	2,	0x1,	0x0 },
144 	},
145 };
146 
147 static const struct rkusbphy_chip rkusbphy_rk3588[] = {
148 	{
149 		.c_base_addr = 0x0000,
150 		.c_regs = &rkusbphy_rk3588_regs,
151 	},
152 	{
153 		.c_base_addr = 0x4000,
154 		.c_regs = &rkusbphy_rk3588_regs,
155 	},
156 	{
157 		.c_base_addr = 0x8000,
158 		.c_regs = &rkusbphy_rk3588_regs,
159 	},
160 	{
161 		.c_base_addr = 0xc000,
162 		.c_regs = &rkusbphy_rk3588_regs,
163 	},
164 };
165 
166 /*
167  * driver stuff
168  */
169 
170 struct rkusbphy_softc {
171 	struct device			 sc_dev;
172 	const struct rkusbphy_regs	*sc_regs;
173 	struct regmap			*sc_grf;
174 	int				 sc_node;
175 
176 	int				 sc_running;
177 
178 	struct phy_device		 sc_otg_phy;
179 	struct phy_device		 sc_host_phy;
180 };
181 #define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname)
182 
183 static int		rkusbphy_match(struct device *, void *, void *);
184 static void		rkusbphy_attach(struct device *, struct device *,
185 			    void *);
186 
187 static uint32_t		rkusbphy_rd(struct rkusbphy_softc *,
188 			    const struct rkusbphy_reg *);
189 static int		rkusbphy_isset(struct rkusbphy_softc *,
190 			    const struct rkusbphy_reg *);
191 static void		rkusbphy_wr(struct rkusbphy_softc *,
192 			    const struct rkusbphy_reg *, uint32_t);
193 static void		rkusbphy_set(struct rkusbphy_softc *,
194 			    const struct rkusbphy_reg *);
195 
196 static int		rkusbphy_otg_phy_enable(void *, uint32_t *);
197 static int		rkusbphy_host_phy_enable(void *, uint32_t *);
198 
199 struct rkusbphy_port_config {
200 	const char			*pc_name;
201 	int (*pc_enable)(void *, uint32_t *);
202 };
203 
204 static void	rkusbphy_register(struct rkusbphy_softc *,
205 		    struct phy_device *, const struct rkusbphy_port_config *);
206 
207 static const struct rkusbphy_port_config rkusbphy_otg_config = {
208 	.pc_name = "otg-port",
209 	.pc_enable = rkusbphy_otg_phy_enable,
210 };
211 
212 static const struct rkusbphy_port_config rkusbphy_host_config = {
213 	.pc_name = "host-port",
214 	.pc_enable = rkusbphy_host_phy_enable,
215 };
216 
217 const struct cfattach rkusbphy_ca = {
218 	sizeof (struct rkusbphy_softc), rkusbphy_match, rkusbphy_attach
219 };
220 
221 struct cfdriver rkusbphy_cd = {
222 	NULL, "rkusbphy", DV_DULL
223 };
224 
225 struct rkusbphy_id {
226 	const char			*id_name;
227 	const struct rkusbphy_chip	*id_chips;
228 	size_t				 id_nchips;
229 };
230 
231 #define RKUSBPHY_ID(_n, _c) { _n, _c, nitems(_c) }
232 
233 static const struct rkusbphy_id rkusbphy_ids[] = {
234 	RKUSBPHY_ID("rockchip,rk3399-usb2phy", rkusbphy_rk3399),
235 	RKUSBPHY_ID("rockchip,rk3568-usb2phy", rkusbphy_rk3568),
236 	RKUSBPHY_ID("rockchip,rk3588-usb2phy", rkusbphy_rk3588),
237 };
238 
239 static const struct rkusbphy_id *
240 rkusbphy_lookup(struct fdt_attach_args *faa)
241 {
242 	size_t i;
243 
244 	for (i = 0; i < nitems(rkusbphy_ids); i++) {
245 		const struct rkusbphy_id *id = &rkusbphy_ids[i];
246 		if (OF_is_compatible(faa->fa_node, id->id_name))
247 			return (id);
248 	}
249 
250 	return (NULL);
251 }
252 
253 static int
254 rkusbphy_match(struct device *parent, void *match, void *aux)
255 {
256 	struct fdt_attach_args *faa = aux;
257 
258 	return (rkusbphy_lookup(faa) != NULL ? 1 : 0);
259 }
260 
261 static void
262 rkusbphy_attach(struct device *parent, struct device *self, void *aux)
263 {
264 	struct rkusbphy_softc *sc = (struct rkusbphy_softc *)self;
265 	struct fdt_attach_args *faa = aux;
266 	const struct rkusbphy_id *id = rkusbphy_lookup(faa);
267 	size_t i;
268 	uint32_t grfph;
269 
270 	if (faa->fa_nreg < 1) {
271 		printf(": no registers\n");
272 		return;
273 	}
274 
275 	for (i = 0; i < id->id_nchips; i++) {
276 		const struct rkusbphy_chip *c = &id->id_chips[i];
277 		if (faa->fa_reg[0].addr == c->c_base_addr) {
278 			printf(": phy %zu\n", i);
279 			sc->sc_regs = c->c_regs;
280 			break;
281 		}
282 	}
283 	if (sc->sc_regs == NULL) {
284 		printf(": unknown base address 0x%llu\n", faa->fa_reg[0].addr);
285 		return;
286 	}
287 
288 	sc->sc_node = faa->fa_node;
289 
290 	grfph = OF_getpropint(sc->sc_node, "rockchip,usbgrf", 0);
291 	if (grfph)
292 		sc->sc_grf = regmap_byphandle(grfph);
293 	else
294 		sc->sc_grf = regmap_bynode(OF_parent(faa->fa_node));
295 	if (sc->sc_grf == NULL) {
296 		printf("%s: rockchip,usbgrf 0x%x not found\n", DEVNAME(sc),
297 		    grfph);
298 		return;
299 	}
300 
301 	rkusbphy_register(sc, &sc->sc_otg_phy, &rkusbphy_otg_config);
302 	rkusbphy_register(sc, &sc->sc_host_phy, &rkusbphy_host_config);
303 }
304 
305 static uint32_t
306 rkusbphy_rd(struct rkusbphy_softc *sc, const struct rkusbphy_reg *r)
307 {
308 	uint32_t v;
309 
310 	if (r->r_mask == 0)
311 		return (0);
312 
313 	v = regmap_read_4(sc->sc_grf, r->r_offs);
314 
315 	return ((v >> r->r_shift) & r->r_mask);
316 }
317 
318 static int
319 rkusbphy_isset(struct rkusbphy_softc *sc, const struct rkusbphy_reg *r)
320 {
321 	return (rkusbphy_rd(sc, r) == r->r_set);
322 }
323 
324 static void
325 rkusbphy_wr(struct rkusbphy_softc *sc, const struct rkusbphy_reg *r, uint32_t v)
326 {
327 	if (r->r_mask == 0)
328 		return;
329 
330 	regmap_write_4(sc->sc_grf, r->r_offs,
331 	    (r->r_mask << (r->r_shift + 16)) | (v << r->r_shift));
332 }
333 
334 static void
335 rkusbphy_set(struct rkusbphy_softc *sc, const struct rkusbphy_reg *r)
336 {
337 	rkusbphy_wr(sc, r, r->r_set);
338 }
339 
340 static void
341 rkusbphy_register(struct rkusbphy_softc *sc, struct phy_device *pd,
342     const struct rkusbphy_port_config *pc)
343 {
344 	char status[32];
345 	int node;
346 
347 	node = OF_getnodebyname(sc->sc_node, pc->pc_name);
348 	if (node == 0)
349 		return;
350 
351 	if (OF_getprop(node, "status", status, sizeof(status)) > 0 &&
352 	    strcmp(status, "disabled") == 0)
353 		return;
354 
355 	pd->pd_node = node;
356 	pd->pd_cookie = sc;
357 	pd->pd_enable = pc->pc_enable;
358 	phy_register(pd);
359 }
360 
361 static void
362 rkusbphy_phy_supply(struct rkusbphy_softc *sc, int node)
363 {
364 	int phandle;
365 
366 	if (!sc->sc_running) {
367 		clock_enable(sc->sc_node, "phyclk");
368 		if (!rkusbphy_isset(sc, &sc->sc_regs->clk_enable)) {
369 			rkusbphy_set(sc, &sc->sc_regs->clk_enable);
370 
371 			delay(1200);
372 		}
373 
374 		sc->sc_running = 1;
375 	}
376 
377 	phandle = OF_getpropint(node, "phy-supply", 0);
378 	if (phandle == 0)
379 		return;
380 
381 	regulator_enable(phandle);
382 }
383 
384 static int
385 rkusbphy_otg_phy_enable(void *cookie, uint32_t *cells)
386 {
387 	struct rkusbphy_softc *sc = cookie;
388 
389 	rkusbphy_phy_supply(sc, sc->sc_otg_phy.pd_node);
390 
391 	rkusbphy_set(sc, &sc->sc_regs->otg.phy_enable);
392 	delay(1500);
393 
394 	return (EINVAL);
395 }
396 
397 static int
398 rkusbphy_host_phy_enable(void *cookie, uint32_t *cells)
399 {
400 	struct rkusbphy_softc *sc = cookie;
401 
402 	rkusbphy_phy_supply(sc, sc->sc_host_phy.pd_node);
403 
404 	rkusbphy_set(sc, &sc->sc_regs->host.phy_enable);
405 	delay(1500);
406 
407 	return (EINVAL);
408 }
409