xref: /freebsd/sys/arm/allwinner/aw_usbphy.c (revision e17f5b1d)
1 /*-
2  * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
18  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
20  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
21  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  * $FreeBSD$
26  */
27 
28 /*
29  * Allwinner USB PHY
30  */
31 
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/bus.h>
38 #include <sys/rman.h>
39 #include <sys/kernel.h>
40 #include <sys/module.h>
41 #include <sys/gpio.h>
42 #include <machine/bus.h>
43 
44 #include <dev/ofw/ofw_bus.h>
45 #include <dev/ofw/ofw_bus_subr.h>
46 #include <dev/gpio/gpiobusvar.h>
47 
48 #include <dev/extres/clk/clk.h>
49 #include <dev/extres/hwreset/hwreset.h>
50 #include <dev/extres/regulator/regulator.h>
51 #include <dev/extres/phy/phy_usb.h>
52 
53 #include "phynode_if.h"
54 
55 enum awusbphy_type {
56 	AWUSBPHY_TYPE_A10 = 1,
57 	AWUSBPHY_TYPE_A13,
58 	AWUSBPHY_TYPE_A20,
59 	AWUSBPHY_TYPE_A31,
60 	AWUSBPHY_TYPE_H3,
61 	AWUSBPHY_TYPE_A64,
62 	AWUSBPHY_TYPE_A83T,
63 	AWUSBPHY_TYPE_H6,
64 };
65 
66 struct aw_usbphy_conf {
67 	int			num_phys;
68 	enum awusbphy_type	phy_type;
69 	bool			pmu_unk1;
70 	bool			phy0_route;
71 };
72 
73 static const struct aw_usbphy_conf a10_usbphy_conf = {
74 	.num_phys = 3,
75 	.phy_type = AWUSBPHY_TYPE_A10,
76 	.pmu_unk1 = false,
77 	.phy0_route = false,
78 };
79 
80 static const struct aw_usbphy_conf a13_usbphy_conf = {
81 	.num_phys = 2,
82 	.phy_type = AWUSBPHY_TYPE_A13,
83 	.pmu_unk1 = false,
84 	.phy0_route = false,
85 };
86 
87 static const struct aw_usbphy_conf a20_usbphy_conf = {
88 	.num_phys = 3,
89 	.phy_type = AWUSBPHY_TYPE_A20,
90 	.pmu_unk1 = false,
91 	.phy0_route = false,
92 };
93 
94 static const struct aw_usbphy_conf a31_usbphy_conf = {
95 	.num_phys = 3,
96 	.phy_type = AWUSBPHY_TYPE_A31,
97 	.pmu_unk1 = false,
98 	.phy0_route = false,
99 };
100 
101 static const struct aw_usbphy_conf h3_usbphy_conf = {
102 	.num_phys = 4,
103 	.phy_type = AWUSBPHY_TYPE_H3,
104 	.pmu_unk1 = true,
105 	.phy0_route = false,
106 };
107 
108 static const struct aw_usbphy_conf a64_usbphy_conf = {
109 	.num_phys = 2,
110 	.phy_type = AWUSBPHY_TYPE_A64,
111 	.pmu_unk1 = true,
112 	.phy0_route = true,
113 };
114 
115 static const struct aw_usbphy_conf a83t_usbphy_conf = {
116 	.num_phys = 3,
117 	.phy_type = AWUSBPHY_TYPE_A83T,
118 	.pmu_unk1 = false,
119 	.phy0_route = false,
120 };
121 
122 static const struct aw_usbphy_conf h6_usbphy_conf = {
123 	.num_phys = 4,
124 	.phy_type = AWUSBPHY_TYPE_H6,
125 	.pmu_unk1 = false,
126 	.phy0_route = true,
127 };
128 
129 static struct ofw_compat_data compat_data[] = {
130 	{ "allwinner,sun4i-a10-usb-phy",	(uintptr_t)&a10_usbphy_conf },
131 	{ "allwinner,sun5i-a13-usb-phy",	(uintptr_t)&a13_usbphy_conf },
132 	{ "allwinner,sun6i-a31-usb-phy",	(uintptr_t)&a31_usbphy_conf },
133 	{ "allwinner,sun7i-a20-usb-phy",	(uintptr_t)&a20_usbphy_conf },
134 	{ "allwinner,sun8i-h3-usb-phy",		(uintptr_t)&h3_usbphy_conf },
135 	{ "allwinner,sun50i-a64-usb-phy",	(uintptr_t)&a64_usbphy_conf },
136 	{ "allwinner,sun8i-a83t-usb-phy",	(uintptr_t)&a83t_usbphy_conf },
137 	{ "allwinner,sun50i-h6-usb-phy",	(uintptr_t)&h6_usbphy_conf },
138 	{ NULL,					0 }
139 };
140 
141 struct awusbphy_softc {
142 	struct resource *	phy_ctrl;
143 	struct resource **	pmu;
144 	regulator_t *		reg;
145 	gpio_pin_t		id_det_pin;
146 	int			id_det_valid;
147 	gpio_pin_t		vbus_det_pin;
148 	int			vbus_det_valid;
149 	struct aw_usbphy_conf	*phy_conf;
150 	int			mode;
151 };
152 
153  /* Phy class and methods. */
154 static int awusbphy_phy_enable(struct phynode *phy, bool enable);
155 static int awusbphy_get_mode(struct phynode *phy, int *mode);
156 static int awusbphy_set_mode(struct phynode *phy, int mode);
157 static phynode_usb_method_t awusbphy_phynode_methods[] = {
158 	PHYNODEMETHOD(phynode_enable, awusbphy_phy_enable),
159 	PHYNODEMETHOD(phynode_usb_get_mode, awusbphy_get_mode),
160 	PHYNODEMETHOD(phynode_usb_set_mode, awusbphy_set_mode),
161 
162 	PHYNODEMETHOD_END
163 };
164 DEFINE_CLASS_1(awusbphy_phynode, awusbphy_phynode_class, awusbphy_phynode_methods,
165   sizeof(struct phynode_usb_sc), phynode_usb_class);
166 
167 #define	RD4(res, o)	bus_read_4(res, (o))
168 #define	WR4(res, o, v)	bus_write_4(res, (o), (v))
169 #define	CLR4(res, o, m)	WR4(res, o, RD4(res, o) & ~(m))
170 #define	SET4(res, o, m)	WR4(res, o, RD4(res, o) | (m))
171 
172 #define	OTG_PHY_CFG	0x20
173 #define	 OTG_PHY_ROUTE_OTG	(1 << 0)
174 #define	PMU_IRQ_ENABLE	0x00
175 #define	 PMU_AHB_INCR8		(1 << 10)
176 #define	 PMU_AHB_INCR4		(1 << 9)
177 #define	 PMU_AHB_INCRX_ALIGN	(1 << 8)
178 #define	 PMU_ULPI_BYPASS	(1 << 0)
179 #define	PMU_UNK_H3	0x10
180 #define	 PMU_UNK_H3_CLR		0x2
181 #define	PHY_CSR		0x00
182 #define	 ID_PULLUP_EN		(1 << 17)
183 #define	 DPDM_PULLUP_EN		(1 << 16)
184 #define	 FORCE_ID		(0x3 << 14)
185 #define	 FORCE_ID_SHIFT		14
186 #define	 FORCE_ID_LOW		2
187 #define	 FORCE_VBUS_VALID	(0x3 << 12)
188 #define	 FORCE_VBUS_VALID_SHIFT	12
189 #define	 FORCE_VBUS_VALID_HIGH	3
190 #define	 VBUS_CHANGE_DET	(1 << 6)
191 #define	 ID_CHANGE_DET		(1 << 5)
192 #define	 DPDM_CHANGE_DET	(1 << 4)
193 
194 static void
195 awusbphy_configure(device_t dev, int phyno)
196 {
197 	struct awusbphy_softc *sc;
198 
199 	sc = device_get_softc(dev);
200 
201 	if (sc->pmu[phyno] == NULL)
202 		return;
203 
204 	if (sc->phy_conf->pmu_unk1 == true)
205 		CLR4(sc->pmu[phyno], PMU_UNK_H3, PMU_UNK_H3_CLR);
206 
207 	SET4(sc->pmu[phyno], PMU_IRQ_ENABLE, PMU_ULPI_BYPASS |
208 	    PMU_AHB_INCR8 | PMU_AHB_INCR4 | PMU_AHB_INCRX_ALIGN);
209 }
210 
211 static int
212 awusbphy_init(device_t dev)
213 {
214 	struct awusbphy_softc *sc;
215 	phandle_t node;
216 	char pname[20];
217 	int error, off, rid;
218 	regulator_t reg;
219 	hwreset_t rst;
220 	clk_t clk;
221 
222 	sc = device_get_softc(dev);
223 	node = ofw_bus_get_node(dev);
224 
225 	sc->phy_conf = (struct aw_usbphy_conf *)ofw_bus_search_compatible(dev, compat_data)->ocd_data;
226 
227 	/* Get phy_ctrl region */
228 	if (ofw_bus_find_string_index(node, "reg-names", "phy_ctrl", &rid) != 0) {
229 		device_printf(dev, "Cannot locate phy control resource\n");
230 		return (ENXIO);
231 	}
232 	sc->phy_ctrl = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
233 	    RF_ACTIVE);
234 	if (sc->phy_ctrl == NULL) {
235 		device_printf(dev, "Cannot allocate resource\n");
236 		return (ENXIO);
237 	}
238 
239 	/* Enable clocks */
240 	for (off = 0; clk_get_by_ofw_index(dev, 0, off, &clk) == 0; off++) {
241 		error = clk_enable(clk);
242 		if (error != 0) {
243 			device_printf(dev, "couldn't enable clock %s\n",
244 			    clk_get_name(clk));
245 			return (error);
246 		}
247 	}
248 
249 	/* De-assert resets */
250 	for (off = 0; hwreset_get_by_ofw_idx(dev, 0, off, &rst) == 0; off++) {
251 		error = hwreset_deassert(rst);
252 		if (error != 0) {
253 			device_printf(dev, "couldn't de-assert reset %d\n",
254 			    off);
255 			return (error);
256 		}
257 	}
258 
259 	/* Get GPIOs */
260 	error = gpio_pin_get_by_ofw_property(dev, node, "usb0_id_det-gpios",
261 	    &sc->id_det_pin);
262 	if (error == 0)
263 		sc->id_det_valid = 1;
264 	error = gpio_pin_get_by_ofw_property(dev, node, "usb0_vbus_det-gpios",
265 	    &sc->vbus_det_pin);
266 	if (error == 0)
267 		sc->vbus_det_valid = 1;
268 
269 	sc->reg = malloc(sizeof(*(sc->reg)) * sc->phy_conf->num_phys, M_DEVBUF,
270 	    M_WAITOK | M_ZERO);
271 	sc->pmu = malloc(sizeof(*(sc->pmu)) * sc->phy_conf->num_phys, M_DEVBUF,
272 	    M_WAITOK | M_ZERO);
273 	/* Get regulators */
274 	for (off = 0; off < sc->phy_conf->num_phys; off++) {
275 		snprintf(pname, sizeof(pname), "usb%d_vbus-supply", off);
276 		if (regulator_get_by_ofw_property(dev, 0, pname, &reg) == 0)
277 			sc->reg[off] = reg;
278 
279 		snprintf(pname, sizeof(pname), "pmu%d", off);
280 		if (ofw_bus_find_string_index(node, "reg-names",
281 		    pname, &rid) != 0)
282 			continue;
283 
284 		sc->pmu[off] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
285 		    RF_ACTIVE);
286 		if (sc->pmu[off] == NULL) {
287 			device_printf(dev, "Cannot allocate resource\n");
288 			return (ENXIO);
289 		}
290 	}
291 
292 	return (0);
293 }
294 
295 static int
296 awusbphy_vbus_detect(device_t dev, int *val)
297 {
298 	struct awusbphy_softc *sc;
299 	bool active;
300 	int error;
301 
302 	sc = device_get_softc(dev);
303 
304 	if (sc->vbus_det_valid) {
305 		error = gpio_pin_is_active(sc->vbus_det_pin, &active);
306 		if (error != 0) {
307 			device_printf(dev, "Cannot get status of id pin %d\n",
308 			    error);
309 			return (error);
310 		}
311 		*val = active;
312 		return (0);
313 	}
314 
315 	*val = 0;
316 	return (0);
317 }
318 
319 static int
320 awusbphy_phy_enable(struct phynode *phynode, bool enable)
321 {
322 	device_t dev;
323 	intptr_t phy;
324 	struct awusbphy_softc *sc;
325 	regulator_t reg;
326 	int error, vbus_det;
327 
328 	dev = phynode_get_device(phynode);
329 	phy = phynode_get_id(phynode);
330 	sc = device_get_softc(dev);
331 
332 	if (phy < 0 || phy >= sc->phy_conf->num_phys)
333 		return (ERANGE);
334 
335 	/* Configure PHY */
336 	awusbphy_configure(dev, phy);
337 
338 	/* Regulators are optional. If not found, return success. */
339 	reg = sc->reg[phy];
340 	if (reg == NULL)
341 		return (0);
342 
343 	if (phy == 0) {
344 		/* If an external vbus is detected, do not enable phy 0 */
345 		error = awusbphy_vbus_detect(dev, &vbus_det);
346 		if (error)
347 			goto out;
348 
349 		if (vbus_det == 1) {
350 			if (bootverbose)
351 				device_printf(dev, "External VBUS detected, not enabling the regulator\n");
352 
353 			return (0);
354 		}
355 	}
356 	if (enable) {
357 		/* Depending on the PHY we need to route OTG to OHCI/EHCI */
358 		error = regulator_enable(reg);
359 	} else
360 		error = regulator_disable(reg);
361 
362 out:
363 	if (error != 0) {
364 		device_printf(dev,
365 		    "couldn't %s regulator for phy %jd\n",
366 		    enable ? "enable" : "disable", (intmax_t)phy);
367 		return (error);
368 	}
369 
370 	return (0);
371 }
372 
373 static int
374 awusbphy_get_mode(struct phynode *phynode, int *mode)
375 {
376 	struct awusbphy_softc *sc;
377 	device_t dev;
378 
379 	dev = phynode_get_device(phynode);
380 	sc = device_get_softc(dev);
381 
382 	*mode = sc->mode;
383 
384 	return (0);
385 }
386 
387 static int
388 awusbphy_set_mode(struct phynode *phynode, int mode)
389 {
390 	device_t dev;
391 	intptr_t phy;
392 	struct awusbphy_softc *sc;
393 	uint32_t val;
394 	int error, vbus_det;
395 
396 	dev = phynode_get_device(phynode);
397 	phy = phynode_get_id(phynode);
398 	sc = device_get_softc(dev);
399 
400 	if (phy != 0) {
401 		if (mode != PHY_USB_MODE_HOST)
402 			return (EINVAL);
403 		return (0);
404 	}
405 
406 	switch (mode) {
407 	case PHY_USB_MODE_HOST:
408 		val = bus_read_4(sc->phy_ctrl, PHY_CSR);
409 		val &= ~(VBUS_CHANGE_DET | ID_CHANGE_DET | DPDM_CHANGE_DET);
410 		val |= (ID_PULLUP_EN | DPDM_PULLUP_EN);
411 		val &= ~FORCE_ID;
412 		val |= (FORCE_ID_LOW << FORCE_ID_SHIFT);
413 		val &= ~FORCE_VBUS_VALID;
414 		val |= (FORCE_VBUS_VALID_HIGH << FORCE_VBUS_VALID_SHIFT);
415 		bus_write_4(sc->phy_ctrl, PHY_CSR, val);
416 		if (sc->phy_conf->phy0_route == true) {
417 			error = awusbphy_vbus_detect(dev, &vbus_det);
418 			if (error)
419 				goto out;
420 			if (vbus_det == 0)
421 				CLR4(sc->phy_ctrl, OTG_PHY_CFG,
422 				  OTG_PHY_ROUTE_OTG);
423 			else
424 				SET4(sc->phy_ctrl, OTG_PHY_CFG,
425 				  OTG_PHY_ROUTE_OTG);
426 		}
427 		break;
428 	case PHY_USB_MODE_OTG:
429 		/* TODO */
430 		break;
431 	}
432 
433 	sc->mode = mode;
434 
435 
436 out:
437 	return (0);
438 }
439 
440 static int
441 awusbphy_probe(device_t dev)
442 {
443 	if (!ofw_bus_status_okay(dev))
444 		return (ENXIO);
445 
446 	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
447 		return (ENXIO);
448 
449 	device_set_desc(dev, "Allwinner USB PHY");
450 	return (BUS_PROBE_DEFAULT);
451 }
452 
453 static int
454 awusbphy_attach(device_t dev)
455 {
456 	int error;
457 	struct phynode *phynode;
458 	struct phynode_init_def phy_init;
459 	struct awusbphy_softc *sc;
460 	int i;
461 
462 	sc = device_get_softc(dev);
463 	error = awusbphy_init(dev);
464 	if (error) {
465 		device_printf(dev, "failed to initialize USB PHY, error %d\n",
466 		    error);
467 		return (error);
468 	}
469 
470 	/* Create and register phys. */
471 	for (i = 0; i < sc->phy_conf->num_phys; i++) {
472 		bzero(&phy_init, sizeof(phy_init));
473 		phy_init.id = i;
474 		phy_init.ofw_node = ofw_bus_get_node(dev);
475 		phynode = phynode_create(dev, &awusbphy_phynode_class,
476 		    &phy_init);
477 		if (phynode == NULL) {
478 			device_printf(dev, "failed to create USB PHY\n");
479 			return (ENXIO);
480 		}
481 		if (phynode_register(phynode) == NULL) {
482 			device_printf(dev, "failed to create USB PHY\n");
483 			return (ENXIO);
484 		}
485 	}
486 
487 	return (error);
488 }
489 
490 static device_method_t awusbphy_methods[] = {
491 	/* Device interface */
492 	DEVMETHOD(device_probe,		awusbphy_probe),
493 	DEVMETHOD(device_attach,	awusbphy_attach),
494 
495 	DEVMETHOD_END
496 };
497 
498 static driver_t awusbphy_driver = {
499 	"awusbphy",
500 	awusbphy_methods,
501 	sizeof(struct awusbphy_softc)
502 };
503 
504 static devclass_t awusbphy_devclass;
505 /* aw_usbphy needs to come up after regulators/gpio/etc, but before ehci/ohci */
506 EARLY_DRIVER_MODULE(awusbphy, simplebus, awusbphy_driver, awusbphy_devclass,
507     0, 0, BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_MIDDLE);
508 MODULE_VERSION(awusbphy, 1);
509