diff options
Diffstat (limited to 'firmware/target/arm/tms320dm320/sansa-connect/tnetv105_usb_drv.c')
-rw-r--r-- | firmware/target/arm/tms320dm320/sansa-connect/tnetv105_usb_drv.c | 1489 |
1 files changed, 1489 insertions, 0 deletions
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/tnetv105_usb_drv.c b/firmware/target/arm/tms320dm320/sansa-connect/tnetv105_usb_drv.c new file mode 100644 index 0000000000..4fdf73cb50 --- /dev/null +++ b/firmware/target/arm/tms320dm320/sansa-connect/tnetv105_usb_drv.c | |||
@@ -0,0 +1,1489 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: $ | ||
9 | * | ||
10 | * Copyright (C) 2021 by Tomasz Moń | ||
11 | * Ported from Sansa Connect TNETV105 UDC Linux driver | ||
12 | * Copyright (c) 2005,2006 Zermatt Systems, Inc. | ||
13 | * Written by: Ben Bostwick | ||
14 | * Linux driver was modeled strongly after the pxa usb driver. | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or | ||
17 | * modify it under the terms of the GNU General Public License | ||
18 | * as published by the Free Software Foundation; either version 2 | ||
19 | * of the License, or (at your option) any later version. | ||
20 | * | ||
21 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
22 | * KIND, either express or implied. | ||
23 | * | ||
24 | ****************************************************************************/ | ||
25 | |||
26 | #include "config.h" | ||
27 | #include "system.h" | ||
28 | #include "kernel.h" | ||
29 | #include "panic.h" | ||
30 | #include "logf.h" | ||
31 | #include "usb.h" | ||
32 | #include "usb_drv.h" | ||
33 | #include "usb_core.h" | ||
34 | #include <string.h> | ||
35 | #include "tnetv105_usb_drv.h" | ||
36 | #include "tnetv105_cppi.h" | ||
37 | |||
38 | #ifdef SANSA_CONNECT | ||
39 | #define SDRAM_SIZE 0x04000000 | ||
40 | |||
41 | static void set_tnetv_reset(bool high) | ||
42 | { | ||
43 | if (high) | ||
44 | { | ||
45 | IO_GIO_BITSET0 = (1 << 7); | ||
46 | } | ||
47 | else | ||
48 | { | ||
49 | IO_GIO_BITCLR0 = (1 << 7); | ||
50 | } | ||
51 | } | ||
52 | |||
53 | static bool is_tnetv_reset_high(void) | ||
54 | { | ||
55 | return (IO_GIO_BITSET0 & (1 << 7)) ? true : false; | ||
56 | } | ||
57 | #endif | ||
58 | |||
59 | static bool setup_is_set_address; | ||
60 | |||
61 | static cppi_info cppi; | ||
62 | |||
63 | static struct ep_runtime_t | ||
64 | { | ||
65 | int max_packet_size; | ||
66 | bool in_allocated; | ||
67 | bool out_allocated; | ||
68 | uint8_t *rx_buf; /* OUT */ | ||
69 | int rx_remaining; | ||
70 | int rx_size; | ||
71 | uint8_t *tx_buf; /* IN */ | ||
72 | int tx_remaining; | ||
73 | int tx_size; | ||
74 | volatile bool block; /* flag indicating that transfer is blocking */ | ||
75 | struct semaphore complete; /* semaphore for blocking transfers */ | ||
76 | } | ||
77 | ep_runtime[USB_NUM_ENDPOINTS]; | ||
78 | |||
79 | static const struct | ||
80 | { | ||
81 | int type; | ||
82 | int hs_max_packet_size; | ||
83 | /* Not sure what xyoff[1] is for. Presumably it is double buffer, but how | ||
84 | * the double buffering works is not so clear from the Sansa Connect Linux | ||
85 | * kernel patch. As TNETV105 datasheet is not available, the values are | ||
86 | * simply taken from the Linux patch as potential constraints are unknown. | ||
87 | * | ||
88 | * Linux kernel has 9 endpoints: | ||
89 | * * 0: ep0 | ||
90 | * * 1: ep1in-bulk | ||
91 | * * 2: ep2out-bulk | ||
92 | * * 3: ep3in-int | ||
93 | * * 4: ep4in-int | ||
94 | * * 5: ep1out-bulk | ||
95 | * * 6: ep2in-bulk | ||
96 | * * 7: ep3out-int | ||
97 | * * 8: ep4out-int | ||
98 | */ | ||
99 | uint16_t xyoff_in[2]; | ||
100 | uint16_t xyoff_out[2]; | ||
101 | } | ||
102 | ep_const_data[USB_NUM_ENDPOINTS] = | ||
103 | { | ||
104 | { | ||
105 | .type = USB_ENDPOINT_XFER_CONTROL, | ||
106 | .hs_max_packet_size = EP0_MAX_PACKET_SIZE, | ||
107 | /* Do not set xyoff as it likely does not apply here. | ||
108 | * Linux simply hardcodes the offsets when needed. | ||
109 | */ | ||
110 | }, | ||
111 | { | ||
112 | .type = USB_ENDPOINT_XFER_BULK, | ||
113 | .hs_max_packet_size = EP1_MAX_PACKET_SIZE, | ||
114 | .xyoff_in = {EP1_XBUFFER_ADDRESS, EP1_YBUFFER_ADDRESS}, | ||
115 | .xyoff_out = {EP5_XBUFFER_ADDRESS, EP5_YBUFFER_ADDRESS}, | ||
116 | }, | ||
117 | { | ||
118 | .type = USB_ENDPOINT_XFER_BULK, | ||
119 | .hs_max_packet_size = EP2_MAX_PACKET_SIZE, | ||
120 | .xyoff_in = {EP6_XBUFFER_ADDRESS, EP6_YBUFFER_ADDRESS}, | ||
121 | .xyoff_out = {EP2_XBUFFER_ADDRESS, EP2_YBUFFER_ADDRESS}, | ||
122 | }, | ||
123 | { | ||
124 | .type = USB_ENDPOINT_XFER_INT, | ||
125 | .hs_max_packet_size = EP3_MAX_PACKET_SIZE, | ||
126 | .xyoff_in = {EP3_XBUFFER_ADDRESS, EP3_YBUFFER_ADDRESS}, | ||
127 | .xyoff_out = {EP7_XBUFFER_ADDRESS, EP7_YBUFFER_ADDRESS}, | ||
128 | }, | ||
129 | { | ||
130 | .type = USB_ENDPOINT_XFER_INT, | ||
131 | .hs_max_packet_size = EP4_MAX_PACKET_SIZE, | ||
132 | .xyoff_in = {EP4_XBUFFER_ADDRESS, EP4_YBUFFER_ADDRESS}, | ||
133 | .xyoff_out = {EP8_XBUFFER_ADDRESS, EP8_YBUFFER_ADDRESS}, | ||
134 | }, | ||
135 | }; | ||
136 | |||
137 | #define VLYNQ_CTL_RESET_MASK 0x0001 | ||
138 | #define VLYNQ_CTL_CLKDIR_MASK 0x8000 | ||
139 | #define VLYNQ_STS_LINK_MASK 0x0001 | ||
140 | |||
141 | #define DM320_VLYNQ_CTRL_RESET (1 << 0) | ||
142 | #define DM320_VLYNQ_CTRL_LOOP (1 << 1) | ||
143 | #define DM320_VLYNQ_CTRL_ADR_OPT (1 << 2) | ||
144 | #define DM320_VLYNQ_CTRL_INT_CFG (1 << 7) | ||
145 | #define DM320_VLYNQ_CTRL_INT_VEC_MASK (0x00001F00) | ||
146 | #define DM320_VLYNQ_CTRL_INT_EN (1 << 13) | ||
147 | #define DM320_VLYNQ_CTRL_INT_LOC (1 << 14) | ||
148 | #define DM320_VLYNQ_CTRL_CLKDIR (1 << 15) | ||
149 | #define DM320_VLYNQ_CTRL_CLKDIV_MASK (0x00070000) | ||
150 | #define DM320_VLYNQ_CTRL_PWR_MAN (1 << 31) | ||
151 | |||
152 | #define DM320_VLYNQ_STAT_LINK (1 << 0) | ||
153 | #define DM320_VLYNQ_STAT_MST_PEND (1 << 1) | ||
154 | #define DM320_VLYNQ_STAT_SLV_PEND (1 << 2) | ||
155 | #define DM320_VLYNQ_STAT_F0_NE (1 << 3) | ||
156 | #define DM320_VLYNQ_STAT_F1_NE (1 << 4) | ||
157 | #define DM320_VLYNQ_STAT_F2_NE (1 << 5) | ||
158 | #define DM320_VLYNQ_STAT_F3_NE (1 << 6) | ||
159 | #define DM320_VLYNQ_STAT_LOC_ERR (1 << 7) | ||
160 | #define DM320_VLYNQ_STAT_REM_ERR (1 << 8) | ||
161 | #define DM320_VLYNQ_STAT_FC_OUT (1 << 9) | ||
162 | #define DM320_VLYNQ_STAT_FC_IN (1 << 10) | ||
163 | |||
164 | #define MAX_PACKET(epn, speed) ((((speed) == USB_SPEED_HIGH) && (((epn) == 1) || ((epn) == 2))) ? USB_HIGH_SPEED_MAXPACKET : USB_FULL_SPEED_MAXPACKET) | ||
165 | |||
166 | #define VLYNQ_INTR_USB20 (1 << 0) | ||
167 | #define VLYNQ_INTR_CPPI (1 << 1) | ||
168 | |||
169 | static inline void set_vlynq_clock(bool enable) | ||
170 | { | ||
171 | if (enable) | ||
172 | { | ||
173 | IO_CLK_MOD2 |= (1 << 13); | ||
174 | } | ||
175 | else | ||
176 | { | ||
177 | IO_CLK_MOD2 &= ~(1 << 13); | ||
178 | } | ||
179 | } | ||
180 | |||
181 | static inline void set_vlynq_irq(bool enabled) | ||
182 | { | ||
183 | if (enabled) | ||
184 | { | ||
185 | /* Enable VLYNQ interrupt */ | ||
186 | IO_INTC_EINT1 |= (1 << 0); | ||
187 | } | ||
188 | else | ||
189 | { | ||
190 | IO_INTC_EINT1 &= ~(1 << 0); | ||
191 | } | ||
192 | } | ||
193 | |||
194 | static int tnetv_hw_reset(void) | ||
195 | { | ||
196 | int timeout; | ||
197 | |||
198 | /* hold down the reset pin on the USB chip */ | ||
199 | set_tnetv_reset(false); | ||
200 | |||
201 | /* Turn on VLYNQ clock. */ | ||
202 | set_vlynq_clock(true); | ||
203 | |||
204 | /* now reset the VLYNQ module */ | ||
205 | VL_CTRL |= (VLYNQ_CTL_CLKDIR_MASK | DM320_VLYNQ_CTRL_PWR_MAN); | ||
206 | VL_CTRL |= VLYNQ_CTL_RESET_MASK; | ||
207 | |||
208 | mdelay(10); | ||
209 | |||
210 | /* pull up the reset pin */ | ||
211 | set_tnetv_reset(true); | ||
212 | |||
213 | /* take the VLYNQ out of reset */ | ||
214 | VL_CTRL &= ~VLYNQ_CTL_RESET_MASK; | ||
215 | |||
216 | timeout = 0; | ||
217 | while (!(VL_STAT & VLYNQ_STS_LINK_MASK) && timeout++ < 50); | ||
218 | { | ||
219 | mdelay(40); | ||
220 | } | ||
221 | |||
222 | if (!(VL_STAT & VLYNQ_STS_LINK_MASK)) | ||
223 | { | ||
224 | logf("ERROR: VLYNQ not initialized!\n"); | ||
225 | return -1; | ||
226 | } | ||
227 | |||
228 | /* set up vlynq local map */ | ||
229 | VL_TXMAP = DM320_VLYNQ_PADDR; | ||
230 | VL_RXMAPOF1 = CONFIG_SDRAM_START; | ||
231 | VL_RXMAPSZ1 = SDRAM_SIZE; | ||
232 | |||
233 | /* set up vlynq remote map for tnetv105 */ | ||
234 | VL_TXMAP_R = 0x00000000; | ||
235 | VL_RXMAPOF1_R = 0x0C000000; | ||
236 | VL_RXMAPSZ1_R = 0x00030000; | ||
237 | |||
238 | /* clear TNETV gpio state */ | ||
239 | tnetv_usb_reg_write(TNETV_V2USB_GPIO_FS, 0); | ||
240 | |||
241 | /* set USB_CHARGE_EN pin (gpio 1) - output, disable pullup */ | ||
242 | tnetv_usb_reg_write(TNETV_V2USB_GPIO_DOUT, 0); | ||
243 | tnetv_usb_reg_write(TNETV_V2USB_GPIO_DIR, 0xffff); | ||
244 | |||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | static int tnetv_xcvr_on(void) | ||
249 | { | ||
250 | return tnetv_hw_reset(); | ||
251 | } | ||
252 | |||
253 | static void tnetv_xcvr_off(void) | ||
254 | { | ||
255 | /* turn off vlynq module clock */ | ||
256 | set_vlynq_clock(false); | ||
257 | |||
258 | /* hold down the reset pin on the USB chip */ | ||
259 | set_tnetv_reset(false); | ||
260 | } | ||
261 | |||
262 | /* Copy data from the usb data memory. The memory reads should be done 32 bits at a time. | ||
263 | * We do not assume that the dst data is aligned. | ||
264 | */ | ||
265 | static void tnetv_copy_from_data_mem(void *dst, const volatile uint32_t *sp, int size) | ||
266 | { | ||
267 | uint8_t *dp = (uint8_t *) dst; | ||
268 | uint32_t value; | ||
269 | |||
270 | while (size >= 4) | ||
271 | { | ||
272 | value = *sp++; | ||
273 | dp[0] = value; | ||
274 | dp[1] = value >> 8; | ||
275 | dp[2] = value >> 16; | ||
276 | dp[3] = value >> 24; | ||
277 | dp += 4; | ||
278 | size -= 4; | ||
279 | } | ||
280 | |||
281 | if (size) | ||
282 | { | ||
283 | value = sp[0]; | ||
284 | switch (size) | ||
285 | { | ||
286 | case 3: | ||
287 | dp[2] = value >> 16; | ||
288 | case 2: | ||
289 | dp[1] = value >> 8; | ||
290 | case 1: | ||
291 | dp[0] = value; | ||
292 | break; | ||
293 | } | ||
294 | } | ||
295 | } | ||
296 | |||
297 | /* Copy data into the usb data memory. The memory writes must be done 32 bits at a time. | ||
298 | * We do not assume that the src data is aligned. | ||
299 | */ | ||
300 | static void tnetv_copy_to_data_mem(volatile uint32_t *dp, const void *src, int size) | ||
301 | { | ||
302 | const uint8_t *sp = (const uint8_t *) src; | ||
303 | uint32_t value; | ||
304 | |||
305 | while (size >= 4) | ||
306 | { | ||
307 | value = sp[0] | (sp[1] << 8) | (sp[2] << 16) | (sp[3] << 24); | ||
308 | *dp++ = value; | ||
309 | sp += 4; | ||
310 | size -= 4; | ||
311 | } | ||
312 | |||
313 | switch (size) | ||
314 | { | ||
315 | case 3: | ||
316 | value = sp[0] | (sp[1] << 8) | (sp[2] << 16); | ||
317 | *dp = value; | ||
318 | break; | ||
319 | case 2: | ||
320 | value = sp[0] | (sp[1] << 8); | ||
321 | *dp = value; | ||
322 | break; | ||
323 | case 1: | ||
324 | value = sp[0]; | ||
325 | *dp = value; | ||
326 | break; | ||
327 | } | ||
328 | } | ||
329 | |||
330 | static void tnetv_init_endpoints(void) | ||
331 | { | ||
332 | UsbEp0CtrlType ep0Cfg; | ||
333 | UsbEp0ByteCntType ep0Cnt; | ||
334 | UsbEpCfgCtrlType epCfg; | ||
335 | UsbEpStartAddrType epStartAddr; | ||
336 | int ch, wd, epn; | ||
337 | |||
338 | ep0Cnt.val = 0; | ||
339 | ep0Cnt.f.out_ybuf_nak = 1; | ||
340 | ep0Cnt.f.out_xbuf_nak = 1; | ||
341 | ep0Cnt.f.in_ybuf_nak = 1; | ||
342 | ep0Cnt.f.in_xbuf_nak = 1; | ||
343 | tnetv_usb_reg_write(TNETV_USB_EP0_CNT, ep0Cnt.val); | ||
344 | |||
345 | /* Setup endpoint zero */ | ||
346 | ep0Cfg.val = 0; | ||
347 | ep0Cfg.f.buf_size = EP0_BUF_SIZE_64; /* must be 64 bytes for USB 2.0 */ | ||
348 | ep0Cfg.f.dbl_buf = 0; | ||
349 | ep0Cfg.f.in_en = 1; | ||
350 | ep0Cfg.f.in_int_en = 1; | ||
351 | ep0Cfg.f.out_en = 1; | ||
352 | ep0Cfg.f.out_int_en = 1; | ||
353 | tnetv_usb_reg_write(TNETV_USB_EP0_CFG, ep0Cfg.val); | ||
354 | |||
355 | /* disable cell dma */ | ||
356 | tnetv_usb_reg_write(TNETV_USB_CELL_DMA_EN, 0); | ||
357 | |||
358 | /* turn off dma engines */ | ||
359 | tnetv_usb_reg_write(TNETV_USB_TX_CTL, 0); | ||
360 | tnetv_usb_reg_write(TNETV_USB_RX_CTL, 0); | ||
361 | |||
362 | /* clear out DMA registers */ | ||
363 | for (ch = 0; ch < TNETV_DMA_NUM_CHANNELS; ch++) | ||
364 | { | ||
365 | for (wd = 0; wd < TNETV_DMA_TX_NUM_WORDS; wd++) | ||
366 | { | ||
367 | tnetv_usb_reg_write(TNETV_DMA_TX_STATE(ch, wd), 0); | ||
368 | } | ||
369 | |||
370 | for (wd = 0; wd < TNETV_DMA_RX_NUM_WORDS; wd++) | ||
371 | { | ||
372 | tnetv_usb_reg_write(TNETV_DMA_RX_STATE(ch, wd), 0); | ||
373 | } | ||
374 | |||
375 | /* flush the free buf count */ | ||
376 | while (tnetv_usb_reg_read(TNETV_USB_RX_FREE_BUF_CNT(ch)) != 0) | ||
377 | { | ||
378 | tnetv_usb_reg_write(TNETV_USB_RX_FREE_BUF_CNT(ch), 0xFFFF); | ||
379 | } | ||
380 | } | ||
381 | |||
382 | for (epn = 1; epn < USB_NUM_ENDPOINTS; epn++) | ||
383 | { | ||
384 | tnetv_usb_reg_write(TNETV_USB_EPx_ADR(epn),0); | ||
385 | tnetv_usb_reg_write(TNETV_USB_EPx_CFG(epn), 0); | ||
386 | tnetv_usb_reg_write(TNETV_USB_EPx_IN_CNT(epn), 0x80008000); | ||
387 | tnetv_usb_reg_write(TNETV_USB_EPx_OUT_CNT(epn), 0x80008000); | ||
388 | } | ||
389 | |||
390 | /* Setup the other endpoints */ | ||
391 | for (epn = 1; epn < USB_NUM_ENDPOINTS; epn++) | ||
392 | { | ||
393 | epCfg.val = tnetv_usb_reg_read(TNETV_USB_EPx_CFG(epn)); | ||
394 | epStartAddr.val = tnetv_usb_reg_read(TNETV_USB_EPx_ADR(epn)); | ||
395 | |||
396 | epCfg.f.in_dbl_buf = 1; | ||
397 | epCfg.f.in_toggle_rst = 1; | ||
398 | epCfg.f.in_ack_int = 0; | ||
399 | epCfg.f.in_stall = 0; | ||
400 | epCfg.f.in_nak_int = 0; | ||
401 | epCfg.f.out_dbl_buf = 1; | ||
402 | epCfg.f.out_toggle_rst = 1; | ||
403 | epCfg.f.out_ack_int = 0; | ||
404 | epCfg.f.out_stall = 0; | ||
405 | epCfg.f.out_nak_int = 0; | ||
406 | |||
407 | /* buf_size is specified "in increments of 8 bytes" */ | ||
408 | epCfg.f.in_buf_size = ep_const_data[epn].hs_max_packet_size >> 3; | ||
409 | epCfg.f.out_buf_size = ep_const_data[epn].hs_max_packet_size >> 3; | ||
410 | |||
411 | epStartAddr.f.xBuffStartAddrIn = ep_const_data[epn].xyoff_in[0] >> 4; | ||
412 | epStartAddr.f.yBuffStartAddrIn = ep_const_data[epn].xyoff_in[1] >> 4; | ||
413 | epStartAddr.f.xBuffStartAddrOut = ep_const_data[epn].xyoff_out[0] >> 4; | ||
414 | epStartAddr.f.yBuffStartAddrOut = ep_const_data[epn].xyoff_out[1] >> 4; | ||
415 | |||
416 | /* allocate memory for DMA */ | ||
417 | tnetv_cppi_init_rcb(&cppi, (epn - 1)); | ||
418 | /* set up DMA queue */ | ||
419 | tnetv_cppi_init_tcb(&cppi, (epn - 1)); | ||
420 | |||
421 | /* now write out the config to the TNETV (write enable bits last) */ | ||
422 | tnetv_usb_reg_write(TNETV_USB_EPx_ADR(epn), epStartAddr.val); | ||
423 | tnetv_usb_reg_write(TNETV_USB_EPx_CFG(epn), epCfg.val); | ||
424 | tnetv_usb_reg_write(TNETV_USB_EPx_IN_CNT(epn), 0x80008000); | ||
425 | tnetv_usb_reg_write(TNETV_USB_EPx_OUT_CNT(epn), 0x80008000); | ||
426 | } | ||
427 | |||
428 | /* turn on dma engines */ | ||
429 | tnetv_usb_reg_write(TNETV_USB_TX_CTL, 1); | ||
430 | tnetv_usb_reg_write(TNETV_USB_RX_CTL, 1); | ||
431 | |||
432 | /* enable cell dma */ | ||
433 | tnetv_usb_reg_write(TNETV_USB_CELL_DMA_EN, (TNETV_USB_CELL_DMA_EN_RX | TNETV_USB_CELL_DMA_EN_TX)); | ||
434 | } | ||
435 | |||
436 | static void tnetv_udc_enable_interrupts(void) | ||
437 | { | ||
438 | UsbCtrlType usb_ctl; | ||
439 | uint8_t tx_int_en, rx_int_en; | ||
440 | int ep, chan; | ||
441 | |||
442 | /* set up the system interrupts */ | ||
443 | usb_ctl.val = tnetv_usb_reg_read(TNETV_USB_CTRL); | ||
444 | usb_ctl.f.vbus_int_en = 1; | ||
445 | usb_ctl.f.reset_int_en = 1; | ||
446 | usb_ctl.f.suspend_int_en = 1; | ||
447 | usb_ctl.f.resume_int_en = 1; | ||
448 | usb_ctl.f.ep0_in_int_en = 1; | ||
449 | usb_ctl.f.ep0_out_int_en = 1; | ||
450 | usb_ctl.f.setup_int_en = 1; | ||
451 | usb_ctl.f.setupow_int_en = 1; | ||
452 | tnetv_usb_reg_write(TNETV_USB_CTRL, usb_ctl.val); | ||
453 | |||
454 | /* Enable the DMA endpoint interrupts */ | ||
455 | tx_int_en = 0; | ||
456 | rx_int_en = 0; | ||
457 | |||
458 | for (ep = 1; ep < USB_NUM_ENDPOINTS; ep++) | ||
459 | { | ||
460 | chan = ep - 1; | ||
461 | rx_int_en |= (1 << chan); /* OUT */ | ||
462 | tx_int_en |= (1 << chan); /* IN */ | ||
463 | } | ||
464 | |||
465 | /* enable rx interrupts */ | ||
466 | tnetv_usb_reg_write(TNETV_USB_RX_INT_EN, rx_int_en); | ||
467 | /* enable tx interrupts */ | ||
468 | tnetv_usb_reg_write(TNETV_USB_TX_INT_EN, tx_int_en); | ||
469 | |||
470 | set_vlynq_irq(true); | ||
471 | } | ||
472 | |||
473 | static void tnetv_udc_disable_interrupts(void) | ||
474 | { | ||
475 | UsbCtrlType usb_ctl; | ||
476 | |||
477 | /* disable interrupts from linux */ | ||
478 | set_vlynq_irq(false); | ||
479 | |||
480 | /* Disable Endpoint Interrupts */ | ||
481 | tnetv_usb_reg_write(TNETV_USB_RX_INT_DIS, 0x3); | ||
482 | tnetv_usb_reg_write(TNETV_USB_TX_INT_DIS, 0x3); | ||
483 | |||
484 | /* Disable USB system interrupts */ | ||
485 | usb_ctl.val = tnetv_usb_reg_read(TNETV_USB_CTRL); | ||
486 | usb_ctl.f.vbus_int_en = 0; | ||
487 | usb_ctl.f.reset_int_en = 0; | ||
488 | usb_ctl.f.suspend_int_en = 0; | ||
489 | usb_ctl.f.resume_int_en = 0; | ||
490 | usb_ctl.f.ep0_in_int_en = 0; | ||
491 | usb_ctl.f.ep0_out_int_en = 0; | ||
492 | usb_ctl.f.setup_int_en = 0; | ||
493 | usb_ctl.f.setupow_int_en = 0; | ||
494 | tnetv_usb_reg_write(TNETV_USB_CTRL, usb_ctl.val); | ||
495 | } | ||
496 | |||
497 | static void tnetv_ep_halt(int epn, bool in) | ||
498 | { | ||
499 | if (in) | ||
500 | { | ||
501 | tnetv_usb_reg_write(TNETV_USB_EPx_IN_CNT(epn), 0x80008000); | ||
502 | } | ||
503 | else | ||
504 | { | ||
505 | tnetv_usb_reg_write(TNETV_USB_EPx_OUT_CNT(epn), 0x80008000); | ||
506 | } | ||
507 | } | ||
508 | |||
509 | /* Reset the TNETV usb2.0 controller and configure it to run in function mode */ | ||
510 | static void tnetv_usb_reset(void) | ||
511 | { | ||
512 | uint32_t timeout = 0; | ||
513 | int wd; | ||
514 | int ch; | ||
515 | |||
516 | /* configure function clock */ | ||
517 | tnetv_usb_reg_write(TNETV_V2USB_CLK_CFG, 0x80); | ||
518 | |||
519 | /* Reset the USB 2.0 function module */ | ||
520 | tnetv_usb_reg_write(TNETV_V2USB_RESET, 0x01); | ||
521 | |||
522 | /* now poll the module ready register until the 2.0 controller finishes resetting */ | ||
523 | while (!(tnetv_usb_reg_read(TNETV_USB_RESET_CMPL) & 0x1) && (timeout < 1000000)) | ||
524 | { | ||
525 | timeout++; | ||
526 | } | ||
527 | |||
528 | if (!(tnetv_usb_reg_read(TNETV_USB_RESET_CMPL) & 0x1)) | ||
529 | { | ||
530 | logf("tnetv105_udc: VLYNQ USB module reset failed!\n"); | ||
531 | return; | ||
532 | } | ||
533 | |||
534 | /* turn off external clock */ | ||
535 | tnetv_usb_reg_write(TNETV_V2USB_CLK_PERF, 0); | ||
536 | |||
537 | /* clear out USB data memory */ | ||
538 | for (wd = 0; wd < TNETV_EP_DATA_SIZE; wd += 4) | ||
539 | { | ||
540 | tnetv_usb_reg_write(TNETV_EP_DATA_ADDR(wd), 0); | ||
541 | } | ||
542 | |||
543 | /* clear out DMA memory */ | ||
544 | for (ch = 0; ch < TNETV_DMA_NUM_CHANNELS; ch++) | ||
545 | { | ||
546 | for (wd = 0; wd < TNETV_DMA_TX_NUM_WORDS; wd++) | ||
547 | { | ||
548 | tnetv_usb_reg_write(TNETV_DMA_TX_STATE(ch, wd), 0); | ||
549 | } | ||
550 | |||
551 | for (wd = 0; wd < TNETV_DMA_RX_NUM_WORDS; wd++) | ||
552 | { | ||
553 | |||
554 | tnetv_usb_reg_write(TNETV_DMA_RX_STATE(ch, wd), 0); | ||
555 | } | ||
556 | } | ||
557 | |||
558 | /* point VLYNQ interrupts at the pending register */ | ||
559 | VL_INTPTR = DM320_VLYNQ_INTPND_PHY; | ||
560 | |||
561 | /* point VLYNQ remote interrupts at the pending register */ | ||
562 | VL_INTPTR_R = 0; | ||
563 | |||
564 | /* clear out interrupt register */ | ||
565 | VL_INTST |= 0xFFFFFFFF; | ||
566 | |||
567 | /* enable interrupts on remote device */ | ||
568 | VL_CTRL_R |= (DM320_VLYNQ_CTRL_INT_EN); | ||
569 | VL_INTVEC30_R = 0x8180; | ||
570 | |||
571 | /* enable VLYNQ interrupts & set interrupts to trigger VLYNQ int */ | ||
572 | VL_CTRL |= (DM320_VLYNQ_CTRL_INT_LOC | DM320_VLYNQ_CTRL_INT_CFG); | ||
573 | } | ||
574 | |||
575 | static int tnetv_ep_start_xmit(int epn, void *buf, int size) | ||
576 | { | ||
577 | UsbEp0ByteCntType ep0Cnt; | ||
578 | |||
579 | if (epn == 0) | ||
580 | { | ||
581 | /* Write the Control Data packet to the EP0 IN memory area */ | ||
582 | tnetv_copy_to_data_mem(TNETV_EP_DATA_ADDR(EP0_INPKT_ADDRESS), buf, size); | ||
583 | |||
584 | /* start xmitting */ | ||
585 | ep0Cnt.val = tnetv_usb_reg_read(TNETV_USB_EP0_CNT); | ||
586 | ep0Cnt.f.in_xbuf_cnt = size; | ||
587 | ep0Cnt.f.in_xbuf_nak = 0; | ||
588 | tnetv_usb_reg_write(TNETV_USB_EP0_CNT, ep0Cnt.val); | ||
589 | } | ||
590 | else | ||
591 | { | ||
592 | dma_addr_t buffer = (dma_addr_t)buf; | ||
593 | commit_discard_dcache_range(buf, size); | ||
594 | if ((buffer >= CONFIG_SDRAM_START) && (buffer <= CONFIG_SDRAM_START + SDRAM_SIZE)) | ||
595 | { | ||
596 | if (tnetv_cppi_send(&cppi, (epn - 1), buffer, size, 0)) | ||
597 | { | ||
598 | panicf("tnetv_cppi_send() failed"); | ||
599 | } | ||
600 | } | ||
601 | else | ||
602 | { | ||
603 | panicf("USB xmit buf outside SDRAM %p", buf); | ||
604 | } | ||
605 | } | ||
606 | |||
607 | return 0; | ||
608 | } | ||
609 | |||
610 | static void tnetv_gadget_req_nuke(int epn, bool in) | ||
611 | { | ||
612 | struct ep_runtime_t *ep = &ep_runtime[epn]; | ||
613 | uint32_t old_rx_int = 0; | ||
614 | uint32_t old_tx_int = 0; | ||
615 | int ch; | ||
616 | int flags; | ||
617 | |||
618 | /* don't nuke control ep */ | ||
619 | if (epn == 0) | ||
620 | { | ||
621 | return; | ||
622 | } | ||
623 | |||
624 | flags = disable_irq_save(); | ||
625 | |||
626 | /* save and disable interrupts before nuking request */ | ||
627 | old_rx_int = tnetv_usb_reg_read(TNETV_USB_RX_INT_EN); | ||
628 | old_tx_int = tnetv_usb_reg_read(TNETV_USB_TX_INT_EN); | ||
629 | tnetv_usb_reg_write(TNETV_USB_RX_INT_DIS, 0x3); | ||
630 | tnetv_usb_reg_write(TNETV_USB_TX_INT_DIS, 0x3); | ||
631 | |||
632 | ch = epn - 1; | ||
633 | |||
634 | if (in) | ||
635 | { | ||
636 | tnetv_cppi_flush_tx_queue(&cppi, ch); | ||
637 | |||
638 | tnetv_usb_reg_write(TNETV_USB_EPx_IN_CNT(epn), 0x80008000); | ||
639 | if (ep->tx_remaining > 0) | ||
640 | { | ||
641 | usb_core_transfer_complete(epn, USB_DIR_IN, -1, 0); | ||
642 | } | ||
643 | ep->tx_buf = NULL; | ||
644 | ep->tx_remaining = 0; | ||
645 | ep->tx_size = 0; | ||
646 | |||
647 | if (ep->block) | ||
648 | { | ||
649 | semaphore_release(&ep->complete); | ||
650 | ep->block = false; | ||
651 | } | ||
652 | } | ||
653 | else | ||
654 | { | ||
655 | tnetv_cppi_flush_rx_queue(&cppi, ch); | ||
656 | |||
657 | tnetv_usb_reg_write(TNETV_USB_EPx_OUT_CNT(epn), 0x80008000); | ||
658 | if (ep->rx_remaining > 0) | ||
659 | { | ||
660 | usb_core_transfer_complete(epn, USB_DIR_OUT, -1, 0); | ||
661 | } | ||
662 | ep->rx_buf = NULL; | ||
663 | ep->rx_remaining = 0; | ||
664 | ep->rx_size = 0; | ||
665 | } | ||
666 | |||
667 | /* reenable any interrupts */ | ||
668 | tnetv_usb_reg_write(TNETV_USB_RX_INT_EN, old_rx_int); | ||
669 | tnetv_usb_reg_write(TNETV_USB_TX_INT_EN, old_tx_int); | ||
670 | |||
671 | restore_irq(flags); | ||
672 | } | ||
673 | |||
674 | static int tnetv_gadget_ep_enable(int epn, bool in) | ||
675 | { | ||
676 | UsbEpCfgCtrlType epCfg; | ||
677 | int flags; | ||
678 | |||
679 | if (epn == 0 || epn >= USB_NUM_ENDPOINTS) | ||
680 | { | ||
681 | return 0; | ||
682 | } | ||
683 | |||
684 | flags = disable_irq_save(); | ||
685 | |||
686 | /* set the maxpacket for this endpoint based on the current speed */ | ||
687 | ep_runtime[epn].max_packet_size = MAX_PACKET(epn, usb_drv_port_speed()); | ||
688 | |||
689 | /* Enable the endpoint */ | ||
690 | epCfg.val = tnetv_usb_reg_read(TNETV_USB_EPx_CFG(epn)); | ||
691 | if (in) | ||
692 | { | ||
693 | epCfg.f.in_en = 1; | ||
694 | epCfg.f.in_stall = 0; | ||
695 | epCfg.f.in_toggle_rst = 1; | ||
696 | epCfg.f.in_buf_size = ep_runtime[epn].max_packet_size >> 3; | ||
697 | tnetv_usb_reg_write(TNETV_USB_EPx_IN_CNT(epn), 0x80008000); | ||
698 | } | ||
699 | else | ||
700 | { | ||
701 | epCfg.f.out_en = 1; | ||
702 | epCfg.f.out_stall = 0; | ||
703 | epCfg.f.out_toggle_rst = 1; | ||
704 | epCfg.f.out_buf_size = ep_runtime[epn].max_packet_size >> 3; | ||
705 | tnetv_usb_reg_write(TNETV_USB_EPx_OUT_CNT(epn), 0x80008000); | ||
706 | } | ||
707 | tnetv_usb_reg_write(TNETV_USB_EPx_CFG(epn), epCfg.val); | ||
708 | |||
709 | restore_irq(flags); | ||
710 | |||
711 | return 0; | ||
712 | } | ||
713 | |||
714 | static int tnetv_gadget_ep_disable(int epn, bool in) | ||
715 | { | ||
716 | UsbEpCfgCtrlType epCfg; | ||
717 | int flags; | ||
718 | |||
719 | if (epn == 0 || epn >= USB_NUM_ENDPOINTS) | ||
720 | { | ||
721 | return 0; | ||
722 | } | ||
723 | |||
724 | flags = disable_irq_save(); | ||
725 | |||
726 | /* Disable the endpoint */ | ||
727 | epCfg.val = tnetv_usb_reg_read(TNETV_USB_EPx_CFG(epn)); | ||
728 | if (in) | ||
729 | { | ||
730 | epCfg.f.in_en = 0; | ||
731 | } | ||
732 | else | ||
733 | { | ||
734 | epCfg.f.out_en = 0; | ||
735 | } | ||
736 | tnetv_usb_reg_write(TNETV_USB_EPx_CFG(epn), epCfg.val); | ||
737 | |||
738 | /* Turn off the endpoint and unready it */ | ||
739 | tnetv_ep_halt(epn, in); | ||
740 | |||
741 | restore_irq(flags); | ||
742 | |||
743 | /* Clear out all the pending requests */ | ||
744 | tnetv_gadget_req_nuke(epn, in); | ||
745 | |||
746 | return 0; | ||
747 | } | ||
748 | |||
749 | /* TNETV udc goo | ||
750 | * Power up and enable the udc. This includes resetting the hardware, turn on the appropriate clocks | ||
751 | * and initializing things so that the first setup packet can be received. | ||
752 | */ | ||
753 | static void tnetv_udc_enable(void) | ||
754 | { | ||
755 | /* Enable M48XI crystal resonator */ | ||
756 | IO_CLK_LPCTL1 &= ~(0x01); | ||
757 | |||
758 | /* Set GIO33 as CLKOUT1B */ | ||
759 | IO_GIO_FSEL3 |= 0x0003; | ||
760 | |||
761 | if (tnetv_xcvr_on()) | ||
762 | return; | ||
763 | |||
764 | tnetv_usb_reset(); | ||
765 | |||
766 | /* BEN - RNDIS mode is assuming zlps after packets that are multiples of buffer endpoints | ||
767 | * zlps are not required by the spec and many controllers don't send them. | ||
768 | * set DMA to RNDIS mode (packet concatenation, less interrupts) | ||
769 | * tnetv_usb_reg_write(TNETV_USB_RNDIS_MODE, 0xFF); | ||
770 | */ | ||
771 | tnetv_usb_reg_write(TNETV_USB_RNDIS_MODE, 0); | ||
772 | |||
773 | tnetv_init_endpoints(); | ||
774 | |||
775 | tnetv_udc_enable_interrupts(); | ||
776 | } | ||
777 | |||
778 | static void tnetv_udc_disable(void) | ||
779 | { | ||
780 | tnetv_udc_disable_interrupts(); | ||
781 | |||
782 | tnetv_hw_reset(); | ||
783 | |||
784 | tnetv_xcvr_off(); | ||
785 | |||
786 | /* Set GIO33 as normal output, drive it low */ | ||
787 | IO_GIO_FSEL3 &= ~(0x0003); | ||
788 | IO_GIO_BITCLR2 = (1 << 1); | ||
789 | |||
790 | /* Disable M48XI crystal resonator */ | ||
791 | IO_CLK_LPCTL1 |= 0x01; | ||
792 | } | ||
793 | |||
794 | static void tnetv_udc_handle_reset(void) | ||
795 | { | ||
796 | UsbCtrlType usbCtrl; | ||
797 | |||
798 | /* disable USB interrupts */ | ||
799 | tnetv_udc_disable_interrupts(); | ||
800 | |||
801 | usbCtrl.val = tnetv_usb_reg_read(TNETV_USB_CTRL); | ||
802 | usbCtrl.f.func_addr = 0; | ||
803 | tnetv_usb_reg_write(TNETV_USB_CTRL, usbCtrl.val); | ||
804 | |||
805 | /* Reset endpoints */ | ||
806 | tnetv_init_endpoints(); | ||
807 | |||
808 | /* Re-enable interrupts */ | ||
809 | tnetv_udc_enable_interrupts(); | ||
810 | } | ||
811 | |||
812 | static void ep_write(int epn) | ||
813 | { | ||
814 | struct ep_runtime_t *ep = &ep_runtime[epn]; | ||
815 | int tx_size; | ||
816 | if (epn == 0) | ||
817 | { | ||
818 | tx_size = MIN(ep->max_packet_size, ep->tx_remaining); | ||
819 | } | ||
820 | else | ||
821 | { | ||
822 | /* DMA takes care of splitting the buffer into packets */ | ||
823 | tx_size = ep->tx_remaining; | ||
824 | } | ||
825 | tnetv_ep_start_xmit(epn, ep->tx_buf, tx_size); | ||
826 | ep->tx_remaining -= tx_size; | ||
827 | ep->tx_buf += tx_size; | ||
828 | } | ||
829 | |||
830 | static void in_interrupt(int epn) | ||
831 | { | ||
832 | struct ep_runtime_t *ep = &ep_runtime[epn]; | ||
833 | |||
834 | if (ep->tx_remaining <= 0) | ||
835 | { | ||
836 | usb_core_transfer_complete(epn, USB_DIR_IN, 0, ep->tx_size); | ||
837 | /* release semaphore for blocking transfer */ | ||
838 | if (ep->block) | ||
839 | { | ||
840 | semaphore_release(&ep->complete); | ||
841 | ep->tx_buf = NULL; | ||
842 | ep->tx_size = 0; | ||
843 | ep->tx_remaining = 0; | ||
844 | ep->block = false; | ||
845 | } | ||
846 | } | ||
847 | else if (ep->tx_buf) | ||
848 | { | ||
849 | ep_write(epn); | ||
850 | } | ||
851 | } | ||
852 | |||
853 | static void ep_read(int epn) | ||
854 | { | ||
855 | if (epn == 0) | ||
856 | { | ||
857 | UsbEp0ByteCntType ep0Cnt; | ||
858 | ep0Cnt.val = tnetv_usb_reg_read(TNETV_USB_EP0_CNT); | ||
859 | ep0Cnt.f.out_xbuf_nak = 0; | ||
860 | tnetv_usb_reg_write(TNETV_USB_EP0_CNT, ep0Cnt.val); | ||
861 | } | ||
862 | else | ||
863 | { | ||
864 | struct ep_runtime_t *ep = &ep_runtime[epn]; | ||
865 | tnetv_cppi_rx_queue_add(&cppi, (epn - 1), 0, ep->rx_remaining); | ||
866 | } | ||
867 | } | ||
868 | |||
869 | static void out_interrupt(int epn) | ||
870 | { | ||
871 | struct ep_runtime_t *ep = &ep_runtime[epn]; | ||
872 | int is_short; | ||
873 | int rcv_len; | ||
874 | |||
875 | if (epn == 0) | ||
876 | { | ||
877 | UsbEp0ByteCntType ep0Cnt; | ||
878 | |||
879 | /* get the length of the received data */ | ||
880 | ep0Cnt.val = tnetv_usb_reg_read(TNETV_USB_EP0_CNT); | ||
881 | rcv_len = ep0Cnt.f.out_xbuf_cnt; | ||
882 | |||
883 | if (rcv_len > ep->rx_remaining) | ||
884 | { | ||
885 | rcv_len = ep->rx_remaining; | ||
886 | } | ||
887 | |||
888 | tnetv_copy_from_data_mem(ep->rx_buf, TNETV_EP_DATA_ADDR(EP0_OUTPKT_ADDRESS), rcv_len); | ||
889 | ep->rx_buf += rcv_len; | ||
890 | ep->rx_remaining -= rcv_len; | ||
891 | |||
892 | /* See if we are done */ | ||
893 | is_short = rcv_len && (rcv_len < ep->max_packet_size); | ||
894 | if (is_short || (ep->rx_remaining == 0)) | ||
895 | { | ||
896 | usb_core_transfer_complete(epn, USB_DIR_OUT, 0, ep->rx_size - ep->rx_remaining); | ||
897 | ep->rx_remaining = 0; | ||
898 | ep->rx_size = 0; | ||
899 | ep->rx_buf = 0; | ||
900 | return; | ||
901 | } | ||
902 | |||
903 | /* make sure nak is cleared only if we expect more data */ | ||
904 | ep0Cnt.f.out_xbuf_nak = 0; | ||
905 | tnetv_usb_reg_write(TNETV_USB_EP0_CNT, ep0Cnt.val); | ||
906 | ep_read(epn); | ||
907 | } | ||
908 | else if (ep->rx_remaining > 0) | ||
909 | { | ||
910 | int ret, bytes_rcvd; | ||
911 | |||
912 | /* copy the data from the DMA buffers */ | ||
913 | bytes_rcvd = ep->rx_remaining; | ||
914 | ret = tnetv_cppi_rx_int_recv(&cppi, (epn - 1), &bytes_rcvd, ep->rx_buf, ep->max_packet_size); | ||
915 | if (ret == 0 || ret == -EAGAIN) | ||
916 | { | ||
917 | ep->rx_buf += bytes_rcvd; | ||
918 | ep->rx_remaining -= bytes_rcvd; | ||
919 | } | ||
920 | |||
921 | /* complete the request if we got a short packet or an error | ||
922 | * make sure we don't complete a request with zero bytes. | ||
923 | */ | ||
924 | if ((ret == 0) && (ep->rx_remaining != ep->rx_size)) | ||
925 | { | ||
926 | usb_core_transfer_complete(epn, USB_DIR_OUT, 0, ep->rx_size - ep->rx_remaining); | ||
927 | ep->rx_remaining = 0; | ||
928 | ep->rx_size = 0; | ||
929 | ep->rx_buf = 0; | ||
930 | } | ||
931 | } | ||
932 | } | ||
933 | |||
934 | static bool tnetv_handle_cppi(void) | ||
935 | { | ||
936 | int ret; | ||
937 | int ch; | ||
938 | uint32_t tx_intstatus; | ||
939 | uint32_t rx_intstatus; | ||
940 | uint32_t status; | ||
941 | int rcv_sched = 0; | ||
942 | |||
943 | rx_intstatus = tnetv_usb_reg_read(TNETV_USB_RX_INT_STATUS); | ||
944 | tx_intstatus = tnetv_usb_reg_read(TNETV_USB_TX_INT_STATUS); | ||
945 | |||
946 | /* handle any transmit interrupts */ | ||
947 | status = tx_intstatus; | ||
948 | for (ch = 0; ch < CPPI_NUM_CHANNELS && status; ch++) | ||
949 | { | ||
950 | if (status & 0x1) | ||
951 | { | ||
952 | ret = tnetv_cppi_tx_int(&cppi, ch); | ||
953 | if (ret >= 0) | ||
954 | { | ||
955 | in_interrupt(ch + 1); | ||
956 | } | ||
957 | } | ||
958 | |||
959 | status = status >> 1; | ||
960 | } | ||
961 | |||
962 | rcv_sched = 0; | ||
963 | status = rx_intstatus; | ||
964 | for (ch = 0; ch < CPPI_NUM_CHANNELS; ch++) | ||
965 | { | ||
966 | if (status & 0x1 || tnetv_cppi_rx_int_recv_check(&cppi, ch)) | ||
967 | { | ||
968 | ret = tnetv_cppi_rx_int(&cppi, ch); | ||
969 | if (ret < 0) | ||
970 | { | ||
971 | /* only an error if interrupt bit is set */ | ||
972 | logf("CPPI Rx: failed to ACK int!\n"); | ||
973 | } | ||
974 | else | ||
975 | { | ||
976 | if (tnetv_cppi_rx_int_recv_check(&cppi, ch)) | ||
977 | { | ||
978 | out_interrupt(ch + 1); | ||
979 | } | ||
980 | } | ||
981 | } | ||
982 | |||
983 | if (tnetv_cppi_rx_int_recv_check(&cppi, ch)) | ||
984 | { | ||
985 | rcv_sched = 1; | ||
986 | } | ||
987 | |||
988 | status = status >> 1; | ||
989 | } | ||
990 | |||
991 | rx_intstatus = tnetv_usb_reg_read(TNETV_USB_RX_INT_STATUS); | ||
992 | tx_intstatus = tnetv_usb_reg_read(TNETV_USB_TX_INT_STATUS); | ||
993 | |||
994 | if (rx_intstatus || tx_intstatus || rcv_sched) | ||
995 | { | ||
996 | /* Request calling again after short delay | ||
997 | * Needed when for example when OUT endpoint has pending | ||
998 | * data but the USB task did not call usb_drv_recv() yet. | ||
999 | */ | ||
1000 | return true; | ||
1001 | } | ||
1002 | return false; | ||
1003 | } | ||
1004 | |||
1005 | static int cppi_timeout_cb(struct timeout *tmo) | ||
1006 | { | ||
1007 | (void)tmo; | ||
1008 | int flags = disable_irq_save(); | ||
1009 | bool requeue = tnetv_handle_cppi(); | ||
1010 | restore_irq(flags); | ||
1011 | return requeue ? HZ/10 : 0; | ||
1012 | } | ||
1013 | |||
1014 | void VLYNQ(void) __attribute__ ((section(".icode"))); | ||
1015 | void VLYNQ(void) | ||
1016 | { | ||
1017 | UsbStatusType sysIntrStatus; | ||
1018 | UsbStatusType sysIntClear; | ||
1019 | UsbCtrlType usbCtrl; | ||
1020 | volatile uint32_t *reg; | ||
1021 | uint32_t vlynq_intr; | ||
1022 | |||
1023 | /* Clear interrupt */ | ||
1024 | IO_INTC_IRQ1 = (1 << 0); | ||
1025 | |||
1026 | /* clear out VLYNQ interrupt register */ | ||
1027 | vlynq_intr = VL_INTST; | ||
1028 | |||
1029 | if (vlynq_intr & VLYNQ_INTR_USB20) | ||
1030 | { | ||
1031 | VL_INTST = VLYNQ_INTR_USB20; | ||
1032 | |||
1033 | /* Examine system interrupt status */ | ||
1034 | sysIntrStatus.val = tnetv_usb_reg_read(TNETV_USB_STATUS); | ||
1035 | |||
1036 | if (sysIntrStatus.f.reset) | ||
1037 | { | ||
1038 | sysIntClear.val = 0; | ||
1039 | sysIntClear.f.reset = 1; | ||
1040 | tnetv_usb_reg_write(TNETV_USB_STATUS, sysIntClear.val); | ||
1041 | |||
1042 | tnetv_udc_handle_reset(); | ||
1043 | usb_core_bus_reset(); | ||
1044 | } | ||
1045 | |||
1046 | if (sysIntrStatus.f.suspend) | ||
1047 | { | ||
1048 | sysIntClear.val = 0; | ||
1049 | sysIntClear.f.suspend = 1; | ||
1050 | tnetv_usb_reg_write(TNETV_USB_STATUS, sysIntClear.val); | ||
1051 | } | ||
1052 | |||
1053 | if (sysIntrStatus.f.resume) | ||
1054 | { | ||
1055 | sysIntClear.val = 0; | ||
1056 | sysIntClear.f.resume = 1; | ||
1057 | tnetv_usb_reg_write(TNETV_USB_STATUS, sysIntClear.val); | ||
1058 | } | ||
1059 | |||
1060 | if (sysIntrStatus.f.vbus) | ||
1061 | { | ||
1062 | sysIntClear.val = 0; | ||
1063 | sysIntClear.f.vbus = 1; | ||
1064 | tnetv_usb_reg_write(TNETV_USB_STATUS, sysIntClear.val); | ||
1065 | |||
1066 | if (*((uint32_t *) TNETV_USB_IF_STATUS) & 0x40) | ||
1067 | { | ||
1068 | /* write out connect bit */ | ||
1069 | reg = (volatile uint32_t *) TNETV_USB_CTRL; | ||
1070 | *reg |= 0x80; | ||
1071 | |||
1072 | /* write to wakeup bit in clock config */ | ||
1073 | reg = (volatile uint32_t *) TNETV_V2USB_CLK_WKUP; | ||
1074 | *reg |= TNETV_V2USB_CLK_WKUP_VBUS; | ||
1075 | } | ||
1076 | else | ||
1077 | { | ||
1078 | /* clear out connect bit */ | ||
1079 | reg = (volatile uint32_t *) TNETV_USB_CTRL; | ||
1080 | *reg &= ~0x80; | ||
1081 | } | ||
1082 | } | ||
1083 | |||
1084 | if (sysIntrStatus.f.setup_ow) | ||
1085 | { | ||
1086 | sysIntrStatus.f.setup_ow = 0; | ||
1087 | sysIntClear.val = 0; | ||
1088 | sysIntClear.f.setup_ow = 1; | ||
1089 | tnetv_usb_reg_write(TNETV_USB_STATUS, sysIntClear.val); | ||
1090 | } | ||
1091 | if (sysIntrStatus.f.setup) | ||
1092 | { | ||
1093 | UsbEp0ByteCntType ep0Cnt; | ||
1094 | static struct usb_ctrlrequest setup; | ||
1095 | |||
1096 | sysIntrStatus.f.setup = 0; | ||
1097 | |||
1098 | /* Copy setup packet into buffer */ | ||
1099 | tnetv_copy_from_data_mem(&setup, TNETV_EP_DATA_ADDR(EP0_OUTPKT_ADDRESS), sizeof(setup)); | ||
1100 | |||
1101 | /* Determine next stage of the control message */ | ||
1102 | if (setup.bRequestType & USB_DIR_IN) | ||
1103 | { | ||
1104 | /* This is a control-read. Switch directions to send the response. | ||
1105 | * set the dir bit before clearing the interrupt | ||
1106 | */ | ||
1107 | usbCtrl.val = tnetv_usb_reg_read(TNETV_USB_CTRL); | ||
1108 | usbCtrl.f.dir = 1; | ||
1109 | tnetv_usb_reg_write(TNETV_USB_CTRL, usbCtrl.val); | ||
1110 | } | ||
1111 | else | ||
1112 | { | ||
1113 | /* This is a control-write. Remain using USB_DIR_OUT to receive the rest of the data. | ||
1114 | * set the NAK bits according to supplement doc | ||
1115 | */ | ||
1116 | ep0Cnt.val = 0; | ||
1117 | ep0Cnt.f.in_xbuf_nak = 1; | ||
1118 | ep0Cnt.f.out_xbuf_nak = 1; | ||
1119 | tnetv_usb_reg_write(TNETV_USB_EP0_CNT, ep0Cnt.val); | ||
1120 | |||
1121 | /* clear the dir bit before clearing the interrupt */ | ||
1122 | usbCtrl.val = tnetv_usb_reg_read(TNETV_USB_CTRL); | ||
1123 | usbCtrl.f.dir = 0; | ||
1124 | tnetv_usb_reg_write(TNETV_USB_CTRL, usbCtrl.val); | ||
1125 | } | ||
1126 | |||
1127 | /* Clear interrupt */ | ||
1128 | sysIntClear.val = 0; | ||
1129 | sysIntClear.f.setup = 1; | ||
1130 | tnetv_usb_reg_write(TNETV_USB_STATUS, sysIntClear.val); | ||
1131 | |||
1132 | if (((setup.bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) && | ||
1133 | (setup.bRequest == USB_REQ_SET_ADDRESS)) | ||
1134 | { | ||
1135 | /* Rockbox USB core works according to USB specification, i.e. | ||
1136 | * it first acknowledges the control transfer and then sets | ||
1137 | * the address. However, Linux TNETV105 driver first sets the | ||
1138 | * address and then acknowledges the transfer. At first, | ||
1139 | * it seemed that Linux driver was wrong, but it seems that | ||
1140 | * TNETV105 simply requires such order. It might be documented | ||
1141 | * in the datasheet and thus there is no comment in the Linux | ||
1142 | * driver about this. | ||
1143 | */ | ||
1144 | setup_is_set_address = true; | ||
1145 | } | ||
1146 | else | ||
1147 | { | ||
1148 | setup_is_set_address = false; | ||
1149 | } | ||
1150 | |||
1151 | /* Process control packet */ | ||
1152 | usb_core_control_request(&setup); | ||
1153 | } | ||
1154 | |||
1155 | if (sysIntrStatus.f.ep0_in_ack) | ||
1156 | { | ||
1157 | sysIntClear.val = 0; | ||
1158 | sysIntClear.f.ep0_in_ack = 1; | ||
1159 | tnetv_usb_reg_write(TNETV_USB_STATUS, sysIntClear.val); | ||
1160 | |||
1161 | in_interrupt(0); | ||
1162 | } | ||
1163 | |||
1164 | if (sysIntrStatus.f.ep0_out_ack) | ||
1165 | { | ||
1166 | sysIntClear.val = 0; | ||
1167 | sysIntClear.f.ep0_out_ack = 1; | ||
1168 | tnetv_usb_reg_write(TNETV_USB_STATUS, sysIntClear.val); | ||
1169 | |||
1170 | out_interrupt(0); | ||
1171 | } | ||
1172 | } | ||
1173 | |||
1174 | if (vlynq_intr & VLYNQ_INTR_CPPI) | ||
1175 | { | ||
1176 | static struct timeout cppi_timeout; | ||
1177 | |||
1178 | VL_INTST = VLYNQ_INTR_CPPI; | ||
1179 | |||
1180 | if (tnetv_handle_cppi()) | ||
1181 | { | ||
1182 | timeout_register(&cppi_timeout, cppi_timeout_cb, HZ/10, 0); | ||
1183 | } | ||
1184 | } | ||
1185 | } | ||
1186 | |||
1187 | void usb_charging_maxcurrent_change(int maxcurrent) | ||
1188 | { | ||
1189 | uint32_t wreg; | ||
1190 | |||
1191 | if (!is_tnetv_reset_high()) | ||
1192 | { | ||
1193 | /* TNETV105 is in reset, it is not getting more than 100 mA */ | ||
1194 | return; | ||
1195 | } | ||
1196 | |||
1197 | wreg = tnetv_usb_reg_read(TNETV_V2USB_GPIO_DOUT); | ||
1198 | if (maxcurrent < 500) | ||
1199 | { | ||
1200 | /* set tnetv into low power mode */ | ||
1201 | tnetv_usb_reg_write(TNETV_V2USB_GPIO_DOUT, (wreg & ~0x2)); | ||
1202 | } | ||
1203 | else | ||
1204 | { | ||
1205 | /* set tnetv into high power mode */ | ||
1206 | tnetv_usb_reg_write(TNETV_V2USB_GPIO_DOUT, (wreg | 0x2)); | ||
1207 | } | ||
1208 | } | ||
1209 | |||
1210 | void usb_drv_init(void) | ||
1211 | { | ||
1212 | int epn; | ||
1213 | memset(ep_runtime, 0, sizeof(ep_runtime)); | ||
1214 | ep_runtime[0].max_packet_size = EP0_MAX_PACKET_SIZE; | ||
1215 | ep_runtime[0].in_allocated = true; | ||
1216 | ep_runtime[0].out_allocated = true; | ||
1217 | for (epn = 0; epn < USB_NUM_ENDPOINTS; epn++) | ||
1218 | { | ||
1219 | semaphore_init(&ep_runtime[epn].complete, 1, 0); | ||
1220 | } | ||
1221 | tnetv_cppi_init(&cppi); | ||
1222 | tnetv_udc_enable(); | ||
1223 | } | ||
1224 | |||
1225 | void usb_drv_exit(void) | ||
1226 | { | ||
1227 | tnetv_udc_disable(); | ||
1228 | tnetv_cppi_cleanup(&cppi); | ||
1229 | } | ||
1230 | |||
1231 | void usb_drv_stall(int endpoint, bool stall, bool in) | ||
1232 | { | ||
1233 | int epn = EP_NUM(endpoint); | ||
1234 | |||
1235 | if (epn == 0) | ||
1236 | { | ||
1237 | UsbEp0CtrlType ep0Ctrl; | ||
1238 | ep0Ctrl.val = tnetv_usb_reg_read(TNETV_USB_EP0_CFG); | ||
1239 | if (in) | ||
1240 | { | ||
1241 | ep0Ctrl.f.in_stall = stall ? 1 : 0; | ||
1242 | } | ||
1243 | else | ||
1244 | { | ||
1245 | ep0Ctrl.f.out_stall = stall ? 1 : 0; | ||
1246 | } | ||
1247 | tnetv_usb_reg_write(TNETV_USB_EP0_CFG, ep0Ctrl.val); | ||
1248 | } | ||
1249 | else | ||
1250 | { | ||
1251 | UsbEpCfgCtrlType epCfg; | ||
1252 | epCfg.val = tnetv_usb_reg_read(TNETV_USB_EPx_CFG(epn)); | ||
1253 | if (in) | ||
1254 | { | ||
1255 | epCfg.f.in_stall = stall ? 1 : 0; | ||
1256 | } | ||
1257 | else | ||
1258 | { | ||
1259 | epCfg.f.out_stall = stall ? 1 : 0; | ||
1260 | } | ||
1261 | tnetv_usb_reg_write(TNETV_USB_EPx_CFG(epn), epCfg.val); | ||
1262 | } | ||
1263 | } | ||
1264 | |||
1265 | bool usb_drv_stalled(int endpoint, bool in) | ||
1266 | { | ||
1267 | int epn = EP_NUM(endpoint); | ||
1268 | if (epn == 0) | ||
1269 | { | ||
1270 | UsbEp0CtrlType ep0Ctrl; | ||
1271 | ep0Ctrl.val = tnetv_usb_reg_read(TNETV_USB_EP0_CFG); | ||
1272 | if (in) | ||
1273 | { | ||
1274 | return ep0Ctrl.f.in_stall; | ||
1275 | } | ||
1276 | else | ||
1277 | { | ||
1278 | return ep0Ctrl.f.out_stall; | ||
1279 | } | ||
1280 | } | ||
1281 | else | ||
1282 | { | ||
1283 | UsbEpCfgCtrlType epCfg; | ||
1284 | epCfg.val = tnetv_usb_reg_read(TNETV_USB_EPx_CFG(epn)); | ||
1285 | if (in) | ||
1286 | { | ||
1287 | return epCfg.f.in_stall; | ||
1288 | } | ||
1289 | else | ||
1290 | { | ||
1291 | return epCfg.f.out_stall; | ||
1292 | } | ||
1293 | } | ||
1294 | } | ||
1295 | |||
1296 | static int _usb_drv_send(int endpoint, void *ptr, int length, bool block) | ||
1297 | { | ||
1298 | int epn = EP_NUM(endpoint); | ||
1299 | struct ep_runtime_t *ep; | ||
1300 | int flags; | ||
1301 | |||
1302 | ep = &ep_runtime[epn]; | ||
1303 | |||
1304 | flags = disable_irq_save(); | ||
1305 | ep->tx_buf = ptr; | ||
1306 | ep->tx_remaining = ep->tx_size = length; | ||
1307 | ep->block = block; | ||
1308 | ep_write(epn); | ||
1309 | restore_irq(flags); | ||
1310 | |||
1311 | /* wait for transfer to end */ | ||
1312 | if (block) | ||
1313 | { | ||
1314 | semaphore_wait(&ep->complete, TIMEOUT_BLOCK); | ||
1315 | } | ||
1316 | return 0; | ||
1317 | } | ||
1318 | |||
1319 | int usb_drv_send(int endpoint, void* ptr, int length) | ||
1320 | { | ||
1321 | if ((EP_NUM(endpoint) == 0) && (length == 0)) | ||
1322 | { | ||
1323 | if (setup_is_set_address) | ||
1324 | { | ||
1325 | /* usb_drv_set_address() will call us later */ | ||
1326 | return 0; | ||
1327 | } | ||
1328 | /* HACK: Do not wait for status stage ZLP | ||
1329 | * This seems to be the only way to get through SET ADDRESS | ||
1330 | * and retain ability to receive SETUP packets. | ||
1331 | */ | ||
1332 | return _usb_drv_send(endpoint, ptr, length, false); | ||
1333 | } | ||
1334 | return _usb_drv_send(endpoint, ptr, length, false); | ||
1335 | } | ||
1336 | |||
1337 | int usb_drv_send_nonblocking(int endpoint, void* ptr, int length) | ||
1338 | { | ||
1339 | return _usb_drv_send(endpoint, ptr, length, false); | ||
1340 | } | ||
1341 | |||
1342 | int usb_drv_recv(int endpoint, void* ptr, int length) | ||
1343 | { | ||
1344 | int epn = EP_NUM(endpoint); | ||
1345 | struct ep_runtime_t *ep; | ||
1346 | int flags; | ||
1347 | |||
1348 | ep = &ep_runtime[epn]; | ||
1349 | |||
1350 | flags = disable_irq_save(); | ||
1351 | ep->rx_buf = ptr; | ||
1352 | ep->rx_remaining = ep->rx_size = length; | ||
1353 | ep_read(epn); | ||
1354 | restore_irq(flags); | ||
1355 | |||
1356 | return 0; | ||
1357 | } | ||
1358 | |||
1359 | void usb_drv_ack(struct usb_ctrlrequest* req); | ||
1360 | |||
1361 | void usb_drv_set_address(int address) | ||
1362 | { | ||
1363 | UsbCtrlType usbCtrl; | ||
1364 | usbCtrl.val = tnetv_usb_reg_read(TNETV_USB_CTRL); | ||
1365 | usbCtrl.f.func_addr = address; | ||
1366 | tnetv_usb_reg_write(TNETV_USB_CTRL, usbCtrl.val); | ||
1367 | |||
1368 | /* This seems to be the only working order */ | ||
1369 | setup_is_set_address = false; | ||
1370 | usb_drv_send(EP_CONTROL, NULL, 0); | ||
1371 | usb_drv_cancel_all_transfers(); | ||
1372 | } | ||
1373 | |||
1374 | /* return port speed FS=0, HS=1 */ | ||
1375 | int usb_drv_port_speed(void) | ||
1376 | { | ||
1377 | UsbCtrlType usbCtrl; | ||
1378 | usbCtrl.val = tnetv_usb_reg_read(TNETV_USB_CTRL); | ||
1379 | return usbCtrl.f.speed ? 1 : 0; | ||
1380 | } | ||
1381 | |||
1382 | void usb_drv_cancel_all_transfers(void) | ||
1383 | { | ||
1384 | int epn; | ||
1385 | if (setup_is_set_address) | ||
1386 | { | ||
1387 | return; | ||
1388 | } | ||
1389 | for (epn = 1; epn < USB_NUM_ENDPOINTS; epn++) | ||
1390 | { | ||
1391 | tnetv_gadget_req_nuke(epn, false); | ||
1392 | tnetv_gadget_req_nuke(epn, true); | ||
1393 | } | ||
1394 | } | ||
1395 | |||
1396 | static const uint8_t TestPacket[] = | ||
1397 | { | ||
1398 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
1399 | 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, | ||
1400 | 0xAA, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, | ||
1401 | 0xEE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | ||
1402 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xBF, 0xDF, | ||
1403 | 0xEF, 0xF7, 0xFB, 0xFD, 0xFC, 0x7E, 0xBF, 0xDF, | ||
1404 | 0xEF, 0xF7, 0xFB, 0xFD, 0x7E | ||
1405 | }; | ||
1406 | |||
1407 | void usb_drv_set_test_mode(int mode) | ||
1408 | { | ||
1409 | UsbCtrlType usbCtrl; | ||
1410 | if (mode == 4) | ||
1411 | { | ||
1412 | volatile uint32_t *reg; | ||
1413 | UsbEp0ByteCntType ep0Cnt; | ||
1414 | UsbEp0CtrlType ep0Cfg; | ||
1415 | uint8_t *addr; | ||
1416 | size_t i; | ||
1417 | |||
1418 | /* set up the xnak for ep0 */ | ||
1419 | reg = (volatile uint32_t *) TNETV_USB_EP0_CNT; | ||
1420 | *reg &= ~0xFF; | ||
1421 | |||
1422 | /* Setup endpoint zero */ | ||
1423 | ep0Cfg.val = 0; | ||
1424 | ep0Cfg.f.buf_size = EP0_BUF_SIZE_64; /* must be 64 bytes for USB 2.0 */ | ||
1425 | ep0Cfg.f.dbl_buf = 0; | ||
1426 | ep0Cfg.f.in_en = 1; | ||
1427 | ep0Cfg.f.in_int_en = 0; | ||
1428 | ep0Cfg.f.out_en = 0; | ||
1429 | ep0Cfg.f.out_int_en = 0; | ||
1430 | tnetv_usb_reg_write(TNETV_USB_EP0_CFG, ep0Cfg.val); | ||
1431 | |||
1432 | addr = (uint8_t *) TNETV_EP_DATA_ADDR(EP0_INPKT_ADDRESS); | ||
1433 | for (i = 0; i < sizeof(TestPacket); i++) | ||
1434 | { | ||
1435 | *addr++ = TestPacket[i]; | ||
1436 | } | ||
1437 | |||
1438 | /* start xmitting (only 53 bytes are used) */ | ||
1439 | ep0Cnt.val = 0; | ||
1440 | ep0Cnt.f.in_xbuf_cnt = 53; | ||
1441 | ep0Cnt.f.in_xbuf_nak = 0; | ||
1442 | tnetv_usb_reg_write(TNETV_USB_EP0_CNT, ep0Cnt.val); | ||
1443 | } | ||
1444 | |||
1445 | /* write the config */ | ||
1446 | usbCtrl.val = tnetv_usb_reg_read(TNETV_USB_CTRL); | ||
1447 | usbCtrl.f.hs_test_mode = mode; | ||
1448 | usbCtrl.f.dir = 1; | ||
1449 | tnetv_usb_reg_write(TNETV_USB_CTRL, usbCtrl.val); | ||
1450 | } | ||
1451 | |||
1452 | int usb_drv_request_endpoint(int type, int dir) | ||
1453 | { | ||
1454 | int epn; | ||
1455 | for (epn = 1; epn < USB_NUM_ENDPOINTS; epn++) | ||
1456 | { | ||
1457 | if (type == ep_const_data[epn].type) | ||
1458 | { | ||
1459 | if ((dir == USB_DIR_IN) && (!ep_runtime[epn].in_allocated)) | ||
1460 | { | ||
1461 | ep_runtime[epn].in_allocated = true; | ||
1462 | tnetv_gadget_ep_enable(epn, true); | ||
1463 | return epn | USB_DIR_IN; | ||
1464 | } | ||
1465 | if ((dir == USB_DIR_OUT) && (!ep_runtime[epn].out_allocated)) | ||
1466 | { | ||
1467 | ep_runtime[epn].out_allocated = true; | ||
1468 | tnetv_gadget_ep_enable(epn, false); | ||
1469 | return epn | USB_DIR_OUT; | ||
1470 | } | ||
1471 | } | ||
1472 | } | ||
1473 | return -1; | ||
1474 | } | ||
1475 | |||
1476 | void usb_drv_release_endpoint(int ep) | ||
1477 | { | ||
1478 | int epn = EP_NUM(ep); | ||
1479 | if (EP_DIR(ep) == DIR_IN) | ||
1480 | { | ||
1481 | ep_runtime[epn].in_allocated = false; | ||
1482 | tnetv_gadget_ep_disable(epn, true); | ||
1483 | } | ||
1484 | else | ||
1485 | { | ||
1486 | ep_runtime[epn].out_allocated = false; | ||
1487 | tnetv_gadget_ep_disable(epn, false); | ||
1488 | } | ||
1489 | } | ||