xref: /openbsd-src/sys/arch/octeon/dev/octxctl.c (revision 36fd90dcf1acf2ddb4ef5dbabe5313b3a8d46ee2)
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