1 /* $OpenBSD: octdwctwo.c,v 1.15 2022/09/04 08:42:39 mglocker Exp $ */
2
3 /*
4 * Copyright (c) 2015 Masao Uebayashi <uebayasi@tombiinc.com>
5 *
6 * Permission to use, copy, modify, and/or 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 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/device.h>
22
23 #include <machine/intr.h>
24 #include <machine/bus.h>
25 #include <machine/octeonreg.h>
26 #include <machine/octeonvar.h>
27 #include <machine/octeon_model.h>
28
29 #include <octeon/dev/iobusvar.h>
30 #include <octeon/dev/octhcireg.h>
31
32 #include <dev/usb/usb.h>
33 #include <dev/usb/usbdi.h>
34 #include <dev/usb/usbdivar.h>
35
36 #include <dev/usb/dwc2/dwc2var.h>
37 #include <dev/usb/dwc2/dwc2.h>
38 #include <dev/usb/dwc2/dwc2_core.h>
39
40 struct octdwctwo_softc {
41 struct dwc2_softc sc_dwc2;
42
43 /* USBN bus space */
44 bus_space_tag_t sc_bust;
45 bus_space_handle_t sc_regh;
46 bus_space_handle_t sc_regh2;
47
48 void *sc_ih;
49 };
50
51 int octdwctwo_match(struct device *, void *, void *);
52 void octdwctwo_attach(struct device *, struct device *,
53 void *);
54 int octdwctwo_activate(struct device *, int);
55 int octdwctwo_set_dma_addr(struct device *, bus_addr_t, int);
56 u_int64_t octdwctwo_reg2_rd(struct octdwctwo_softc *, bus_size_t);
57 void octdwctwo_reg2_wr(struct octdwctwo_softc *, bus_size_t,
58 u_int64_t);
59 void octdwctwo_reg_set(struct octdwctwo_softc *, bus_size_t,
60 u_int64_t);
61 void octdwctwo_reg_clear(struct octdwctwo_softc *,
62 bus_size_t, u_int64_t);
63 u_int32_t octdwctwo_read_4(bus_space_tag_t, bus_space_handle_t,
64 bus_size_t);
65 void octdwctwo_write_4(bus_space_tag_t, bus_space_handle_t,
66 bus_size_t, u_int32_t);
67
68
69 const struct cfattach octdwctwo_ca = {
70 sizeof(struct octdwctwo_softc), octdwctwo_match, octdwctwo_attach,
71 NULL, octdwctwo_activate
72 };
73
74 struct cfdriver dwctwo_cd = {
75 NULL, "dwctwo", DV_DULL
76 };
77
78 static struct dwc2_core_params octdwctwo_params = {
79 .otg_caps.hnp_support = 0,
80 .otg_caps.srp_support = 0,
81 .host_dma = 1,
82 .dma_desc_enable = 0,
83 .speed = 0,
84 .enable_dynamic_fifo = 1,
85 .en_multiple_tx_fifo = 0,
86 .host_rx_fifo_size = 456,
87 .host_nperio_tx_fifo_size = 912,
88 .host_perio_tx_fifo_size = 256,
89 .max_transfer_size = 65535,
90 .max_packet_count = 511,
91 .host_channels = 8,
92 .phy_type = 1,
93 .phy_utmi_width = 16,
94 .phy_ulpi_ddr = 0,
95 .phy_ulpi_ext_vbus = 0,
96 .i2c_enable = 0,
97 .ulpi_fs_ls = 0,
98 .host_support_fs_ls_low_power = 0,
99 .host_ls_low_power_phy_clk = 0,
100 .ts_dline = 0,
101 .reload_ctl = 0,
102 .ahbcfg = 0x7,
103 .uframe_sched = 1,
104 .external_id_pin_ctl = 0,
105 };
106
107 /*
108 * This bus space tag adjusts register addresses to account for
109 * dwc2 using little endian addressing. dwc2 only does 32bit reads
110 * and writes, so only those functions are provided.
111 */
112 bus_space_t octdwctwo_tag = {
113 .bus_base = PHYS_TO_XKPHYS(0, CCA_NC),
114 .bus_private = NULL,
115 ._space_read_4 = octdwctwo_read_4,
116 ._space_write_4 = octdwctwo_write_4,
117 ._space_map = iobus_space_map,
118 ._space_unmap = iobus_space_unmap,
119 ._space_subregion = generic_space_region,
120 ._space_vaddr = generic_space_vaddr
121 };
122
123 int
octdwctwo_match(struct device * parent,void * match,void * aux)124 octdwctwo_match(struct device *parent, void *match, void *aux)
125 {
126 int id;
127
128 id = octeon_get_chipid();
129 switch (octeon_model_family(id)) {
130 case OCTEON_MODEL_FAMILY_CN30XX:
131 case OCTEON_MODEL_FAMILY_CN31XX:
132 case OCTEON_MODEL_FAMILY_CN50XX:
133 return (1);
134 default:
135 return (0);
136 }
137 }
138
139 void
octdwctwo_attach(struct device * parent,struct device * self,void * aux)140 octdwctwo_attach(struct device *parent, struct device *self, void *aux)
141 {
142 struct octdwctwo_softc *sc = (struct octdwctwo_softc *)self;
143 struct iobus_attach_args *aa = aux;
144 uint64_t clk;
145 int rc;
146
147 sc->sc_dwc2.sc_iot = &octdwctwo_tag;
148 sc->sc_dwc2.sc_bus.pipe_size = sizeof(struct usbd_pipe);
149 sc->sc_dwc2.sc_bus.dmatag = aa->aa_dmat;
150 sc->sc_dwc2.sc_params = &octdwctwo_params;
151 sc->sc_dwc2.sc_set_dma_addr = octdwctwo_set_dma_addr;
152
153 rc = bus_space_map(sc->sc_dwc2.sc_iot, USBC_BASE, USBC_SIZE,
154 0, &sc->sc_dwc2.sc_ioh);
155 KASSERT(rc == 0);
156
157 sc->sc_bust = aa->aa_bust;
158 rc = bus_space_map(sc->sc_bust, USBN_BASE, USBN_SIZE,
159 0, &sc->sc_regh);
160 KASSERT(rc == 0);
161 rc = bus_space_map(sc->sc_bust, USBN_2_BASE, USBN_2_SIZE,
162 0, &sc->sc_regh2);
163 KASSERT(rc == 0);
164
165 /*
166 * Clock setup.
167 */
168 clk = bus_space_read_8(sc->sc_bust, sc->sc_regh, USBN_CLK_CTL_OFFSET);
169 clk |= USBN_CLK_CTL_POR;
170 clk &= ~(USBN_CLK_CTL_HRST | USBN_CLK_CTL_PRST | USBN_CLK_CTL_HCLK_RST |
171 USBN_CLK_CTL_ENABLE | USBN_CLK_CTL_P_C_SEL | USBN_CLK_CTL_P_RTYPE);
172 clk |= SET_USBN_CLK_CTL_DIVIDE(0x4ULL)
173 | SET_USBN_CLK_CTL_DIVIDE2(0x0ULL);
174
175 bus_space_write_8(sc->sc_bust, sc->sc_regh, USBN_CLK_CTL_OFFSET, clk);
176 bus_space_read_8(sc->sc_bust, sc->sc_regh, USBN_CLK_CTL_OFFSET);
177
178 /*
179 * Reset HCLK and wait for it to stabilize.
180 */
181 octdwctwo_reg_set(sc, USBN_CLK_CTL_OFFSET, USBN_CLK_CTL_HCLK_RST);
182 delay(64);
183
184 octdwctwo_reg_clear(sc, USBN_CLK_CTL_OFFSET, USBN_CLK_CTL_POR);
185
186 /*
187 * Wait for the PHY clock to start.
188 */
189 delay(1000);
190
191 octdwctwo_reg_set(sc, USBN_USBP_CTL_STATUS_OFFSET,
192 USBN_USBP_CTL_STATUS_ATE_RESET);
193 delay(10);
194
195 octdwctwo_reg_clear(sc, USBN_USBP_CTL_STATUS_OFFSET,
196 USBN_USBP_CTL_STATUS_ATE_RESET);
197 octdwctwo_reg_set(sc, USBN_CLK_CTL_OFFSET, USBN_CLK_CTL_PRST);
198
199 /*
200 * Select host mode.
201 */
202 octdwctwo_reg_clear(sc, USBN_USBP_CTL_STATUS_OFFSET,
203 USBN_USBP_CTL_STATUS_HST_MODE);
204 delay(1);
205
206 octdwctwo_reg_set(sc, USBN_CLK_CTL_OFFSET, USBN_CLK_CTL_HRST);
207
208 /*
209 * Enable clock.
210 */
211 octdwctwo_reg_set(sc, USBN_CLK_CTL_OFFSET, USBN_CLK_CTL_ENABLE);
212 delay(1);
213
214 strlcpy(sc->sc_dwc2.sc_vendor, "Octeon", sizeof(sc->sc_dwc2.sc_vendor));
215
216 rc = dwc2_init(&sc->sc_dwc2);
217 if (rc != 0)
218 return;
219
220 printf("\n");
221
222 sc->sc_dwc2.sc_child = config_found(&sc->sc_dwc2.sc_bus.bdev,
223 &sc->sc_dwc2.sc_bus, usbctlprint);
224
225 sc->sc_ih = octeon_intr_establish(CIU_INT_USB, IPL_VM | IPL_MPSAFE,
226 dwc2_intr, (void *)&sc->sc_dwc2, sc->sc_dwc2.sc_bus.bdev.dv_xname);
227 KASSERT(sc->sc_ih != NULL);
228 }
229
230 int
octdwctwo_activate(struct device * self,int act)231 octdwctwo_activate(struct device *self, int act)
232 {
233 struct octdwctwo_softc *sc = (struct octdwctwo_softc *)self;
234 uint64_t clk;
235 int rv = 0;
236
237 switch (act) {
238 case DVACT_POWERDOWN:
239 /*
240 * Put the controller into reset mode.
241 * It appears necessary to hold this state for a moment.
242 * Otherwise subsequent attempts to reinitialize the controller
243 * may fail because of hanging or trapping access
244 * of DWC2 core registers.
245 */
246 clk = bus_space_read_8(sc->sc_bust, sc->sc_regh,
247 USBN_CLK_CTL_OFFSET);
248 clk |= USBN_CLK_CTL_POR;
249 clk |= USBN_CLK_CTL_HCLK_RST;
250 clk |= USBN_CLK_CTL_ENABLE;
251 clk &= ~USBN_CLK_CTL_HRST;
252 clk &= ~USBN_CLK_CTL_PRST;
253 bus_space_write_8(sc->sc_bust, sc->sc_regh,
254 USBN_CLK_CTL_OFFSET, clk);
255 (void)bus_space_read_8(sc->sc_bust, sc->sc_regh,
256 USBN_CLK_CTL_OFFSET);
257 delay(50000);
258 break;
259 default:
260 break;
261 }
262 return rv;
263 }
264
265 int
octdwctwo_set_dma_addr(struct device * data,bus_addr_t dma_addr,int ch)266 octdwctwo_set_dma_addr(struct device *data, bus_addr_t dma_addr, int ch)
267 {
268 struct octdwctwo_softc *sc = (struct octdwctwo_softc *)data;
269
270 octdwctwo_reg2_wr(sc,
271 USBN_DMA0_INB_CHN0_OFFSET + ch * 0x8, dma_addr);
272 octdwctwo_reg2_wr(sc,
273 USBN_DMA0_OUTB_CHN0_OFFSET + ch * 0x8, dma_addr);
274 return 0;
275 }
276
277 u_int64_t
octdwctwo_reg2_rd(struct octdwctwo_softc * sc,bus_size_t offset)278 octdwctwo_reg2_rd(struct octdwctwo_softc *sc, bus_size_t offset)
279 {
280 u_int64_t value;
281
282 value = bus_space_read_8(sc->sc_bust, sc->sc_regh2, offset);
283 return value;
284 }
285
286 void
octdwctwo_reg2_wr(struct octdwctwo_softc * sc,bus_size_t offset,u_int64_t value)287 octdwctwo_reg2_wr(struct octdwctwo_softc *sc, bus_size_t offset, u_int64_t value)
288 {
289 bus_space_write_8(sc->sc_bust, sc->sc_regh2, offset, value);
290 /* guarantee completion of the store operation on RSL registers*/
291 bus_space_read_8(sc->sc_bust, sc->sc_regh2, offset);
292 }
293
294 void
octdwctwo_reg_set(struct octdwctwo_softc * sc,bus_size_t offset,u_int64_t bits)295 octdwctwo_reg_set(struct octdwctwo_softc *sc, bus_size_t offset,
296 u_int64_t bits)
297 {
298 u_int64_t value;
299 value = bus_space_read_8(sc->sc_bust, sc->sc_regh, offset);
300 value |= bits;
301
302 bus_space_write_8(sc->sc_bust, sc->sc_regh, offset, value);
303 bus_space_read_8(sc->sc_bust, sc->sc_regh, offset);
304 }
305
306 void
octdwctwo_reg_clear(struct octdwctwo_softc * sc,bus_size_t offset,u_int64_t bits)307 octdwctwo_reg_clear(struct octdwctwo_softc *sc, bus_size_t offset,
308 u_int64_t bits)
309 {
310 u_int64_t value;
311 value = bus_space_read_8(sc->sc_bust, sc->sc_regh, offset);
312 value &= ~bits;
313
314 bus_space_write_8(sc->sc_bust, sc->sc_regh, offset, value);
315 bus_space_read_8(sc->sc_bust, sc->sc_regh, offset);
316 }
317
318 u_int32_t
octdwctwo_read_4(bus_space_tag_t t,bus_space_handle_t h,bus_size_t o)319 octdwctwo_read_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
320 {
321 return *(volatile u_int32_t *)(h + (o^4));
322 }
323
324 void
octdwctwo_write_4(bus_space_tag_t t,bus_space_handle_t h,bus_size_t o,u_int32_t v)325 octdwctwo_write_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
326 u_int32_t v)
327 {
328 *(volatile u_int32_t *)(h + (o^4)) = v;
329 }
330