| @@ -1,391 +1,390 @@ | | | @@ -1,391 +1,390 @@ |
1 | /* $NetBSD: octeon_xhci.c,v 1.1 2020/07/16 21:34:52 jmcneill Exp $ */ | | 1 | /* $NetBSD: octeon_xhci.c,v 1.2 2020/07/17 08:06:02 simonb Exp $ */ |
2 | /* $OpenBSD: octxhci.c,v 1.4 2019/09/29 04:32:23 visa Exp $ */ | | 2 | /* $OpenBSD: octxhci.c,v 1.4 2019/09/29 04:32:23 visa Exp $ */ |
3 | | | 3 | |
4 | /* | | 4 | /* |
5 | * Copyright (c) 2017 Visa Hankala | | 5 | * Copyright (c) 2017 Visa Hankala |
6 | * Copyright (c) 2020 Jared McNeill <jmcneill@invisible.ca> | | 6 | * Copyright (c) 2020 Jared McNeill <jmcneill@invisible.ca> |
7 | * | | 7 | * |
8 | * Permission to use, copy, modify, and distribute this software for any | | 8 | * Permission to use, copy, modify, and distribute this software for any |
9 | * purpose with or without fee is hereby granted, provided that the above | | 9 | * purpose with or without fee is hereby granted, provided that the above |
10 | * copyright notice and this permission notice appear in all copies. | | 10 | * copyright notice and this permission notice appear in all copies. |
11 | * | | 11 | * |
12 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | | 12 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
13 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | | 13 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
14 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | | 14 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
15 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | | 15 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
16 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | | 16 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
17 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | | 17 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
18 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | | 18 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
19 | */ | | 19 | */ |
20 | | | 20 | |
21 | /* | | 21 | /* |
22 | * Driver for OCTEON USB3 controller bridge. | | 22 | * Driver for OCTEON USB3 controller bridge. |
23 | */ | | 23 | */ |
24 | | | 24 | |
25 | #include <sys/param.h> | | 25 | #include <sys/param.h> |
26 | #include <sys/systm.h> | | 26 | #include <sys/systm.h> |
27 | #include <sys/device.h> | | 27 | #include <sys/device.h> |
28 | #include <sys/malloc.h> | | 28 | #include <sys/malloc.h> |
29 | | | 29 | |
30 | #include <mips/cavium/octeonvar.h> | | 30 | #include <mips/cavium/octeonvar.h> |
31 | | | 31 | |
32 | #include <mips/cavium/dev/octeon_xhcireg.h> | | 32 | #include <mips/cavium/dev/octeon_xhcireg.h> |
33 | | | 33 | |
34 | #include <dev/usb/usb.h> | | 34 | #include <dev/usb/usb.h> |
35 | #include <dev/usb/usbdi.h> | | 35 | #include <dev/usb/usbdi.h> |
36 | #include <dev/usb/usbdivar.h> | | 36 | #include <dev/usb/usbdivar.h> |
37 | #include <dev/usb/usb_mem.h> | | 37 | #include <dev/usb/usb_mem.h> |
38 | #include <dev/usb/xhcireg.h> | | 38 | #include <dev/usb/xhcireg.h> |
39 | #include <dev/usb/xhcivar.h> | | 39 | #include <dev/usb/xhcivar.h> |
40 | | | 40 | |
41 | #include <dev/fdt/fdtvar.h> | | 41 | #include <dev/fdt/fdtvar.h> |
42 | | | 42 | |
43 | #define XCTL_RD_8(sc, reg) \ | | 43 | #define XCTL_RD_8(sc, reg) \ |
44 | bus_space_read_8((sc)->sc_iot, (sc)->sc_ioh, (reg)) | | 44 | bus_space_read_8((sc)->sc_iot, (sc)->sc_ioh, (reg)) |
45 | #define XCTL_WR_8(sc, reg, val) \ | | 45 | #define XCTL_WR_8(sc, reg, val) \ |
46 | bus_space_write_8((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) | | 46 | bus_space_write_8((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) |
47 | | | 47 | |
48 | struct octxhci_softc { | | 48 | struct octxhci_softc { |
49 | struct xhci_softc sc_xhci; | | 49 | struct xhci_softc sc_xhci; |
50 | bus_space_tag_t sc_iot; | | 50 | bus_space_tag_t sc_iot; |
51 | bus_space_handle_t sc_ioh; | | 51 | bus_space_handle_t sc_ioh; |
52 | struct fdtbus_gpio_pin *sc_power_gpio; | | 52 | struct fdtbus_gpio_pin *sc_power_gpio; |
53 | int sc_unit; | | 53 | int sc_unit; |
54 | }; | | 54 | }; |
55 | | | 55 | |
56 | static int octxhci_match(device_t, cfdata_t, void *); | | 56 | static int octxhci_match(device_t, cfdata_t, void *); |
57 | static void octxhci_attach(device_t, device_t, void *); | | 57 | static void octxhci_attach(device_t, device_t, void *); |
58 | | | 58 | |
59 | static int octxhci_dwc3_init(struct xhci_softc *); | | 59 | static int octxhci_dwc3_init(struct xhci_softc *); |
60 | static void octxhci_uctl_init(struct octxhci_softc *, uint64_t, uint64_t); | | 60 | static void octxhci_uctl_init(struct octxhci_softc *, uint64_t, uint64_t); |
61 | | | 61 | |
62 | static void octxhci_bus_io_init(bus_space_tag_t, void *); | | 62 | static void octxhci_bus_io_init(bus_space_tag_t, void *); |
63 | | | 63 | |
64 | static struct mips_bus_space octxhci_bus_tag; | | 64 | static struct mips_bus_space octxhci_bus_tag; |
65 | | | 65 | |
66 | CFATTACH_DECL_NEW(octxhci, sizeof(struct octxhci_softc), | | 66 | CFATTACH_DECL_NEW(octxhci, sizeof(struct octxhci_softc), |
67 | octxhci_match, octxhci_attach, NULL, NULL); | | 67 | octxhci_match, octxhci_attach, NULL, NULL); |
68 | | | 68 | |
69 | static const char * compatible[] = { | | 69 | static const char * compatible[] = { |
70 | "cavium,octeon-7130-usb-uctl", | | 70 | "cavium,octeon-7130-usb-uctl", |
71 | NULL | | 71 | NULL |
72 | }; | | 72 | }; |
73 | | | 73 | |
74 | int | | 74 | int |
75 | octxhci_match(device_t parent, cfdata_t cf, void *aux) | | 75 | octxhci_match(device_t parent, cfdata_t cf, void *aux) |
76 | { | | 76 | { |
77 | struct fdt_attach_args * const faa = aux; | | 77 | struct fdt_attach_args * const faa = aux; |
78 | | | 78 | |
79 | return of_match_compatible(faa->faa_phandle, compatible); | | 79 | return of_match_compatible(faa->faa_phandle, compatible); |
80 | } | | 80 | } |
81 | | | 81 | |
82 | void | | 82 | void |
83 | octxhci_attach(device_t parent, device_t self, void *aux) | | 83 | octxhci_attach(device_t parent, device_t self, void *aux) |
84 | { | | 84 | { |
85 | struct octxhci_softc *osc = device_private(self); | | 85 | struct octxhci_softc *osc = device_private(self); |
86 | struct xhci_softc *sc = &osc->sc_xhci; | | 86 | struct xhci_softc *sc = &osc->sc_xhci; |
87 | struct fdt_attach_args * const faa = aux; | | 87 | struct fdt_attach_args * const faa = aux; |
88 | const int phandle = faa->faa_phandle; | | 88 | const int phandle = faa->faa_phandle; |
89 | const char *clock_type_hs; | | 89 | const char *clock_type_hs; |
90 | const char *clock_type_ss; | | 90 | const char *clock_type_ss; |
91 | u_int clock_freq, clock_sel; | | 91 | u_int clock_freq, clock_sel; |
92 | char intrstr[128]; | | 92 | char intrstr[128]; |
93 | int child, error; | | 93 | int child, error; |
94 | bus_addr_t addr; | | 94 | bus_addr_t addr; |
95 | bus_size_t size; | | 95 | bus_size_t size; |
96 | void *ih; | | 96 | void *ih; |
97 | | | 97 | |
98 | osc->sc_iot = faa->faa_bst; | | 98 | osc->sc_iot = faa->faa_bst; |
99 | | | 99 | |
100 | if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { | | 100 | if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { |
101 | aprint_error(": couldn't get bridge registers\n"); | | 101 | aprint_error(": couldn't get bridge registers\n"); |
102 | return; | | 102 | return; |
103 | } | | 103 | } |
104 | if (bus_space_map(osc->sc_iot, addr, size, 0, &osc->sc_ioh) != 0) { | | 104 | if (bus_space_map(osc->sc_iot, addr, size, 0, &osc->sc_ioh) != 0) { |
105 | aprint_error(": couldn't map bridge registers\n"); | | 105 | aprint_error(": couldn't map bridge registers\n"); |
106 | return; | | 106 | return; |
107 | } | | 107 | } |
108 | osc->sc_power_gpio = fdtbus_gpio_acquire(phandle, "power", | | 108 | osc->sc_power_gpio = fdtbus_gpio_acquire(phandle, "power", |
109 | GPIO_PIN_OUTPUT); | | 109 | GPIO_PIN_OUTPUT); |
110 | osc->sc_unit = (addr >> 24) & 0x1; | | 110 | osc->sc_unit = (addr >> 24) & 0x1; |
111 | | | 111 | |
112 | octxhci_bus_io_init(&octxhci_bus_tag, NULL); | | 112 | octxhci_bus_io_init(&octxhci_bus_tag, NULL); |
113 | | | 113 | |
114 | sc->sc_dev = self; | | 114 | sc->sc_dev = self; |
115 | sc->sc_bus.ub_hcpriv = sc; | | 115 | sc->sc_bus.ub_hcpriv = sc; |
116 | sc->sc_bus.ub_dmatag = faa->faa_dmat; | | 116 | sc->sc_bus.ub_dmatag = faa->faa_dmat; |
117 | sc->sc_iot = &octxhci_bus_tag; | | 117 | sc->sc_iot = &octxhci_bus_tag; |
118 | | | 118 | |
119 | child = of_find_bycompat(phandle, "synopsys,dwc3"); | | 119 | child = of_find_bycompat(phandle, "synopsys,dwc3"); |
120 | if (child == -1) { | | 120 | if (child == -1) { |
121 | aprint_error(": couldn't find dwc3 child node\n"); | | 121 | aprint_error(": couldn't find dwc3 child node\n"); |
122 | return; | | 122 | return; |
123 | } | | 123 | } |
124 | if (fdtbus_get_reg(child, 0, &addr, &size) != 0) { | | 124 | if (fdtbus_get_reg(child, 0, &addr, &size) != 0) { |
125 | aprint_error(": couldn't get xhci registers\n"); | | 125 | aprint_error(": couldn't get xhci registers\n"); |
126 | return; | | 126 | return; |
127 | } | | 127 | } |
128 | if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh) != 0) { | | 128 | if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh) != 0) { |
129 | aprint_error(": couldn't map xhci registers\n"); | | 129 | aprint_error(": couldn't map xhci registers\n"); |
130 | return; | | 130 | return; |
131 | } | | 131 | } |
132 | | | 132 | |
133 | if (of_getprop_uint32(phandle, "refclk-frequency", &clock_freq) != 0) { | | 133 | if (of_getprop_uint32(phandle, "refclk-frequency", &clock_freq) != 0) { |
134 | aprint_error(": couldn't get refclk-frequency property\n"); | | 134 | aprint_error(": couldn't get refclk-frequency property\n"); |
135 | return; | | 135 | return; |
136 | } | | 136 | } |
137 | clock_type_hs = fdtbus_get_string(phandle, "refclk-type-hs"); | | 137 | clock_type_hs = fdtbus_get_string(phandle, "refclk-type-hs"); |
138 | if (clock_type_hs == NULL) { | | 138 | if (clock_type_hs == NULL) { |
139 | aprint_error(": couldn't get refclk-type-hs property\n"); | | 139 | aprint_error(": couldn't get refclk-type-hs property\n"); |
140 | return; | | 140 | return; |
141 | } | | 141 | } |
142 | clock_type_ss = fdtbus_get_string(phandle, "refclk-type-ss"); | | 142 | clock_type_ss = fdtbus_get_string(phandle, "refclk-type-ss"); |
143 | if (clock_type_ss == NULL) { | | 143 | if (clock_type_ss == NULL) { |
144 | aprint_error(": couldn't get refclk-type-ss property\n"); | | 144 | aprint_error(": couldn't get refclk-type-ss property\n"); |
145 | return; | | 145 | return; |
146 | } | | 146 | } |
147 | | | 147 | |
148 | clock_sel = 0; | | 148 | clock_sel = 0; |
149 | if (strcmp(clock_type_ss, "dlmc_ref_clk1") == 0) | | 149 | if (strcmp(clock_type_ss, "dlmc_ref_clk1") == 0) |
150 | clock_sel |= 1; | | 150 | clock_sel |= 1; |
151 | if (strcmp(clock_type_hs, "pll_ref_clk") == 0) | | 151 | if (strcmp(clock_type_hs, "pll_ref_clk") == 0) |
152 | clock_sel |= 2; | | 152 | clock_sel |= 2; |
153 | | | 153 | |
154 | if (0) | | | |
155 | octxhci_uctl_init(osc, clock_freq, clock_sel); | | 154 | octxhci_uctl_init(osc, clock_freq, clock_sel); |
156 | | | 155 | |
157 | if (octxhci_dwc3_init(sc) != 0) { | | 156 | if (octxhci_dwc3_init(sc) != 0) { |
158 | /* Error message has been printed already. */ | | 157 | /* Error message has been printed already. */ |
159 | return; | | 158 | return; |
160 | } | | 159 | } |
161 | | | 160 | |
162 | if (!fdtbus_intr_str(child, 0, intrstr, sizeof(intrstr))) { | | 161 | if (!fdtbus_intr_str(child, 0, intrstr, sizeof(intrstr))) { |
163 | aprint_error_dev(self, "failed to decode interrupt\n"); | | 162 | aprint_error_dev(self, "failed to decode interrupt\n"); |
164 | return; | | 163 | return; |
165 | } | | 164 | } |
166 | | | 165 | |
167 | ih = fdtbus_intr_establish(child, 0, IPL_USB, FDT_INTR_MPSAFE, | | 166 | ih = fdtbus_intr_establish(child, 0, IPL_USB, FDT_INTR_MPSAFE, |
168 | xhci_intr, sc); | | 167 | xhci_intr, sc); |
169 | if (ih == NULL) { | | 168 | if (ih == NULL) { |
170 | aprint_error_dev(self, "couldn't establish interrupt on %s\n", | | 169 | aprint_error_dev(self, "couldn't establish interrupt on %s\n", |
171 | intrstr); | | 170 | intrstr); |
172 | return; | | 171 | return; |
173 | } | | 172 | } |
174 | aprint_normal_dev(self, "interrupting on %s\n", intrstr); | | 173 | aprint_normal_dev(self, "interrupting on %s\n", intrstr); |
175 | | | 174 | |
176 | sc->sc_bus.ub_revision = USBREV_3_0; | | 175 | sc->sc_bus.ub_revision = USBREV_3_0; |
177 | error = xhci_init(sc); | | 176 | error = xhci_init(sc); |
178 | if (error != 0) { | | 177 | if (error != 0) { |
179 | aprint_error_dev(self, "init failed, error = %d\n", error); | | 178 | aprint_error_dev(self, "init failed, error = %d\n", error); |
180 | return; | | 179 | return; |
181 | } | | 180 | } |
182 | | | 181 | |
183 | sc->sc_child = config_found(self, &sc->sc_bus, usbctlprint); | | 182 | sc->sc_child = config_found(self, &sc->sc_bus, usbctlprint); |
184 | sc->sc_child2 = config_found(self, &sc->sc_bus2, usbctlprint); | | 183 | sc->sc_child2 = config_found(self, &sc->sc_bus2, usbctlprint); |
185 | } | | 184 | } |
186 | | | 185 | |
187 | void | | 186 | void |
188 | octxhci_uctl_init(struct octxhci_softc *sc, uint64_t clock_freq, | | 187 | octxhci_uctl_init(struct octxhci_softc *sc, uint64_t clock_freq, |
189 | uint64_t clock_sel) | | 188 | uint64_t clock_sel) |
190 | { | | 189 | { |
191 | static const uint32_t clock_divs[] = { 1, 2, 4, 6, 8, 16, 24, 32 }; | | 190 | static const uint32_t clock_divs[] = { 1, 2, 4, 6, 8, 16, 24, 32 }; |
192 | uint64_t i, val; | | 191 | uint64_t i, val; |
193 | uint64_t ioclock = octeon_ioclock_speed(); | | 192 | uint64_t ioclock = octeon_ioclock_speed(); |
194 | uint64_t mpll_mult; | | 193 | uint64_t mpll_mult; |
195 | uint64_t refclk_fsel; | | 194 | uint64_t refclk_fsel; |
196 | #if notyet | | 195 | #if notyet |
197 | int output_sel; | | 196 | int output_sel; |
198 | #endif | | 197 | #endif |
199 | | | 198 | |
200 | /* | | 199 | /* |
201 | * Put the bridge controller, USB core, PHY, and clock divider | | 200 | * Put the bridge controller, USB core, PHY, and clock divider |
202 | * into reset. | | 201 | * into reset. |
203 | */ | | 202 | */ |
204 | val = XCTL_RD_8(sc, XCTL_CTL); | | 203 | val = XCTL_RD_8(sc, XCTL_CTL); |
205 | val |= XCTL_CTL_UCTL_RST; | | 204 | val |= XCTL_CTL_UCTL_RST; |
206 | val |= XCTL_CTL_UAHC_RST; | | 205 | val |= XCTL_CTL_UAHC_RST; |
207 | val |= XCTL_CTL_UPHY_RST; | | 206 | val |= XCTL_CTL_UPHY_RST; |
208 | XCTL_WR_8(sc, XCTL_CTL, val); | | 207 | XCTL_WR_8(sc, XCTL_CTL, val); |
209 | val = XCTL_RD_8(sc, XCTL_CTL); | | 208 | val = XCTL_RD_8(sc, XCTL_CTL); |
210 | val |= XCTL_CTL_CLKDIV_RST; | | 209 | val |= XCTL_CTL_CLKDIV_RST; |
211 | XCTL_WR_8(sc, XCTL_CTL, val); | | 210 | XCTL_WR_8(sc, XCTL_CTL, val); |
212 | | | 211 | |
213 | /* Select IO clock divisor. */ | | 212 | /* Select IO clock divisor. */ |
214 | for (i = 0; i < __arraycount(clock_divs); i++) { | | 213 | for (i = 0; i < __arraycount(clock_divs); i++) { |
215 | if (ioclock / clock_divs[i] < 300000000) | | 214 | if (ioclock / clock_divs[i] < 300000000) |
216 | break; | | 215 | break; |
217 | } | | 216 | } |
218 | | | 217 | |
219 | /* Update the divisor and enable the clock. */ | | 218 | /* Update the divisor and enable the clock. */ |
220 | val = XCTL_RD_8(sc, XCTL_CTL); | | 219 | val = XCTL_RD_8(sc, XCTL_CTL); |
221 | val &= ~XCTL_CTL_CLKDIV_SEL; | | 220 | val &= ~XCTL_CTL_CLKDIV_SEL; |
222 | val |= (i << XCTL_CTL_CLKDIV_SEL_SHIFT) & XCTL_CTL_CLKDIV_SEL; | | 221 | val |= (i << XCTL_CTL_CLKDIV_SEL_SHIFT) & XCTL_CTL_CLKDIV_SEL; |
223 | val |= XCTL_CTL_CLK_EN; | | 222 | val |= XCTL_CTL_CLK_EN; |
224 | XCTL_WR_8(sc, XCTL_CTL, val); | | 223 | XCTL_WR_8(sc, XCTL_CTL, val); |
225 | | | 224 | |
226 | /* Take the clock divider out of reset. */ | | 225 | /* Take the clock divider out of reset. */ |
227 | val = XCTL_RD_8(sc, XCTL_CTL); | | 226 | val = XCTL_RD_8(sc, XCTL_CTL); |
228 | val &= ~XCTL_CTL_CLKDIV_RST; | | 227 | val &= ~XCTL_CTL_CLKDIV_RST; |
229 | XCTL_WR_8(sc, XCTL_CTL, val); | | 228 | XCTL_WR_8(sc, XCTL_CTL, val); |
230 | | | 229 | |
231 | /* Select the reference clock. */ | | 230 | /* Select the reference clock. */ |
232 | switch (clock_freq) { | | 231 | switch (clock_freq) { |
233 | case 50000000: | | 232 | case 50000000: |
234 | refclk_fsel = 0x07; | | 233 | refclk_fsel = 0x07; |
235 | mpll_mult = 0x32; | | 234 | mpll_mult = 0x32; |
236 | break; | | 235 | break; |
237 | case 125000000: | | 236 | case 125000000: |
238 | refclk_fsel = 0x07; | | 237 | refclk_fsel = 0x07; |
239 | mpll_mult = 0x28; | | 238 | mpll_mult = 0x28; |
240 | break; | | 239 | break; |
241 | case 100000000: | | 240 | case 100000000: |
242 | default: | | 241 | default: |
243 | if (clock_sel < 2) | | 242 | if (clock_sel < 2) |
244 | refclk_fsel = 0x27; | | 243 | refclk_fsel = 0x27; |
245 | else | | 244 | else |
246 | refclk_fsel = 0x07; | | 245 | refclk_fsel = 0x07; |
247 | mpll_mult = 0x19; | | 246 | mpll_mult = 0x19; |
248 | break; | | 247 | break; |
249 | } | | 248 | } |
250 | | | 249 | |
251 | /* Set the clock and power up PHYs. */ | | 250 | /* Set the clock and power up PHYs. */ |
252 | val = XCTL_RD_8(sc, XCTL_CTL); | | 251 | val = XCTL_RD_8(sc, XCTL_CTL); |
253 | val &= ~XCTL_CTL_REFCLK_SEL; | | 252 | val &= ~XCTL_CTL_REFCLK_SEL; |
254 | val |= clock_sel << XCTL_CTL_REFCLK_SEL_SHIFT; | | 253 | val |= clock_sel << XCTL_CTL_REFCLK_SEL_SHIFT; |
255 | val &= ~XCTL_CTL_REFCLK_DIV2; | | 254 | val &= ~XCTL_CTL_REFCLK_DIV2; |
256 | val &= ~XCTL_CTL_REFCLK_FSEL; | | 255 | val &= ~XCTL_CTL_REFCLK_FSEL; |
257 | val |= refclk_fsel << XCTL_CTL_REFCLK_FSEL_SHIFT; | | 256 | val |= refclk_fsel << XCTL_CTL_REFCLK_FSEL_SHIFT; |
258 | val &= ~XCTL_CTL_MPLL_MULT; | | 257 | val &= ~XCTL_CTL_MPLL_MULT; |
259 | val |= mpll_mult << XCTL_CTL_MPLL_MULT_SHIFT; | | 258 | val |= mpll_mult << XCTL_CTL_MPLL_MULT_SHIFT; |
260 | val |= XCTL_CTL_SSC_EN; | | 259 | val |= XCTL_CTL_SSC_EN; |
261 | val |= XCTL_CTL_REFCLK_SSP_EN; | | 260 | val |= XCTL_CTL_REFCLK_SSP_EN; |
262 | val |= XCTL_CTL_SSPOWER_EN; | | 261 | val |= XCTL_CTL_SSPOWER_EN; |
263 | val |= XCTL_CTL_HSPOWER_EN; | | 262 | val |= XCTL_CTL_HSPOWER_EN; |
264 | XCTL_WR_8(sc, XCTL_CTL, val); | | 263 | XCTL_WR_8(sc, XCTL_CTL, val); |
265 | | | 264 | |
266 | delay(100); | | 265 | delay(100); |
267 | | | 266 | |
268 | /* Take the bridge out of reset. */ | | 267 | /* Take the bridge out of reset. */ |
269 | val = XCTL_RD_8(sc, XCTL_CTL); | | 268 | val = XCTL_RD_8(sc, XCTL_CTL); |
270 | val &= ~XCTL_CTL_UCTL_RST; | | 269 | val &= ~XCTL_CTL_UCTL_RST; |
271 | XCTL_WR_8(sc, XCTL_CTL, val); | | 270 | XCTL_WR_8(sc, XCTL_CTL, val); |
272 | | | 271 | |
273 | delay(100); | | 272 | delay(100); |
274 | | | 273 | |
275 | #if notyet | | 274 | #if notyet |
276 | if (sc->sc_power_gpio[0] != 0) { | | 275 | if (sc->sc_power_gpio[0] != 0) { |
277 | if (sc->sc_unit == 0) | | 276 | if (sc->sc_unit == 0) |
278 | output_sel = GPIO_CONFIG_MD_USB0_VBUS_CTRL; | | 277 | output_sel = GPIO_CONFIG_MD_USB0_VBUS_CTRL; |
279 | else | | 278 | else |
280 | output_sel = GPIO_CONFIG_MD_USB1_VBUS_CTRL; | | 279 | output_sel = GPIO_CONFIG_MD_USB1_VBUS_CTRL; |
281 | gpio_controller_config_pin(sc->sc_power_gpio, | | 280 | gpio_controller_config_pin(sc->sc_power_gpio, |
282 | GPIO_CONFIG_OUTPUT | output_sel); | | 281 | GPIO_CONFIG_OUTPUT | output_sel); |
283 | | | 282 | |
284 | /* Enable port power control. */ | | 283 | /* Enable port power control. */ |
285 | val = XCTL_RD_8(sc, XCTL_HOST_CFG); | | 284 | val = XCTL_RD_8(sc, XCTL_HOST_CFG); |
286 | val |= XCTL_HOST_CFG_PPC_EN; | | 285 | val |= XCTL_HOST_CFG_PPC_EN; |
287 | if (sc->sc_power_gpio[2] & GPIO_ACTIVE_LOW) | | 286 | if (sc->sc_power_gpio[2] & GPIO_ACTIVE_LOW) |
288 | val &= ~XCTL_HOST_CFG_PPC_ACTIVE_HIGH_EN; | | 287 | val &= ~XCTL_HOST_CFG_PPC_ACTIVE_HIGH_EN; |
289 | else | | 288 | else |
290 | val |= XCTL_HOST_CFG_PPC_ACTIVE_HIGH_EN; | | 289 | val |= XCTL_HOST_CFG_PPC_ACTIVE_HIGH_EN; |
291 | XCTL_WR_8(sc, XCTL_HOST_CFG, val); | | 290 | XCTL_WR_8(sc, XCTL_HOST_CFG, val); |
292 | } else { | | 291 | } else { |
293 | /* Disable port power control. */ | | 292 | /* Disable port power control. */ |
294 | val = XCTL_RD_8(sc, XCTL_HOST_CFG); | | 293 | val = XCTL_RD_8(sc, XCTL_HOST_CFG); |
295 | val &= ~XCTL_HOST_CFG_PPC_EN; | | 294 | val &= ~XCTL_HOST_CFG_PPC_EN; |
296 | XCTL_WR_8(sc, XCTL_HOST_CFG, val); | | 295 | XCTL_WR_8(sc, XCTL_HOST_CFG, val); |
297 | } | | 296 | } |
298 | #else | | 297 | #else |
299 | /* Disable port power control. */ | | 298 | /* Disable port power control. */ |
300 | val = XCTL_RD_8(sc, XCTL_HOST_CFG); | | 299 | val = XCTL_RD_8(sc, XCTL_HOST_CFG); |
301 | val &= ~XCTL_HOST_CFG_PPC_EN; | | 300 | val &= ~XCTL_HOST_CFG_PPC_EN; |
302 | XCTL_WR_8(sc, XCTL_HOST_CFG, val); | | 301 | XCTL_WR_8(sc, XCTL_HOST_CFG, val); |
303 | #endif | | 302 | #endif |
304 | | | 303 | |
305 | /* Enable host-only mode. */ | | 304 | /* Enable host-only mode. */ |
306 | val = XCTL_RD_8(sc, XCTL_CTL); | | 305 | val = XCTL_RD_8(sc, XCTL_CTL); |
307 | val &= ~XCTL_CTL_DRD_MODE; | | 306 | val &= ~XCTL_CTL_DRD_MODE; |
308 | XCTL_WR_8(sc, XCTL_CTL, val); | | 307 | XCTL_WR_8(sc, XCTL_CTL, val); |
309 | | | 308 | |
310 | delay(100); | | 309 | delay(100); |
311 | | | 310 | |
312 | /* Take the USB core out of reset. */ | | 311 | /* Take the USB core out of reset. */ |
313 | val = XCTL_RD_8(sc, XCTL_CTL); | | 312 | val = XCTL_RD_8(sc, XCTL_CTL); |
314 | val &= ~XCTL_CTL_UAHC_RST; | | 313 | val &= ~XCTL_CTL_UAHC_RST; |
315 | XCTL_WR_8(sc, XCTL_CTL, val); | | 314 | XCTL_WR_8(sc, XCTL_CTL, val); |
316 | | | 315 | |
317 | delay(100); | | 316 | delay(100); |
318 | | | 317 | |
319 | val = XCTL_RD_8(sc, XCTL_CTL); | | 318 | val = XCTL_RD_8(sc, XCTL_CTL); |
320 | val |= XCTL_CTL_CSCLK_EN; | | 319 | val |= XCTL_CTL_CSCLK_EN; |
321 | XCTL_WR_8(sc, XCTL_CTL, val); | | 320 | XCTL_WR_8(sc, XCTL_CTL, val); |
322 | | | 321 | |
323 | /* Take the PHY out of reset. */ | | 322 | /* Take the PHY out of reset. */ |
324 | val = XCTL_RD_8(sc, XCTL_CTL); | | 323 | val = XCTL_RD_8(sc, XCTL_CTL); |
325 | val &= ~XCTL_CTL_UPHY_RST; | | 324 | val &= ~XCTL_CTL_UPHY_RST; |
326 | XCTL_WR_8(sc, XCTL_CTL, val); | | 325 | XCTL_WR_8(sc, XCTL_CTL, val); |
327 | (void)XCTL_RD_8(sc, XCTL_CTL); | | 326 | (void)XCTL_RD_8(sc, XCTL_CTL); |
328 | | | 327 | |
329 | /* Fix endianess. */ | | 328 | /* Fix endianess. */ |
330 | val = XCTL_RD_8(sc, XCTL_SHIM_CFG); | | 329 | val = XCTL_RD_8(sc, XCTL_SHIM_CFG); |
331 | val &= ~XCTL_SHIM_CFG_CSR_BYTE_SWAP; | | 330 | val &= ~XCTL_SHIM_CFG_CSR_BYTE_SWAP; |
332 | val &= ~XCTL_SHIM_CFG_DMA_BYTE_SWAP; | | 331 | val &= ~XCTL_SHIM_CFG_DMA_BYTE_SWAP; |
333 | val |= 3ull << XCTL_SHIM_CFG_CSR_BYTE_SWAP_SHIFT; | | 332 | val |= __SHIFTIN(XCTL_SHIM_ENDIAN_BIG, XCTL_SHIM_CFG_DMA_BYTE_SWAP); |
334 | val |= 1ull << XCTL_SHIM_CFG_DMA_BYTE_SWAP_SHIFT; | | 333 | val |= __SHIFTIN(XCTL_SHIM_ENDIAN_BIG, XCTL_SHIM_CFG_CSR_BYTE_SWAP); |
335 | XCTL_WR_8(sc, XCTL_SHIM_CFG, val); | | 334 | XCTL_WR_8(sc, XCTL_SHIM_CFG, val); |
336 | (void)XCTL_RD_8(sc, XCTL_SHIM_CFG); | | 335 | (void)XCTL_RD_8(sc, XCTL_SHIM_CFG); |
337 | } | | 336 | } |
338 | | | 337 | |
339 | int | | 338 | int |
340 | octxhci_dwc3_init(struct xhci_softc *sc) | | 339 | octxhci_dwc3_init(struct xhci_softc *sc) |
341 | { | | 340 | { |
342 | bus_space_handle_t ioh = sc->sc_ioh; | | 341 | bus_space_handle_t ioh = sc->sc_ioh; |
343 | uint32_t rev; | | 342 | uint32_t rev; |
344 | uint32_t val; | | 343 | uint32_t val; |
345 | | | 344 | |
346 | val = bus_space_read_4(sc->sc_iot, ioh, DWC3_GSNPSID); | | 345 | val = bus_space_read_4(sc->sc_iot, ioh, DWC3_GSNPSID); |
347 | if ((val & 0xffff0000u) != 0x55330000u) { | | 346 | if ((val & 0xffff0000u) != 0x55330000u) { |
348 | aprint_error(": no DWC3 core (DWC3_GSNPSID=%08x)\n", val); | | 347 | aprint_error(": no DWC3 core (DWC3_GSNPSID=%08x)\n", val); |
349 | return EIO; | | 348 | return EIO; |
350 | } | | 349 | } |
351 | rev = val & 0xffffu; | | 350 | rev = val & 0xffffu; |
352 | aprint_normal(": DWC3 rev 0x%04x\n", rev); | | 351 | aprint_normal(": DWC3 rev 0x%04x\n", rev); |
353 | | | 352 | |
354 | val = bus_space_read_4(sc->sc_iot, ioh, DWC3_GUSB3PIPECTL(0)); | | 353 | val = bus_space_read_4(sc->sc_iot, ioh, DWC3_GUSB3PIPECTL(0)); |
355 | val &= ~DWC3_GUSB3PIPECTL_UX_EXIT_PX; | | 354 | val &= ~DWC3_GUSB3PIPECTL_UX_EXIT_PX; |
356 | val |= DWC3_GUSB3PIPECTL_SUSPHY; | | 355 | val |= DWC3_GUSB3PIPECTL_SUSPHY; |
357 | bus_space_write_4(sc->sc_iot, ioh, DWC3_GUSB3PIPECTL(0), val); | | 356 | bus_space_write_4(sc->sc_iot, ioh, DWC3_GUSB3PIPECTL(0), val); |
358 | | | 357 | |
359 | val = bus_space_read_4(sc->sc_iot, ioh, DWC3_GUSB2PHYCFG(0)); | | 358 | val = bus_space_read_4(sc->sc_iot, ioh, DWC3_GUSB2PHYCFG(0)); |
360 | val |= DWC3_GUSB2PHYCFG_SUSPHY; | | 359 | val |= DWC3_GUSB2PHYCFG_SUSPHY; |
361 | bus_space_write_4(sc->sc_iot, ioh, DWC3_GUSB2PHYCFG(0), val); | | 360 | bus_space_write_4(sc->sc_iot, ioh, DWC3_GUSB2PHYCFG(0), val); |
362 | | | 361 | |
363 | /* Set the controller into host mode. */ | | 362 | /* Set the controller into host mode. */ |
364 | val = bus_space_read_4(sc->sc_iot, ioh, DWC3_GCTL); | | 363 | val = bus_space_read_4(sc->sc_iot, ioh, DWC3_GCTL); |
365 | val &= ~DWC3_GCTL_PRTCAP_MASK; | | 364 | val &= ~DWC3_GCTL_PRTCAP_MASK; |
366 | val |= DWC3_GCTL_PRTCAP_HOST; | | 365 | val |= DWC3_GCTL_PRTCAP_HOST; |
367 | bus_space_write_4(sc->sc_iot, ioh, DWC3_GCTL, val); | | 366 | bus_space_write_4(sc->sc_iot, ioh, DWC3_GCTL, val); |
368 | | | 367 | |
369 | val = bus_space_read_4(sc->sc_iot, ioh, DWC3_GCTL); | | 368 | val = bus_space_read_4(sc->sc_iot, ioh, DWC3_GCTL); |
370 | val &= ~DWC3_GCTL_SCALEDOWN_MASK; | | 369 | val &= ~DWC3_GCTL_SCALEDOWN_MASK; |
371 | val &= ~DWC3_GCTL_DISSCRAMBLE; | | 370 | val &= ~DWC3_GCTL_DISSCRAMBLE; |
372 | if (rev >= DWC3_REV_210A && rev <= DWC3_REV_250A) | | 371 | if (rev >= DWC3_REV_210A && rev <= DWC3_REV_250A) |
373 | val |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC; | | 372 | val |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC; |
374 | else | | 373 | else |
375 | val &= ~DWC3_GCTL_DSBLCLKGTNG; | | 374 | val &= ~DWC3_GCTL_DSBLCLKGTNG; |
376 | bus_space_write_4(sc->sc_iot, ioh, DWC3_GCTL, val); | | 375 | bus_space_write_4(sc->sc_iot, ioh, DWC3_GCTL, val); |
377 | | | 376 | |
378 | return 0; | | 377 | return 0; |
379 | } | | 378 | } |
380 | | | 379 | |
381 | /* ---- bus_space(9) */ | | 380 | /* ---- bus_space(9) */ |
382 | #define CHIP octxhci | | 381 | #define CHIP octxhci |
383 | #define CHIP_IO | | 382 | #define CHIP_IO |
384 | #define CHIP_LITTLE_ENDIAN | | 383 | #define CHIP_LITTLE_ENDIAN |
385 | | | 384 | |
386 | #define CHIP_W1_BUS_START(v) 0x0000000000000000ULL | | 385 | #define CHIP_W1_BUS_START(v) 0x0000000000000000ULL |
387 | #define CHIP_W1_BUS_END(v) 0x7fffffffffffffffULL | | 386 | #define CHIP_W1_BUS_END(v) 0x7fffffffffffffffULL |
388 | #define CHIP_W1_SYS_START(v) 0x8000000000000000ULL | | 387 | #define CHIP_W1_SYS_START(v) 0x8000000000000000ULL |
389 | #define CHIP_W1_SYS_END(v) 0xffffffffffffffffULL | | 388 | #define CHIP_W1_SYS_END(v) 0xffffffffffffffffULL |
390 | | | 389 | |
391 | #include <mips/mips/bus_space_alignstride_chipdep.c> | | 390 | #include <mips/mips/bus_space_alignstride_chipdep.c> |