]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/amlogic/aml8726/aml8726_usb_phy-m3.c
Update to bmake-20171028
[FreeBSD/FreeBSD.git] / sys / arm / amlogic / aml8726 / aml8726_usb_phy-m3.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-m3 USB physical layer driver.
29  *
30  * Both USB physical interfaces share the same configuration register.
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 "gpio_if.h"
57
58 struct aml8726_usb_phy_gpio {
59         device_t        dev;
60         uint32_t        pin;
61         uint32_t        pol;
62 };
63
64 struct aml8726_usb_phy_softc {
65         device_t                        dev;
66         struct resource                 *res[1];
67         uint32_t                        npwr_en;
68         struct aml8726_usb_phy_gpio     *pwr_en;
69 };
70
71 static struct resource_spec aml8726_usb_phy_spec[] = {
72         { SYS_RES_MEMORY,       0,      RF_ACTIVE },
73         { -1, 0 }
74 };
75
76 #define AML_USB_PHY_CFG_REG                     0
77 #define AML_USB_PHY_CFG_A_CLK_DETECTED          (1U << 31)
78 #define AML_USB_PHY_CFG_CLK_DIV_MASK            (0x7f << 24)
79 #define AML_USB_PHY_CFG_CLK_DIV_SHIFT           24
80 #define AML_USB_PHY_CFG_B_CLK_DETECTED          (1 << 22)
81 #define AML_USB_PHY_CFG_A_PLL_RST               (1 << 19)
82 #define AML_USB_PHY_CFG_A_PHYS_RST              (1 << 18)
83 #define AML_USB_PHY_CFG_A_RST                   (1 << 17)
84 #define AML_USB_PHY_CFG_B_PLL_RST               (1 << 13)
85 #define AML_USB_PHY_CFG_B_PHYS_RST              (1 << 12)
86 #define AML_USB_PHY_CFG_B_RST                   (1 << 11)
87 #define AML_USB_PHY_CFG_CLK_EN                  (1 << 8)
88 #define AML_USB_PHY_CFG_CLK_SEL_MASK            (7 << 5)
89 #define AML_USB_PHY_CFG_CLK_SEL_XTAL            (0 << 5)
90 #define AML_USB_PHY_CFG_CLK_SEL_XTAL_DIV2       (1 << 5)
91 #define AML_USB_PHY_CFG_B_POR                   (1 << 1)
92 #define AML_USB_PHY_CFG_A_POR                   (1 << 0)
93
94 #define AML_USB_PHY_CFG_CLK_DETECTED \
95     (AML_USB_PHY_CFG_A_CLK_DETECTED | AML_USB_PHY_CFG_B_CLK_DETECTED)
96
97 #define AML_USB_PHY_MISC_A_REG                  12
98 #define AML_USB_PHY_MISC_B_REG                  16
99 #define AML_USB_PHY_MISC_ID_OVERIDE_EN          (1 << 23)
100 #define AML_USB_PHY_MISC_ID_OVERIDE_DEVICE      (1 << 22)
101 #define AML_USB_PHY_MISC_ID_OVERIDE_HOST        (0 << 22)
102
103 #define CSR_WRITE_4(sc, reg, val)       bus_write_4((sc)->res[0], reg, (val))
104 #define CSR_READ_4(sc, reg)             bus_read_4((sc)->res[0], reg)
105 #define CSR_BARRIER(sc, reg)            bus_barrier((sc)->res[0], reg, 4, \
106     (BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE))
107
108 #define PIN_ON_FLAG(pol)                ((pol) == 0 ?   \
109     GPIO_PIN_LOW : GPIO_PIN_HIGH)
110 #define PIN_OFF_FLAG(pol)               ((pol) == 0 ?   \
111     GPIO_PIN_HIGH : GPIO_PIN_LOW)
112
113 static int
114 aml8726_usb_phy_mode(const char *dwcotg_path, uint32_t *mode)
115 {
116         char *usb_mode;
117         phandle_t node;
118         ssize_t len;
119         
120         if ((node = OF_finddevice(dwcotg_path)) == 0)
121                 return (ENXIO);
122
123         if (fdt_is_compatible_strict(node, "synopsys,designware-hs-otg2") == 0)
124                 return (ENXIO);
125
126         *mode = 0;
127
128         len = OF_getprop_alloc(node, "dr_mode",
129             sizeof(char), (void **)&usb_mode);
130
131         if (len <= 0)
132                 return (0);
133
134         if (strcasecmp(usb_mode, "host") == 0) {
135                 *mode = AML_USB_PHY_MISC_ID_OVERIDE_EN |
136                     AML_USB_PHY_MISC_ID_OVERIDE_HOST;
137         } else if (strcasecmp(usb_mode, "peripheral") == 0) {
138                 *mode = AML_USB_PHY_MISC_ID_OVERIDE_EN |
139                     AML_USB_PHY_MISC_ID_OVERIDE_DEVICE;
140         }
141
142         OF_prop_free(usb_mode);
143
144         return (0);
145 }
146
147 static int
148 aml8726_usb_phy_probe(device_t dev)
149 {
150
151         if (!ofw_bus_status_okay(dev))
152                 return (ENXIO);
153
154         if (!ofw_bus_is_compatible(dev, "amlogic,aml8726-m3-usb-phy"))
155                 return (ENXIO);
156
157         device_set_desc(dev, "Amlogic aml8726-m3 USB PHY");
158
159         return (BUS_PROBE_DEFAULT);
160 }
161
162 static int
163 aml8726_usb_phy_attach(device_t dev)
164 {
165         struct aml8726_usb_phy_softc *sc = device_get_softc(dev);
166         int err;
167         int npwr_en;
168         pcell_t *prop;
169         phandle_t node;
170         ssize_t len;
171         uint32_t div;
172         uint32_t i;
173         uint32_t mode_a;
174         uint32_t mode_b;
175         uint32_t value;
176
177         sc->dev = dev;
178
179         if (aml8726_usb_phy_mode("/soc/usb@c9040000", &mode_a) != 0) {
180                 device_printf(dev, "missing usb@c9040000 node in FDT\n");
181                 return (ENXIO);
182         }
183
184         if (aml8726_usb_phy_mode("/soc/usb@c90c0000", &mode_b) != 0) {
185                 device_printf(dev, "missing usb@c90c0000 node in FDT\n");
186                 return (ENXIO);
187         }
188
189         if (bus_alloc_resources(dev, aml8726_usb_phy_spec, sc->res)) {
190                 device_printf(dev, "can not allocate resources for device\n");
191                 return (ENXIO);
192         }
193
194         node = ofw_bus_get_node(dev);
195
196         err = 0;
197
198         len = OF_getencprop_alloc(node, "usb-pwr-en",
199             3 * sizeof(pcell_t), (void **)&prop);
200         npwr_en = (len > 0) ? len : 0;
201
202         sc->npwr_en = 0;
203         sc->pwr_en = (struct aml8726_usb_phy_gpio *)
204             malloc(npwr_en * sizeof (*sc->pwr_en), M_DEVBUF, M_WAITOK);
205
206         for (i = 0; i < npwr_en; i++) {
207                 sc->pwr_en[i].dev = OF_device_from_xref(prop[i * 3]);
208                 sc->pwr_en[i].pin = prop[i * 3 + 1];
209                 sc->pwr_en[i].pol = prop[i * 3 + 2];
210
211                 if (sc->pwr_en[i].dev == NULL) {
212                         err = 1;
213                         break;
214                 }
215         }
216
217         OF_prop_free(prop);
218
219         if (err) {
220                 device_printf(dev, "unable to parse gpio\n");
221                 goto fail;
222         }
223
224         /* Turn on power by setting pin and then enabling output driver. */
225         for (i = 0; i < npwr_en; i++) {
226                 if (GPIO_PIN_SET(sc->pwr_en[i].dev, sc->pwr_en[i].pin,
227                     PIN_ON_FLAG(sc->pwr_en[i].pol)) != 0 ||
228                     GPIO_PIN_SETFLAGS(sc->pwr_en[i].dev, sc->pwr_en[i].pin,
229                     GPIO_PIN_OUTPUT) != 0) {
230                         device_printf(dev,
231                             "could not use gpio to control power\n");
232                         goto fail;
233                 }
234
235                 sc->npwr_en++;
236         }
237
238         /*
239          * Configure the clock source and divider.
240          */
241
242         div = 2;
243
244         value = CSR_READ_4(sc, AML_USB_PHY_CFG_REG);
245
246         value &= ~(AML_USB_PHY_CFG_CLK_DIV_MASK | AML_USB_PHY_CFG_CLK_SEL_MASK);
247
248         value &= ~(AML_USB_PHY_CFG_A_RST | AML_USB_PHY_CFG_B_RST);
249         value &= ~(AML_USB_PHY_CFG_A_PLL_RST | AML_USB_PHY_CFG_B_PLL_RST);
250         value &= ~(AML_USB_PHY_CFG_A_PHYS_RST | AML_USB_PHY_CFG_B_PHYS_RST);
251         value &= ~(AML_USB_PHY_CFG_A_POR | AML_USB_PHY_CFG_B_POR);
252
253         value |= AML_USB_PHY_CFG_CLK_SEL_XTAL;
254         value |= ((div - 1) << AML_USB_PHY_CFG_CLK_DIV_SHIFT) &
255             AML_USB_PHY_CFG_CLK_DIV_MASK;
256         value |= AML_USB_PHY_CFG_CLK_EN;
257
258         CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value);
259         CSR_BARRIER(sc, AML_USB_PHY_CFG_REG);
260
261         /*
262          * Issue the reset sequence.
263          */
264
265         value |= (AML_USB_PHY_CFG_A_RST | AML_USB_PHY_CFG_B_RST);
266
267         CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value);
268         CSR_BARRIER(sc, AML_USB_PHY_CFG_REG);
269
270         DELAY(200);
271
272         value &= ~(AML_USB_PHY_CFG_A_RST | AML_USB_PHY_CFG_B_RST);
273
274         CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value);
275         CSR_BARRIER(sc, AML_USB_PHY_CFG_REG);
276
277         DELAY(200);
278
279         value |= (AML_USB_PHY_CFG_A_PLL_RST | AML_USB_PHY_CFG_B_PLL_RST);
280
281         CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value);
282         CSR_BARRIER(sc, AML_USB_PHY_CFG_REG);
283
284         DELAY(200);
285
286         value &= ~(AML_USB_PHY_CFG_A_PLL_RST | AML_USB_PHY_CFG_B_PLL_RST);
287
288         CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value);
289         CSR_BARRIER(sc, AML_USB_PHY_CFG_REG);
290
291         DELAY(200);
292
293         value |= (AML_USB_PHY_CFG_A_PHYS_RST | AML_USB_PHY_CFG_B_PHYS_RST);
294
295         CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value);
296         CSR_BARRIER(sc, AML_USB_PHY_CFG_REG);
297
298         DELAY(200);
299
300         value &= ~(AML_USB_PHY_CFG_A_PHYS_RST | AML_USB_PHY_CFG_B_PHYS_RST);
301
302         CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value);
303         CSR_BARRIER(sc, AML_USB_PHY_CFG_REG);
304
305         DELAY(200);
306
307         value |= (AML_USB_PHY_CFG_A_POR | AML_USB_PHY_CFG_B_POR);
308
309         CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value);
310         CSR_BARRIER(sc, AML_USB_PHY_CFG_REG);
311
312         DELAY(200);
313
314         /*
315          * Enable by clearing the power on reset.
316          */
317
318         value &= ~(AML_USB_PHY_CFG_A_POR | AML_USB_PHY_CFG_B_POR);
319
320         CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value);
321
322         CSR_BARRIER(sc, AML_USB_PHY_CFG_REG);
323
324         DELAY(200);
325
326         /*
327          * Check if the clock was detected.
328          */
329         value = CSR_READ_4(sc, AML_USB_PHY_CFG_REG);
330         if ((value & AML_USB_PHY_CFG_CLK_DETECTED) !=
331             AML_USB_PHY_CFG_CLK_DETECTED)
332                 device_printf(dev, "PHY Clock not detected\n");
333
334         /*
335          * Configure the mode for each port.
336          */
337
338         value = CSR_READ_4(sc, AML_USB_PHY_MISC_A_REG);
339
340         value &= ~(AML_USB_PHY_MISC_ID_OVERIDE_EN |
341             AML_USB_PHY_MISC_ID_OVERIDE_DEVICE |
342             AML_USB_PHY_MISC_ID_OVERIDE_HOST);
343         value |= mode_a;
344
345         CSR_WRITE_4(sc, AML_USB_PHY_MISC_A_REG, value);
346
347         value = CSR_READ_4(sc, AML_USB_PHY_MISC_B_REG);
348
349         value &= ~(AML_USB_PHY_MISC_ID_OVERIDE_EN |
350             AML_USB_PHY_MISC_ID_OVERIDE_DEVICE |
351             AML_USB_PHY_MISC_ID_OVERIDE_HOST);
352         value |= mode_b;
353
354         CSR_WRITE_4(sc, AML_USB_PHY_MISC_B_REG, value);
355
356         CSR_BARRIER(sc, AML_USB_PHY_MISC_B_REG);
357
358         return (0);
359
360 fail:
361         /* In the event of problems attempt to turn things back off. */
362         i = sc->npwr_en;
363         while (i-- != 0) {
364                 GPIO_PIN_SET(sc->pwr_en[i].dev, sc->pwr_en[i].pin,
365                     PIN_OFF_FLAG(sc->pwr_en[i].pol));
366         }
367
368         free (sc->pwr_en, M_DEVBUF);
369         sc->pwr_en = NULL;
370
371         bus_release_resources(dev, aml8726_usb_phy_spec, sc->res);
372
373         return (ENXIO);
374 }
375
376 static int
377 aml8726_usb_phy_detach(device_t dev)
378 {
379         struct aml8726_usb_phy_softc *sc = device_get_softc(dev);
380         uint32_t i;
381         uint32_t value;
382
383         /*
384          * Disable by issuing a power on reset.
385          */
386
387         value = CSR_READ_4(sc, AML_USB_PHY_CFG_REG);
388
389         value |= (AML_USB_PHY_CFG_A_POR | AML_USB_PHY_CFG_B_POR);
390
391         CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value);
392
393         CSR_BARRIER(sc, AML_USB_PHY_CFG_REG);
394
395         /* Turn off power */
396         i = sc->npwr_en;
397         while (i-- != 0) {
398                 (void)GPIO_PIN_SET(sc->pwr_en[i].dev, sc->pwr_en[i].pin,
399                     PIN_OFF_FLAG(sc->pwr_en[i].pol));
400         }
401         free (sc->pwr_en, M_DEVBUF);
402         sc->pwr_en = NULL;
403
404         bus_release_resources(dev, aml8726_usb_phy_spec, sc->res);
405
406         return (0);
407 }
408
409 static device_method_t aml8726_usb_phy_methods[] = {
410         /* Device interface */
411         DEVMETHOD(device_probe,         aml8726_usb_phy_probe),
412         DEVMETHOD(device_attach,        aml8726_usb_phy_attach),
413         DEVMETHOD(device_detach,        aml8726_usb_phy_detach),
414
415         DEVMETHOD_END
416 };
417
418 static driver_t aml8726_usb_phy_driver = {
419         "usbphy",
420         aml8726_usb_phy_methods,
421         sizeof(struct aml8726_usb_phy_softc),
422 };
423
424 static devclass_t aml8726_usb_phy_devclass;
425
426 DRIVER_MODULE(aml8726_m3usbphy, simplebus, aml8726_usb_phy_driver,
427     aml8726_usb_phy_devclass, 0, 0);
428 MODULE_DEPEND(aml8726_m3usbphy, aml8726_gpio, 1, 1, 1);