]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/amlogic/aml8726/aml8726_usb_phy-m6.c
Merge ACPICA 20160930.
[FreeBSD/FreeBSD.git] / sys / arm / amlogic / aml8726 / aml8726_usb_phy-m6.c
1 /*-
2  * Copyright 2014-2015 John Wehle <john@feith.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 /*
28  * Amlogic aml8726-m6 (and later) USB physical layer driver.
29  *
30  * Each USB physical interface has a dedicated register block.
31  */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/conf.h>
39 #include <sys/bus.h>
40 #include <sys/kernel.h>
41 #include <sys/module.h>
42 #include <sys/lock.h>
43 #include <sys/mutex.h>
44 #include <sys/resource.h>
45 #include <sys/rman.h>
46
47 #include <sys/gpio.h>
48
49 #include <machine/bus.h>
50 #include <machine/cpu.h>
51
52 #include <dev/fdt/fdt_common.h>
53 #include <dev/ofw/ofw_bus.h>
54 #include <dev/ofw/ofw_bus_subr.h>
55
56 #include <arm/amlogic/aml8726/aml8726_soc.h>
57
58 #include "gpio_if.h"
59
60 struct aml8726_usb_phy_gpio {
61         device_t        dev;
62         uint32_t        pin;
63         uint32_t        pol;
64 };
65
66 struct aml8726_usb_phy_softc {
67         device_t                        dev;
68         struct resource                 *res[1];
69         uint32_t                        npwr_en;
70         struct aml8726_usb_phy_gpio     *pwr_en;
71         boolean_t                       force_aca;
72         struct aml8726_usb_phy_gpio     hub_rst;
73 };
74
75 static struct resource_spec aml8726_usb_phy_spec[] = {
76         { SYS_RES_MEMORY,       0,      RF_ACTIVE },
77         { -1, 0 }
78 };
79
80 #define AML_USB_PHY_CFG_REG                     0
81 #define AML_USB_PHY_CFG_CLK_SEL_32K_ALT         (1 << 15)
82 #define AML_USB_PHY_CFG_CLK_DIV_MASK            (0x7f << 4)
83 #define AML_USB_PHY_CFG_CLK_DIV_SHIFT           4
84 #define AML_USB_PHY_CFG_CLK_SEL_MASK            (7 << 1)
85 #define AML_USB_PHY_CFG_CLK_SEL_XTAL            (0 << 1)
86 #define AML_USB_PHY_CFG_CLK_SEL_XTAL_DIV2       (1 << 1)
87 #define AML_USB_PHY_CFG_CLK_EN                  (1 << 0)
88
89 #define AML_USB_PHY_CTRL_REG                    4
90 #define AML_USB_PHY_CTRL_FSEL_MASK              (7 << 22)
91 #define AML_USB_PHY_CTRL_FSEL_12M               (2 << 22)
92 #define AML_USB_PHY_CTRL_FSEL_24M               (5 << 22)
93 #define AML_USB_PHY_CTRL_POR                    (1 << 15)
94 #define AML_USB_PHY_CTRL_CLK_DETECTED           (1 << 8)
95
96 #define AML_USB_PHY_ADP_BC_REG                  12
97 #define AML_USB_PHY_ADP_BC_ACA_FLOATING         (1 << 26)
98 #define AML_USB_PHY_ADP_BC_ACA_EN               (1 << 16)
99
100 #define CSR_WRITE_4(sc, reg, val)       bus_write_4((sc)->res[0], reg, (val))
101 #define CSR_READ_4(sc, reg)             bus_read_4((sc)->res[0], reg)
102 #define CSR_BARRIER(sc, reg)            bus_barrier((sc)->res[0], reg, 4, \
103     (BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE))
104
105 #define PIN_ON_FLAG(pol)                ((pol) == 0 ?   \
106     GPIO_PIN_LOW : GPIO_PIN_HIGH)
107 #define PIN_OFF_FLAG(pol)               ((pol) == 0 ?   \
108     GPIO_PIN_HIGH : GPIO_PIN_LOW)
109
110 static int
111 aml8726_usb_phy_probe(device_t dev)
112 {
113
114         if (!ofw_bus_status_okay(dev))
115                 return (ENXIO);
116
117         if (!ofw_bus_is_compatible(dev, "amlogic,aml8726-m6-usb-phy") &&
118             !ofw_bus_is_compatible(dev, "amlogic,aml8726-m8-usb-phy"))
119                 return (ENXIO);
120
121         switch (aml8726_soc_hw_rev) {
122         case AML_SOC_HW_REV_M8:
123         case AML_SOC_HW_REV_M8B:
124                 device_set_desc(dev, "Amlogic aml8726-m8 USB PHY");
125                 break;
126         default:
127                 device_set_desc(dev, "Amlogic aml8726-m6 USB PHY");
128                 break;
129         }
130
131         return (BUS_PROBE_DEFAULT);
132 }
133
134 static int
135 aml8726_usb_phy_attach(device_t dev)
136 {
137         struct aml8726_usb_phy_softc *sc = device_get_softc(dev);
138         char *force_aca;
139         int err;
140         int npwr_en;
141         pcell_t *prop;
142         phandle_t node;
143         ssize_t len;
144         uint32_t div;
145         uint32_t i;
146         uint32_t value;
147
148         sc->dev = dev;
149
150         if (bus_alloc_resources(dev, aml8726_usb_phy_spec, sc->res)) {
151                 device_printf(dev, "can not allocate resources for device\n");
152                 return (ENXIO);
153         }
154
155         node = ofw_bus_get_node(dev);
156
157         len = OF_getprop_alloc(node, "force-aca",
158             sizeof(char), (void **)&force_aca);
159
160         sc->force_aca = FALSE;
161
162         if (len > 0) {
163                 if (strncmp(force_aca, "true", len) == 0)
164                         sc->force_aca = TRUE;
165         }
166
167         OF_prop_free(force_aca);
168
169         err = 0;
170
171         len = OF_getencprop_alloc(node, "usb-pwr-en",
172             3 * sizeof(pcell_t), (void **)&prop);
173         npwr_en = (len > 0) ? len : 0;
174
175         sc->npwr_en = 0;
176         sc->pwr_en = (struct aml8726_usb_phy_gpio *)
177             malloc(npwr_en * sizeof (*sc->pwr_en), M_DEVBUF, M_WAITOK);
178
179         for (i = 0; i < npwr_en; i++) {
180                 sc->pwr_en[i].dev = OF_device_from_xref(prop[i * 3]);
181                 sc->pwr_en[i].pin = prop[i * 3 + 1];
182                 sc->pwr_en[i].pol = prop[i * 3 + 2];
183
184                 if (sc->pwr_en[i].dev == NULL) {
185                         err = 1;
186                         break;
187                 }
188         }
189
190         OF_prop_free(prop);
191
192         len = OF_getencprop_alloc(node, "usb-hub-rst",
193             3 * sizeof(pcell_t), (void **)&prop);
194         if (len > 0) {
195                 sc->hub_rst.dev = OF_device_from_xref(prop[0]);
196                 sc->hub_rst.pin = prop[1];
197                 sc->hub_rst.pol = prop[2];
198
199                 if (len > 1 || sc->hub_rst.dev == NULL)
200                         err = 1;
201         }
202
203         OF_prop_free(prop);
204
205         if (err) {
206                 device_printf(dev, "unable to parse gpio\n");
207                 goto fail;
208         }
209
210         /* Turn on power by setting pin and then enabling output driver. */
211         for (i = 0; i < npwr_en; i++) {
212                 if (GPIO_PIN_SET(sc->pwr_en[i].dev, sc->pwr_en[i].pin,
213                     PIN_ON_FLAG(sc->pwr_en[i].pol)) != 0 ||
214                     GPIO_PIN_SETFLAGS(sc->pwr_en[i].dev, sc->pwr_en[i].pin,
215                     GPIO_PIN_OUTPUT) != 0) {
216                         device_printf(dev,
217                             "could not use gpio to control power\n");
218                         goto fail;
219                 }
220
221                 sc->npwr_en++;
222         }
223
224         /*
225          * Configure the clock source and divider.
226          */
227
228         value = CSR_READ_4(sc, AML_USB_PHY_CFG_REG);
229
230         value &= ~(AML_USB_PHY_CFG_CLK_SEL_32K_ALT |
231             AML_USB_PHY_CFG_CLK_DIV_MASK |
232             AML_USB_PHY_CFG_CLK_SEL_MASK |
233             AML_USB_PHY_CFG_CLK_EN);
234
235         switch (aml8726_soc_hw_rev) {
236         case AML_SOC_HW_REV_M8:
237         case AML_SOC_HW_REV_M8B:
238                 value |= AML_USB_PHY_CFG_CLK_SEL_32K_ALT;
239                 break;
240         default:
241                 div = 2;
242                 value |= AML_USB_PHY_CFG_CLK_SEL_XTAL;
243                 value |= ((div - 1) << AML_USB_PHY_CFG_CLK_DIV_SHIFT) &
244                     AML_USB_PHY_CFG_CLK_DIV_MASK;
245                 value |= AML_USB_PHY_CFG_CLK_EN;
246                 break;
247         }
248
249         CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value);
250
251         CSR_BARRIER(sc, AML_USB_PHY_CFG_REG);
252
253         /*
254          * Configure the clock frequency and issue a power on reset.
255          */
256
257         value = CSR_READ_4(sc, AML_USB_PHY_CTRL_REG);
258
259         value &= ~AML_USB_PHY_CTRL_FSEL_MASK;
260
261         switch (aml8726_soc_hw_rev) {
262         case AML_SOC_HW_REV_M8:
263         case AML_SOC_HW_REV_M8B:
264                 value |= AML_USB_PHY_CTRL_FSEL_24M;
265                 break;
266         default:
267                 value |= AML_USB_PHY_CTRL_FSEL_12M;
268                 break;
269         }
270
271         value |= AML_USB_PHY_CTRL_POR;
272
273         CSR_WRITE_4(sc, AML_USB_PHY_CTRL_REG, value);
274
275         CSR_BARRIER(sc, AML_USB_PHY_CTRL_REG);
276
277         DELAY(500);
278
279         /*
280          * Enable by clearing the power on reset.
281          */
282
283         value &= ~AML_USB_PHY_CTRL_POR;
284
285         CSR_WRITE_4(sc, AML_USB_PHY_CTRL_REG, value);
286
287         CSR_BARRIER(sc, AML_USB_PHY_CTRL_REG);
288
289         DELAY(1000);
290
291         /*
292          * Check if the clock was detected.
293          */
294         value = CSR_READ_4(sc, AML_USB_PHY_CTRL_REG);
295         if ((value & AML_USB_PHY_CTRL_CLK_DETECTED) == 0)
296                 device_printf(dev, "PHY Clock not detected\n");
297
298         /*
299          * If necessary enabled Accessory Charger Adaptor detection
300          * so that the port knows what mode to operate in.
301          */
302         if (sc->force_aca) {
303                 value = CSR_READ_4(sc, AML_USB_PHY_ADP_BC_REG);
304
305                 value |= AML_USB_PHY_ADP_BC_ACA_EN;
306
307                 CSR_WRITE_4(sc, AML_USB_PHY_ADP_BC_REG, value);
308
309                 CSR_BARRIER(sc, AML_USB_PHY_ADP_BC_REG);
310
311                 DELAY(50);
312
313                 value = CSR_READ_4(sc, AML_USB_PHY_ADP_BC_REG);
314
315                 if ((value & AML_USB_PHY_ADP_BC_ACA_FLOATING) != 0) {
316                         device_printf(dev,
317                             "force-aca requires newer silicon\n");
318                         goto fail;
319                 }
320         }
321
322         /*
323          * Reset the hub.
324          */
325         if (sc->hub_rst.dev != NULL) {
326                 err = 0;
327
328                 if (GPIO_PIN_SET(sc->hub_rst.dev, sc->hub_rst.pin,
329                     PIN_ON_FLAG(sc->hub_rst.pol)) != 0 ||
330                     GPIO_PIN_SETFLAGS(sc->hub_rst.dev, sc->hub_rst.pin,
331                     GPIO_PIN_OUTPUT) != 0)
332                         err = 1;
333
334                 DELAY(30);
335
336                 if (GPIO_PIN_SET(sc->hub_rst.dev, sc->hub_rst.pin,
337                     PIN_OFF_FLAG(sc->hub_rst.pol)) != 0)
338                         err = 1;
339
340                 DELAY(60000);
341
342                 if (err) {
343                         device_printf(dev,
344                             "could not use gpio to reset hub\n");
345                         goto fail;
346                 }
347         }
348
349         return (0);
350
351 fail:
352         /* In the event of problems attempt to turn things back off. */
353         i = sc->npwr_en;
354         while (i-- != 0) {
355                 GPIO_PIN_SET(sc->pwr_en[i].dev, sc->pwr_en[i].pin,
356                     PIN_OFF_FLAG(sc->pwr_en[i].pol));
357         }
358
359         free (sc->pwr_en, M_DEVBUF);
360         sc->pwr_en = NULL;
361
362         bus_release_resources(dev, aml8726_usb_phy_spec, sc->res);
363
364         return (ENXIO);
365 }
366
367 static int
368 aml8726_usb_phy_detach(device_t dev)
369 {
370         struct aml8726_usb_phy_softc *sc = device_get_softc(dev);
371         uint32_t i;
372         uint32_t value;
373
374         /*
375          * Disable by issuing a power on reset.
376          */
377
378         value = CSR_READ_4(sc, AML_USB_PHY_CTRL_REG);
379
380         value |= AML_USB_PHY_CTRL_POR;
381
382         CSR_WRITE_4(sc, AML_USB_PHY_CTRL_REG, value);
383
384         CSR_BARRIER(sc, AML_USB_PHY_CTRL_REG);
385
386         /* Turn off power */
387         i = sc->npwr_en;
388         while (i-- != 0) {
389                 GPIO_PIN_SET(sc->pwr_en[i].dev, sc->pwr_en[i].pin,
390                     PIN_OFF_FLAG(sc->pwr_en[i].pol));
391         }
392         free (sc->pwr_en, M_DEVBUF);
393         sc->pwr_en = NULL;
394
395         bus_release_resources(dev, aml8726_usb_phy_spec, sc->res);
396
397         return (0);
398 }
399
400 static device_method_t aml8726_usb_phy_methods[] = {
401         /* Device interface */
402         DEVMETHOD(device_probe,         aml8726_usb_phy_probe),
403         DEVMETHOD(device_attach,        aml8726_usb_phy_attach),
404         DEVMETHOD(device_detach,        aml8726_usb_phy_detach),
405
406         DEVMETHOD_END
407 };
408
409 static driver_t aml8726_usb_phy_driver = {
410         "usbphy",
411         aml8726_usb_phy_methods,
412         sizeof(struct aml8726_usb_phy_softc),
413 };
414
415 static devclass_t aml8726_usb_phy_devclass;
416
417 DRIVER_MODULE(aml8726_m6usbphy, simplebus, aml8726_usb_phy_driver,
418     aml8726_usb_phy_devclass, 0, 0);
419 MODULE_DEPEND(aml8726_m6usbphy, aml8726_gpio, 1, 1, 1);