1 /* $OpenBSD: octxctl.c,v 1.5 2021/03/11 11:16:59 jsg Exp $ */
2
3 /*
4 * Copyright (c) 2017 Visa Hankala
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 /*
20 * Driver for OCTEON USB3 controller bridge.
21 */
22
23 #include <sys/param.h>
24 #include <sys/systm.h>
25 #include <sys/device.h>
26 #include <sys/malloc.h>
27
28 #include <machine/fdt.h>
29 #include <machine/octeonvar.h>
30
31 #include <dev/ofw/fdt.h>
32 #include <dev/ofw/ofw_gpio.h>
33 #include <dev/ofw/openfirm.h>
34
35 #include <octeon/dev/iobusvar.h>
36 #include <octeon/dev/octxctlreg.h>
37
38 #define XCTL_RD_8(sc, reg) \
39 bus_space_read_8((sc)->sc_iot, (sc)->sc_ioh, (reg))
40 #define XCTL_WR_8(sc, reg, val) \
41 bus_space_write_8((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
42
43 struct octxctl_softc {
44 struct device sc_dev;
45 bus_space_tag_t sc_iot;
46 bus_space_handle_t sc_ioh;
47 int sc_power_gpio[3];
48 int sc_unit;
49 };
50
51 int octxctl_match(struct device *, void *, void *);
52 void octxctl_attach(struct device *, struct device *, void *);
53
54 int octxctl_dwc3_init(struct octxctl_softc *, struct fdt_reg *);
55 void octxctl_uctl_init(struct octxctl_softc *, uint64_t, uint64_t);
56 uint8_t octxctl_read_1(bus_space_tag_t, bus_space_handle_t, bus_size_t);
57 uint16_t octxctl_read_2(bus_space_tag_t, bus_space_handle_t, bus_size_t);
58 uint32_t octxctl_read_4(bus_space_tag_t, bus_space_handle_t, bus_size_t);
59 void octxctl_write_1(bus_space_tag_t, bus_space_handle_t, bus_size_t,
60 uint8_t);
61 void octxctl_write_2(bus_space_tag_t, bus_space_handle_t, bus_size_t,
62 uint16_t);
63 void octxctl_write_4(bus_space_tag_t, bus_space_handle_t, bus_size_t,
64 uint32_t);
65
66 const struct cfattach octxctl_ca = {
67 sizeof(struct octxctl_softc), octxctl_match, octxctl_attach
68 };
69
70 struct cfdriver octxctl_cd = {
71 NULL, "octxctl", DV_DULL
72 };
73
74 bus_space_t octxctl_tag = {
75 .bus_base = PHYS_TO_XKPHYS(0, CCA_NC),
76 ._space_read_1 = octxctl_read_1,
77 ._space_read_2 = octxctl_read_2,
78 ._space_read_4 = octxctl_read_4,
79 ._space_write_1 = octxctl_write_1,
80 ._space_write_2 = octxctl_write_2,
81 ._space_write_4 = octxctl_write_4,
82 ._space_map = iobus_space_map,
83 ._space_unmap = iobus_space_unmap,
84 ._space_subregion = generic_space_region,
85 ._space_vaddr = generic_space_vaddr
86 };
87
88 int
octxctl_match(struct device * parent,void * match,void * aux)89 octxctl_match(struct device *parent, void *match, void *aux)
90 {
91 struct fdt_attach_args *faa = aux;
92 int child;
93
94 if (OF_is_compatible(faa->fa_node, "cavium,octeon-7130-usb-uctl") == 0)
95 return 0;
96 if ((child = OF_child(faa->fa_node)) == 0)
97 return 0;
98 return OF_is_compatible(child, "cavium,octeon-7130-xhci");
99 }
100
101 void
octxctl_attach(struct device * parent,struct device * self,void * aux)102 octxctl_attach(struct device *parent, struct device *self, void *aux)
103 {
104 char clock_type_hs[32];
105 char clock_type_ss[32];
106 struct fdt_reg child_reg;
107 struct fdt_attach_args child_faa;
108 struct fdt_attach_args *faa = aux;
109 struct octxctl_softc *sc = (struct octxctl_softc *)self;
110 uint64_t clock_freq, clock_sel;
111 uint32_t reg[4];
112 int child;
113
114 if (faa->fa_nreg != 1) {
115 printf(": expected one IO space, got %d\n", faa->fa_nreg);
116 return;
117 }
118
119 child = OF_child(faa->fa_node);
120 if (OF_getpropint(faa->fa_node, "#address-cells", 0) != 2 ||
121 OF_getpropint(faa->fa_node, "#size-cells", 0) != 2) {
122 printf(": invalid fdt reg cells\n");
123 return;
124 }
125 if (OF_getproplen(child, "reg") != sizeof(reg)) {
126 printf(": invalid child fdt reg\n");
127 return;
128 }
129 OF_getpropintarray(child, "reg", reg, sizeof(reg));
130 child_reg.addr = ((uint64_t)reg[0] << 32) | reg[1];
131 child_reg.size = ((uint64_t)reg[2] << 32) | reg[3];
132
133 clock_freq = OF_getpropint(faa->fa_node, "refclk-frequency", 0);
134
135 if (OF_getprop(faa->fa_node, "refclk-type-hs", clock_type_hs,
136 sizeof(clock_type_hs)) < 0)
137 goto error;
138 if (OF_getprop(faa->fa_node, "refclk-type-ss", clock_type_ss,
139 sizeof(clock_type_ss)) < 0)
140 goto error;
141 clock_sel = 0;
142 if (strcmp(clock_type_ss, "dlmc_ref_clk1") == 0)
143 clock_sel |= 1;
144 if (strcmp(clock_type_hs, "pll_ref_clk") == 0)
145 clock_sel |= 2;
146
147 OF_getpropintarray(faa->fa_node, "power", sc->sc_power_gpio,
148 sizeof(sc->sc_power_gpio));
149
150 sc->sc_unit = (faa->fa_reg[0].addr >> 24) & 0x1;
151 sc->sc_iot = faa->fa_iot;
152 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, faa->fa_reg[0].size,
153 0, &sc->sc_ioh)) {
154 printf(": could not map registers\n");
155 goto error;
156 }
157
158 octxctl_uctl_init(sc, clock_freq, clock_sel);
159
160 if (octxctl_dwc3_init(sc, &child_reg) != 0) {
161 /* Error message has been printed already. */
162 goto error;
163 }
164
165 printf("\n");
166
167 memset(&child_faa, 0, sizeof(child_faa));
168 child_faa.fa_name = "";
169 child_faa.fa_node = child;
170 child_faa.fa_iot = &octxctl_tag;
171 child_faa.fa_dmat = faa->fa_dmat;
172 child_faa.fa_reg = &child_reg;
173 child_faa.fa_nreg = 1;
174 /* child_faa.fa_intr is not utilized. */
175
176 config_found(self, &child_faa, NULL);
177
178 return;
179
180 error:
181 if (sc->sc_ioh != 0)
182 bus_space_unmap(sc->sc_iot, sc->sc_ioh, faa->fa_reg[0].size);
183 }
184
185 void
octxctl_uctl_init(struct octxctl_softc * sc,uint64_t clock_freq,uint64_t clock_sel)186 octxctl_uctl_init(struct octxctl_softc *sc, uint64_t clock_freq,
187 uint64_t clock_sel)
188 {
189 static const uint32_t clock_divs[] = { 1, 2, 4, 6, 8, 16, 24, 32 };
190 uint64_t i, val;
191 uint64_t ioclock = octeon_ioclock_speed();
192 uint64_t mpll_mult;
193 uint64_t refclk_fsel;
194 int output_sel;
195
196 /*
197 * Put the bridge controller, USB core, PHY, and clock divider
198 * into reset.
199 */
200 val = XCTL_RD_8(sc, XCTL_CTL);
201 val |= XCTL_CTL_UCTL_RST;
202 val |= XCTL_CTL_UAHC_RST;
203 val |= XCTL_CTL_UPHY_RST;
204 XCTL_WR_8(sc, XCTL_CTL, val);
205 val = XCTL_RD_8(sc, XCTL_CTL);
206 val |= XCTL_CTL_CLKDIV_RST;
207 XCTL_WR_8(sc, XCTL_CTL, val);
208
209 /* Select IO clock divisor. */
210 for (i = 0; i < nitems(clock_divs); i++) {
211 if (ioclock / clock_divs[i] < 300000000)
212 break;
213 }
214
215 /* Update the divisor and enable the clock. */
216 val = XCTL_RD_8(sc, XCTL_CTL);
217 val &= ~XCTL_CTL_CLKDIV_SEL;
218 val |= (i << XCTL_CTL_CLKDIV_SEL_SHIFT) & XCTL_CTL_CLKDIV_SEL;
219 val |= XCTL_CTL_CLK_EN;
220 XCTL_WR_8(sc, XCTL_CTL, val);
221
222 /* Take the clock divider out of reset. */
223 val = XCTL_RD_8(sc, XCTL_CTL);
224 val &= ~XCTL_CTL_CLKDIV_RST;
225 XCTL_WR_8(sc, XCTL_CTL, val);
226
227 /* Select the reference clock. */
228 switch (clock_freq) {
229 case 50000000:
230 refclk_fsel = 0x07;
231 mpll_mult = 0x32;
232 break;
233 case 125000000:
234 refclk_fsel = 0x07;
235 mpll_mult = 0x28;
236 break;
237 case 100000000:
238 default:
239 if (clock_sel < 2)
240 refclk_fsel = 0x27;
241 else
242 refclk_fsel = 0x07;
243 mpll_mult = 0x19;
244 break;
245 }
246
247 /* Set the clock and power up PHYs. */
248 val = XCTL_RD_8(sc, XCTL_CTL);
249 val &= ~XCTL_CTL_REFCLK_SEL;
250 val |= clock_sel << XCTL_CTL_REFCLK_SEL_SHIFT;
251 val &= ~XCTL_CTL_REFCLK_DIV2;
252 val &= ~XCTL_CTL_REFCLK_FSEL;
253 val |= refclk_fsel << XCTL_CTL_REFCLK_FSEL_SHIFT;
254 val &= ~XCTL_CTL_MPLL_MULT;
255 val |= mpll_mult << XCTL_CTL_MPLL_MULT_SHIFT;
256 val |= XCTL_CTL_SSC_EN;
257 val |= XCTL_CTL_REFCLK_SSP_EN;
258 val |= XCTL_CTL_SSPOWER_EN;
259 val |= XCTL_CTL_HSPOWER_EN;
260 XCTL_WR_8(sc, XCTL_CTL, val);
261
262 delay(100);
263
264 /* Take the bridge out of reset. */
265 val = XCTL_RD_8(sc, XCTL_CTL);
266 val &= ~XCTL_CTL_UCTL_RST;
267 XCTL_WR_8(sc, XCTL_CTL, val);
268
269 delay(100);
270
271 if (sc->sc_power_gpio[0] != 0) {
272 if (sc->sc_unit == 0)
273 output_sel = GPIO_CONFIG_MD_USB0_VBUS_CTRL;
274 else
275 output_sel = GPIO_CONFIG_MD_USB1_VBUS_CTRL;
276 gpio_controller_config_pin(sc->sc_power_gpio,
277 GPIO_CONFIG_OUTPUT | output_sel);
278
279 /* Enable port power control. */
280 val = XCTL_RD_8(sc, XCTL_HOST_CFG);
281 val |= XCTL_HOST_CFG_PPC_EN;
282 if (sc->sc_power_gpio[2] & GPIO_ACTIVE_LOW)
283 val &= ~XCTL_HOST_CFG_PPC_ACTIVE_HIGH_EN;
284 else
285 val |= XCTL_HOST_CFG_PPC_ACTIVE_HIGH_EN;
286 XCTL_WR_8(sc, XCTL_HOST_CFG, val);
287 } else {
288 /* Disable port power control. */
289 val = XCTL_RD_8(sc, XCTL_HOST_CFG);
290 val &= ~XCTL_HOST_CFG_PPC_EN;
291 XCTL_WR_8(sc, XCTL_HOST_CFG, val);
292 }
293
294 /* Enable host-only mode. */
295 val = XCTL_RD_8(sc, XCTL_CTL);
296 val &= ~XCTL_CTL_DRD_MODE;
297 XCTL_WR_8(sc, XCTL_CTL, val);
298
299 delay(100);
300
301 /* Take the USB core out of reset. */
302 val = XCTL_RD_8(sc, XCTL_CTL);
303 val &= ~XCTL_CTL_UAHC_RST;
304 XCTL_WR_8(sc, XCTL_CTL, val);
305
306 delay(100);
307
308 val = XCTL_RD_8(sc, XCTL_CTL);
309 val |= XCTL_CTL_CSCLK_EN;
310 XCTL_WR_8(sc, XCTL_CTL, val);
311
312 /* Take the PHY out of reset. */
313 val = XCTL_RD_8(sc, XCTL_CTL);
314 val &= ~XCTL_CTL_UPHY_RST;
315 XCTL_WR_8(sc, XCTL_CTL, val);
316 (void)XCTL_RD_8(sc, XCTL_CTL);
317
318 /* Fix endianness. */
319 val = XCTL_RD_8(sc, XCTL_SHIM_CFG);
320 val &= ~XCTL_SHIM_CFG_CSR_BYTE_SWAP;
321 val &= ~XCTL_SHIM_CFG_DMA_BYTE_SWAP;
322 val |= 3ull << XCTL_SHIM_CFG_CSR_BYTE_SWAP_SHIFT;
323 val |= 1ull << XCTL_SHIM_CFG_DMA_BYTE_SWAP_SHIFT;
324 XCTL_WR_8(sc, XCTL_SHIM_CFG, val);
325 (void)XCTL_RD_8(sc, XCTL_SHIM_CFG);
326 }
327
328 int
octxctl_dwc3_init(struct octxctl_softc * sc,struct fdt_reg * reg)329 octxctl_dwc3_init(struct octxctl_softc *sc, struct fdt_reg *reg)
330 {
331 bus_space_handle_t ioh;
332 uint32_t rev;
333 uint32_t val;
334 int error = 0;
335
336 if (bus_space_map(sc->sc_iot, reg->addr, reg->size, 0, &ioh) != 0) {
337 printf(": could not map USB3 core registers\n");
338 return EIO;
339 }
340
341 val = bus_space_read_4(sc->sc_iot, ioh, DWC3_GSNPSID);
342 if ((val & 0xffff0000u) != 0x55330000u) {
343 printf(": no DWC3 core\n");
344 error = EIO;
345 goto out;
346 }
347 rev = val & 0xffffu;
348 printf(": DWC3 rev 0x%04x", rev);
349
350 val = bus_space_read_4(sc->sc_iot, ioh, DWC3_GUSB3PIPECTL(0));
351 val &= ~DWC3_GUSB3PIPECTL_UX_EXIT_PX;
352 val |= DWC3_GUSB3PIPECTL_SUSPHY;
353 bus_space_write_4(sc->sc_iot, ioh, DWC3_GUSB3PIPECTL(0), val);
354
355 val = bus_space_read_4(sc->sc_iot, ioh, DWC3_GUSB2PHYCFG(0));
356 val |= DWC3_GUSB2PHYCFG_SUSPHY;
357 bus_space_write_4(sc->sc_iot, ioh, DWC3_GUSB2PHYCFG(0), val);
358
359 /* Set the controller into host mode. */
360 val = bus_space_read_4(sc->sc_iot, ioh, DWC3_GCTL);
361 val &= ~DWC3_GCTL_PRTCAP_MASK;
362 val |= DWC3_GCTL_PRTCAP_HOST;
363 bus_space_write_4(sc->sc_iot, ioh, DWC3_GCTL, val);
364
365 val = bus_space_read_4(sc->sc_iot, ioh, DWC3_GCTL);
366 val &= ~DWC3_GCTL_SCALEDOWN_MASK;
367 val &= ~DWC3_GCTL_DISSCRAMBLE;
368 if (rev >= DWC3_REV_210A && rev <= DWC3_REV_250A)
369 val |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC;
370 else
371 val &= ~DWC3_GCTL_DSBLCLKGTNG;
372 bus_space_write_4(sc->sc_iot, ioh, DWC3_GCTL, val);
373
374 out:
375 bus_space_unmap(sc->sc_iot, ioh, reg->size);
376
377 return error;
378 }
379
380 /*
381 * Bus access routines for xhci(4).
382 */
383
384 uint8_t
octxctl_read_1(bus_space_tag_t t,bus_space_handle_t h,bus_size_t o)385 octxctl_read_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
386 {
387 return *(volatile uint8_t *)(h + (o ^ 3));
388 }
389
390 uint16_t
octxctl_read_2(bus_space_tag_t t,bus_space_handle_t h,bus_size_t o)391 octxctl_read_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
392 {
393 return *(volatile uint16_t *)(h + (o ^ 2));
394 }
395
396 uint32_t
octxctl_read_4(bus_space_tag_t t,bus_space_handle_t h,bus_size_t o)397 octxctl_read_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
398 {
399 return *(volatile uint32_t *)(h + o);
400 }
401
402 void
octxctl_write_1(bus_space_tag_t t,bus_space_handle_t h,bus_size_t o,uint8_t v)403 octxctl_write_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
404 uint8_t v)
405 {
406 *(volatile uint8_t *)(h + (o ^ 3)) = v;
407 }
408
409 void
octxctl_write_2(bus_space_tag_t t,bus_space_handle_t h,bus_size_t o,uint16_t v)410 octxctl_write_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
411 uint16_t v)
412 {
413 *(volatile uint16_t *)(h + (o ^ 2)) = v;
414 }
415
416 void
octxctl_write_4(bus_space_tag_t t,bus_space_handle_t h,bus_size_t o,uint32_t v)417 octxctl_write_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
418 uint32_t v)
419 {
420 *(volatile uint32_t *)(h + o) = v;
421 }
422