2 * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
28 * DWC3 USB 3.0 DRD (dual role device) PHY
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <sys/param.h>
35 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/module.h>
39 #include <sys/malloc.h>
41 #include <sys/timeet.h>
42 #include <sys/timetc.h>
43 #include <sys/watchdog.h>
46 #include <dev/ofw/openfirm.h>
47 #include <dev/ofw/ofw_bus.h>
48 #include <dev/ofw/ofw_bus_subr.h>
50 #include <machine/bus.h>
51 #include <machine/cpu.h>
52 #include <machine/intr.h>
54 #include <arm/samsung/exynos/exynos5_common.h>
55 #include <arm/samsung/exynos/exynos5_pmu.h>
59 #define USB_DRD_LINKSYSTEM 0x04
60 #define LINKSYSTEM_FLADJ_MASK (0x3f << 1)
61 #define LINKSYSTEM_FLADJ(x) ((x) << 1)
62 #define LINKSYSTEM_XHCI_VERSION_CTRL (1 << 27)
63 #define USB_DRD_PHYUTMI 0x08
64 #define PHYUTMI_OTGDISABLE (1 << 6)
65 #define PHYUTMI_FORCESUSPEND (1 << 1)
66 #define PHYUTMI_FORCESLEEP (1 << 0)
67 #define USB_DRD_PHYPIPE 0x0c
68 #define USB_DRD_PHYCLKRST 0x10
69 #define PHYCLKRST_PORTRESET (1 << 1)
70 #define PHYCLKRST_COMMONONN (1 << 0)
71 #define PHYCLKRST_EN_UTMISUSPEND (1 << 31)
72 #define PHYCLKRST_SSC_REFCLKSEL_MASK (0xff << 23)
73 #define PHYCLKRST_SSC_REFCLKSEL(x) ((x) << 23)
74 #define PHYCLKRST_SSC_RANGE_MASK (0x03 << 21)
75 #define PHYCLKRST_SSC_RANGE(x) ((x) << 21)
76 #define PHYCLKRST_SSC_EN (1 << 20)
77 #define PHYCLKRST_REF_SSP_EN (1 << 19)
78 #define PHYCLKRST_REF_CLKDIV2 (1 << 18)
79 #define PHYCLKRST_MPLL_MLTPR_MASK (0x7f << 11)
80 #define PHYCLKRST_MPLL_MLTPR_100MHZ (0x19 << 11)
81 #define PHYCLKRST_MPLL_MLTPR_50M (0x32 << 11)
82 #define PHYCLKRST_MPLL_MLTPR_24MHZ (0x68 << 11)
83 #define PHYCLKRST_MPLL_MLTPR_20MHZ (0x7d << 11)
84 #define PHYCLKRST_MPLL_MLTPR_19200KHZ (0x02 << 11)
85 #define PHYCLKRST_FSEL_UTMI_MASK (0x7 << 5)
86 #define PHYCLKRST_FSEL_PIPE_MASK (0x7 << 8)
87 #define PHYCLKRST_FSEL(x) ((x) << 5)
88 #define PHYCLKRST_FSEL_9MHZ6 0x0
89 #define PHYCLKRST_FSEL_10MHZ 0x1
90 #define PHYCLKRST_FSEL_12MHZ 0x2
91 #define PHYCLKRST_FSEL_19MHZ2 0x3
92 #define PHYCLKRST_FSEL_20MHZ 0x4
93 #define PHYCLKRST_FSEL_24MHZ 0x5
94 #define PHYCLKRST_FSEL_50MHZ 0x7
95 #define PHYCLKRST_RETENABLEN (1 << 4)
96 #define PHYCLKRST_REFCLKSEL_MASK (0x03 << 2)
97 #define PHYCLKRST_REFCLKSEL_PAD_REFCLK (0x2 << 2)
98 #define PHYCLKRST_REFCLKSEL_EXT_REFCLK (0x3 << 2)
99 #define USB_DRD_PHYREG0 0x14
100 #define USB_DRD_PHYREG1 0x18
101 #define USB_DRD_PHYPARAM0 0x1c
102 #define PHYPARAM0_REF_USE_PAD (1 << 31)
103 #define PHYPARAM0_REF_LOSLEVEL_MASK (0x1f << 26)
104 #define PHYPARAM0_REF_LOSLEVEL (0x9 << 26)
105 #define USB_DRD_PHYPARAM1 0x20
106 #define PHYPARAM1_PCS_TXDEEMPH_MASK (0x1f << 0)
107 #define PHYPARAM1_PCS_TXDEEMPH (0x1c)
108 #define USB_DRD_PHYTERM 0x24
109 #define USB_DRD_PHYTEST 0x28
110 #define PHYTEST_POWERDOWN_SSP (1 << 3)
111 #define PHYTEST_POWERDOWN_HSP (1 << 2)
112 #define USB_DRD_PHYADP 0x2c
113 #define USB_DRD_PHYUTMICLKSEL 0x30
114 #define PHYUTMICLKSEL_UTMI_CLKSEL (1 << 2)
115 #define USB_DRD_PHYRESUME 0x34
116 #define USB_DRD_LINKPORT 0x44
118 struct usb_phy_softc {
119 struct resource *res[1];
121 bus_space_handle_t bsh;
125 static struct resource_spec usb_phy_spec[] = {
126 { SYS_RES_MEMORY, 0, RF_ACTIVE },
131 usb_phy_probe(device_t dev)
134 if (!ofw_bus_status_okay(dev))
137 if (!ofw_bus_is_compatible(dev, "samsung,exynos5420-usbdrd-phy"))
140 device_set_desc(dev, "Samsung Exynos 5 USB PHY");
141 return (BUS_PROBE_DEFAULT);
145 vbus_on(struct usb_phy_softc *sc)
147 pcell_t dts_value[3];
153 if ((node = ofw_bus_get_node(sc->dev)) == -1)
157 if ((len = OF_getproplen(node, "vbus-supply")) <= 0)
159 OF_getencprop(node, "vbus-supply", dts_value, len);
162 gpio_dev = devclass_get_device(devclass_find("gpio"), 0);
163 if (gpio_dev == NULL) {
164 device_printf(sc->dev, "can't find gpio_dev\n");
168 GPIO_PIN_SETFLAGS(gpio_dev, pin, GPIO_PIN_OUTPUT);
169 GPIO_PIN_SET(gpio_dev, pin, GPIO_PIN_HIGH);
175 usb3_phy_init(struct usb_phy_softc *sc)
179 /* Reset USB 3.0 PHY */
180 WRITE4(sc, USB_DRD_PHYREG0, 0);
182 reg = READ4(sc, USB_DRD_PHYPARAM0);
184 reg &= ~(PHYPARAM0_REF_USE_PAD);
185 reg &= ~(PHYPARAM0_REF_LOSLEVEL_MASK);
186 reg |= (PHYPARAM0_REF_LOSLEVEL);
187 WRITE4(sc, USB_DRD_PHYPARAM0, reg);
188 WRITE4(sc, USB_DRD_PHYRESUME, 0);
190 reg = (LINKSYSTEM_XHCI_VERSION_CTRL |
191 LINKSYSTEM_FLADJ(0x20));
192 WRITE4(sc, USB_DRD_LINKSYSTEM, reg);
194 reg = READ4(sc, USB_DRD_PHYPARAM1);
195 reg &= ~(PHYPARAM1_PCS_TXDEEMPH_MASK);
196 reg |= (PHYPARAM1_PCS_TXDEEMPH);
197 WRITE4(sc, USB_DRD_PHYPARAM1, reg);
199 reg = READ4(sc, USB_DRD_PHYUTMICLKSEL);
200 reg |= (PHYUTMICLKSEL_UTMI_CLKSEL);
201 WRITE4(sc, USB_DRD_PHYUTMICLKSEL, reg);
203 reg = READ4(sc, USB_DRD_PHYTEST);
204 reg &= ~(PHYTEST_POWERDOWN_HSP);
205 reg &= ~(PHYTEST_POWERDOWN_SSP);
206 WRITE4(sc, USB_DRD_PHYTEST, reg);
208 WRITE4(sc, USB_DRD_PHYUTMI, PHYUTMI_OTGDISABLE);
211 reg = (PHYCLKRST_REFCLKSEL_EXT_REFCLK);
212 reg |= (PHYCLKRST_FSEL(PHYCLKRST_FSEL_24MHZ));
213 reg |= (PHYCLKRST_MPLL_MLTPR_24MHZ);
214 reg |= (PHYCLKRST_SSC_REFCLKSEL(0x88));
215 reg |= (PHYCLKRST_RETENABLEN |
216 PHYCLKRST_REF_SSP_EN | /* Super speed */
217 PHYCLKRST_SSC_EN | /* Spread spectrum */
218 PHYCLKRST_COMMONONN |
219 PHYCLKRST_PORTRESET);
221 WRITE4(sc, USB_DRD_PHYCLKRST, reg);
223 reg &= ~PHYCLKRST_PORTRESET;
224 WRITE4(sc, USB_DRD_PHYCLKRST, reg);
230 usb_phy_attach(device_t dev)
232 struct usb_phy_softc *sc;
234 sc = device_get_softc(dev);
237 if (bus_alloc_resources(dev, usb_phy_spec, sc->res)) {
238 device_printf(dev, "could not allocate resources\n");
242 /* Memory interface */
243 sc->bst = rman_get_bustag(sc->res[0]);
244 sc->bsh = rman_get_bushandle(sc->res[0]);
248 usbdrd_phy_power_on();
257 static device_method_t usb_phy_methods[] = {
258 DEVMETHOD(device_probe, usb_phy_probe),
259 DEVMETHOD(device_attach, usb_phy_attach),
263 static driver_t usb_phy_driver = {
266 sizeof(struct usb_phy_softc),
269 static devclass_t usb_phy_devclass;
271 DRIVER_MODULE(usb_phy, simplebus, usb_phy_driver, usb_phy_devclass, 0, 0);