diff options
-rw-r--r-- | bootloader/sansaconnect.c | 20 | ||||
-rw-r--r-- | firmware/SOURCES | 2 | ||||
-rw-r--r-- | firmware/export/config.h | 6 | ||||
-rw-r--r-- | firmware/export/config/sansaconnect.h | 11 | ||||
-rw-r--r-- | firmware/target/arm/tms320dm320/sansa-connect/tnetv105_cppi.c | 1044 | ||||
-rw-r--r-- | firmware/target/arm/tms320dm320/sansa-connect/tnetv105_cppi.h | 144 | ||||
-rw-r--r-- | firmware/target/arm/tms320dm320/sansa-connect/tnetv105_usb_drv.c | 1489 | ||||
-rw-r--r-- | firmware/target/arm/tms320dm320/sansa-connect/tnetv105_usb_drv.h | 335 | ||||
-rw-r--r-- | firmware/target/arm/tms320dm320/sansa-connect/usb-sansaconnect.c | 67 | ||||
-rw-r--r-- | firmware/target/arm/tms320dm320/system-dm320.c | 7 | ||||
-rw-r--r-- | firmware/target/arm/tms320dm320/system-target.h | 1 |
11 files changed, 3066 insertions, 60 deletions
diff --git a/bootloader/sansaconnect.c b/bootloader/sansaconnect.c index a87b23745f..c5dbca717d 100644 --- a/bootloader/sansaconnect.c +++ b/bootloader/sansaconnect.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * \/ \/ \/ \/ \/ | 7 | * \/ \/ \/ \/ \/ |
8 | * $Id: $ | 8 | * $Id: $ |
9 | * | 9 | * |
10 | * Copyright (C) 2011 by Tomasz Moń | 10 | * Copyright (C) 2011-2021 by Tomasz Moń |
11 | * | 11 | * |
12 | * All files in this archive are subject to the GNU General Public License. | 12 | * All files in this archive are subject to the GNU General Public License. |
13 | * See the file COPYING in the source tree root for full license agreement. | 13 | * See the file COPYING in the source tree root for full license agreement. |
@@ -32,6 +32,7 @@ | |||
32 | #include "uart-target.h" | 32 | #include "uart-target.h" |
33 | #include "power.h" | 33 | #include "power.h" |
34 | #include "loader_strerror.h" | 34 | #include "loader_strerror.h" |
35 | #include "usb.h" | ||
35 | 36 | ||
36 | #define FLASH_BASE 0x00100000 | 37 | #define FLASH_BASE 0x00100000 |
37 | #define PARAMETERS_FLASH_OFFSET 0x00010000 | 38 | #define PARAMETERS_FLASH_OFFSET 0x00010000 |
@@ -206,6 +207,8 @@ void main(void) | |||
206 | 207 | ||
207 | printf("Rockbox boot loader"); | 208 | printf("Rockbox boot loader"); |
208 | printf("Version %s", rbversion); | 209 | printf("Version %s", rbversion); |
210 | usb_init(); | ||
211 | usb_start_monitoring(); | ||
209 | 212 | ||
210 | clear_recoverzap(); | 213 | clear_recoverzap(); |
211 | 214 | ||
@@ -215,6 +218,17 @@ void main(void) | |||
215 | 218 | ||
216 | filesystem_init(); | 219 | filesystem_init(); |
217 | 220 | ||
221 | if (usb_detect() == USB_INSERTED) | ||
222 | { | ||
223 | usb_enable(true); | ||
224 | while (usb_detect() == USB_INSERTED) | ||
225 | { | ||
226 | sleep(HZ); | ||
227 | storage_spin(); | ||
228 | } | ||
229 | usb_enable(false); | ||
230 | } | ||
231 | |||
218 | ret = disk_mount_all(); | 232 | ret = disk_mount_all(); |
219 | if (ret <= 0) | 233 | if (ret <= 0) |
220 | error(EDISK, ret, true); | 234 | error(EDISK, ret, true); |
@@ -269,8 +283,8 @@ void main(void) | |||
269 | ret = kernel_entry(); | 283 | ret = kernel_entry(); |
270 | printf("FAILED!"); | 284 | printf("FAILED!"); |
271 | } | 285 | } |
272 | 286 | ||
273 | storage_sleepnow(); | 287 | storage_sleepnow(); |
274 | 288 | ||
275 | while(1); | 289 | while(1); |
276 | } | 290 | } |
diff --git a/firmware/SOURCES b/firmware/SOURCES index 0d93439ff8..4c1fa7bf46 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES | |||
@@ -1264,6 +1264,8 @@ target/arm/tms320dm320/sansa-connect/lcd-sansaconnect.c | |||
1264 | target/arm/tms320dm320/sansa-connect/adc-sansaconnect.c | 1264 | target/arm/tms320dm320/sansa-connect/adc-sansaconnect.c |
1265 | target/arm/tms320dm320/sansa-connect/power-sansaconnect.c | 1265 | target/arm/tms320dm320/sansa-connect/power-sansaconnect.c |
1266 | target/arm/tms320dm320/sansa-connect/powermgmt-sansaconnect.c | 1266 | target/arm/tms320dm320/sansa-connect/powermgmt-sansaconnect.c |
1267 | target/arm/tms320dm320/sansa-connect/tnetv105_cppi.c | ||
1268 | target/arm/tms320dm320/sansa-connect/tnetv105_usb_drv.c | ||
1267 | target/arm/tms320dm320/sansa-connect/usb-sansaconnect.c | 1269 | target/arm/tms320dm320/sansa-connect/usb-sansaconnect.c |
1268 | target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c | 1270 | target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c |
1269 | target/arm/tms320dm320/sansa-connect/backlight-sansaconnect.c | 1271 | target/arm/tms320dm320/sansa-connect/backlight-sansaconnect.c |
diff --git a/firmware/export/config.h b/firmware/export/config.h index b758bef49d..0242045450 100644 --- a/firmware/export/config.h +++ b/firmware/export/config.h | |||
@@ -938,6 +938,9 @@ Lyre prototype 1 */ | |||
938 | #define USB_DETECT_BY_REQUEST | 938 | #define USB_DETECT_BY_REQUEST |
939 | #elif CONFIG_USBOTG == USBOTG_RK27XX | 939 | #elif CONFIG_USBOTG == USBOTG_RK27XX |
940 | #define USB_DETECT_BY_REQUEST | 940 | #define USB_DETECT_BY_REQUEST |
941 | #elif CONFIG_USBOTG == USBOTG_TNETV105 | ||
942 | #define USB_STATUS_BY_EVENT | ||
943 | #define USB_DETECT_BY_REQUEST | ||
941 | #endif /* CONFIG_USB == */ | 944 | #endif /* CONFIG_USB == */ |
942 | #endif /* HAVE_USBSTACK */ | 945 | #endif /* HAVE_USBSTACK */ |
943 | 946 | ||
@@ -1171,7 +1174,8 @@ Lyre prototype 1 */ | |||
1171 | (CONFIG_USBOTG == USBOTG_M66591) || \ | 1174 | (CONFIG_USBOTG == USBOTG_M66591) || \ |
1172 | (CONFIG_USBOTG == USBOTG_DESIGNWARE) || \ | 1175 | (CONFIG_USBOTG == USBOTG_DESIGNWARE) || \ |
1173 | (CONFIG_USBOTG == USBOTG_AS3525) || \ | 1176 | (CONFIG_USBOTG == USBOTG_AS3525) || \ |
1174 | (CONFIG_USBOTG == USBOTG_RK27XX) | 1177 | (CONFIG_USBOTG == USBOTG_RK27XX) || \ |
1178 | (CONFIG_USBOTG == USBOTG_TNETV105) | ||
1175 | #define USB_HAS_BULK | 1179 | #define USB_HAS_BULK |
1176 | #define USB_HAS_INTERRUPT | 1180 | #define USB_HAS_INTERRUPT |
1177 | #elif defined(CPU_TCC780X) | 1181 | #elif defined(CPU_TCC780X) |
diff --git a/firmware/export/config/sansaconnect.h b/firmware/export/config/sansaconnect.h index 465a576664..5ae2be1b16 100644 --- a/firmware/export/config/sansaconnect.h +++ b/firmware/export/config/sansaconnect.h | |||
@@ -182,11 +182,18 @@ | |||
182 | /* Offset ( in the firmware file's header ) to the real data */ | 182 | /* Offset ( in the firmware file's header ) to the real data */ |
183 | #define FIRMWARE_OFFSET_FILE_DATA 8 | 183 | #define FIRMWARE_OFFSET_FILE_DATA 8 |
184 | 184 | ||
185 | #if 0 | 185 | /* Hardware controlled charging */ |
186 | #define CONFIG_CHARGING CHARGING_SIMPLE | ||
187 | |||
188 | #define CONFIG_USBOTG USBOTG_TNETV105 | ||
189 | |||
186 | #define HAVE_USBSTACK | 190 | #define HAVE_USBSTACK |
191 | #define HAVE_USB_POWER | ||
192 | #define HAVE_USB_CHARGING_ENABLE | ||
193 | #define HAVE_BOOTLOADER_USB_MODE | ||
187 | #define USB_VENDOR_ID 0x0781 | 194 | #define USB_VENDOR_ID 0x0781 |
188 | #define USB_PRODUCT_ID 0x7480 | 195 | #define USB_PRODUCT_ID 0x7480 |
189 | #endif | 196 | #define USB_NUM_ENDPOINTS 5 |
190 | 197 | ||
191 | #define INCLUDE_TIMEOUT_API | 198 | #define INCLUDE_TIMEOUT_API |
192 | 199 | ||
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/tnetv105_cppi.c b/firmware/target/arm/tms320dm320/sansa-connect/tnetv105_cppi.c new file mode 100644 index 0000000000..93477bed9e --- /dev/null +++ b/firmware/target/arm/tms320dm320/sansa-connect/tnetv105_cppi.c | |||
@@ -0,0 +1,1044 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: $ | ||
9 | * | ||
10 | * Copyright (C) 2021 by Tomasz Moń | ||
11 | * Copied with minor modifications from Sansa Connect Linux driver | ||
12 | * Copyright (c) 2005,2006 Zermatt Systems, Inc. | ||
13 | * Written by: Ben Bostwick | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or | ||
16 | * modify it under the terms of the GNU General Public License | ||
17 | * as published by the Free Software Foundation; either version 2 | ||
18 | * of the License, or (at your option) any later version. | ||
19 | * | ||
20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
21 | * KIND, either express or implied. | ||
22 | * | ||
23 | ****************************************************************************/ | ||
24 | |||
25 | #include <string.h> | ||
26 | #include "config.h" | ||
27 | #include "system.h" | ||
28 | #include "kernel.h" | ||
29 | #include "panic.h" | ||
30 | #include "logf.h" | ||
31 | #include "tnetv105_usb_drv.h" | ||
32 | #include "tnetv105_cppi.h" | ||
33 | |||
34 | /* This file is pretty much directly copied from the Sansa Connect | ||
35 | * Linux kernel source code. This is because the functionality is | ||
36 | * nicely separated from actual kernel specific code and CPPI seems | ||
37 | * complex (atleast without access to the datasheet). | ||
38 | * | ||
39 | * The only non cosmetic change was changing the dynamic allocations | ||
40 | * to static allocations. | ||
41 | * | ||
42 | * It seems that the only way to get interrupt on non-control endpoint | ||
43 | * acticity is to use the CPPI. This sounds like a plausible explanation | ||
44 | * for the fake DMA buffers mentioned in CPPI code. | ||
45 | */ | ||
46 | |||
47 | /* Translate Linux consistent_sync() to Rockbox functions */ | ||
48 | #define DMA_TO_DEVICE commit_discard_dcache_range | ||
49 | #define DMA_FROM_DEVICE discard_dcache_range | ||
50 | #define consistent_sync(ptr, size, func) func(ptr, size) | ||
51 | /* Rockbox TMS320DM320 crt0.S maps everything to itself */ | ||
52 | #define __virt_to_phys(ptr) ptr | ||
53 | #define __phys_to_virt(ptr) ptr | ||
54 | |||
55 | // CPPI functions | ||
56 | #define CB_SOF_BIT (1<<31) | ||
57 | #define CB_EOF_BIT (1<<30) | ||
58 | #define CB_OWNERSHIP_BIT (1<<29) | ||
59 | #define CB_EOQ_BIT (1<<28) | ||
60 | #define CB_ZLP_GARBAGE (1<<23) | ||
61 | #define CB_SIZE_MASK 0x0000ffff | ||
62 | #define CB_OFFSET_MASK 0xffff0000 | ||
63 | #define TEARDOWN_VAL 0xfffffffc | ||
64 | |||
65 | #define MAX_BUF_SIZE 512 | ||
66 | |||
67 | #define CPPI_DMA_RX_BUF_SIZE (MAX_BUF_SIZE * CPPI_RX_NUM_BUFS) | ||
68 | |||
69 | static uint8_t *dma_recv_buf[CPPI_NUM_CHANNELS]; | ||
70 | static uint8_t ch0_rx_buf[CPPI_DMA_RX_BUF_SIZE]; | ||
71 | static uint8_t ch1_rx_buf[CPPI_DMA_RX_BUF_SIZE]; | ||
72 | |||
73 | #if USB_CPPI_LOGGING | ||
74 | #define cppi_log_event0(msg) usb_log_event(msg, LOG_EVENT_D0, 0, 0, 0, 0) | ||
75 | #define cppi_log_event1(msg, data0) usb_log_event(msg, LOG_EVENT_D1, data0, 0, 0, 0) | ||
76 | #define cppi_log_event2(msg, data0, data1) usb_log_event(msg, LOG_EVENT_D2, data0, data1, 0, 0) | ||
77 | #define cppi_log_event3(msg, data0, data1, data2) usb_log_event(msg, LOG_EVENT_D3, data0, data1, data2, 0) | ||
78 | #define cppi_log_event4(msg, data0, data1, data2, data3) usb_log_event(msg, LOG_EVENT_D4, data0, data1, data2, data3) | ||
79 | #else | ||
80 | #define cppi_log_event0(x) | ||
81 | #define cppi_log_event1(x, y) | ||
82 | #define cppi_log_event2(x, y, z) | ||
83 | #define cppi_log_event3(x, y, z, w) | ||
84 | #define cppi_log_event4(x, y, z, w, u) | ||
85 | #endif | ||
86 | |||
87 | /* | ||
88 | * This function processes transmit interrupts. It traverses the | ||
89 | * transmit buffer queue, detecting sent data buffers | ||
90 | * | ||
91 | * @return 0 if OK, non-zero otherwise. | ||
92 | */ | ||
93 | int tnetv_cppi_tx_int(struct cppi_info *cppi, int ch) | ||
94 | { | ||
95 | cppi_tcb *CurrentTcb,*LastTcbProcessed; | ||
96 | uint32_t TxFrameStatus; | ||
97 | cppi_txcntl *pTxCtl = &cppi->tx_ctl[ch]; | ||
98 | int bytes_sent = 0; | ||
99 | |||
100 | cppi_log_event1("[cppi]TxInt ch", ch); | ||
101 | |||
102 | CurrentTcb = pTxCtl->TxActQueueHead; | ||
103 | |||
104 | if (CurrentTcb == 0) | ||
105 | { | ||
106 | cppi_log_event0("[cppi] tx int: no current tcb"); | ||
107 | return -1; | ||
108 | } | ||
109 | |||
110 | // sync up the tcb from memory | ||
111 | consistent_sync(CurrentTcb, sizeof(*CurrentTcb), DMA_FROM_DEVICE); | ||
112 | |||
113 | TxFrameStatus = CurrentTcb->mode; | ||
114 | LastTcbProcessed = NULL; | ||
115 | |||
116 | cppi_log_event3("[cppi] int tcb status", (uint32_t) CurrentTcb, TxFrameStatus, CurrentTcb->Off_BLen); | ||
117 | |||
118 | while(CurrentTcb && (TxFrameStatus & CB_OWNERSHIP_BIT) == 0) | ||
119 | { | ||
120 | cppi_log_event3("[cppi] tx int: tcb (mode) (len)", (uint32_t) CurrentTcb, CurrentTcb->mode, CurrentTcb->Off_BLen); | ||
121 | |||
122 | // calculate the amount of bytes sent. | ||
123 | // don't count the fake ZLP byte | ||
124 | if (CurrentTcb->Off_BLen > 0x1) | ||
125 | { | ||
126 | bytes_sent += CurrentTcb->Off_BLen & 0xFFFF; | ||
127 | } | ||
128 | |||
129 | if (CurrentTcb->mode & CB_EOQ_BIT) | ||
130 | { | ||
131 | if (CurrentTcb->Next) | ||
132 | { | ||
133 | cppi_log_event0(" [cppi] misqueue!"); | ||
134 | |||
135 | // Misqueued packet | ||
136 | tnetv_usb_reg_write(TNETV_DMA_TX_STATE(ch, TNETV_CPPI_TX_WORD_HDP), CurrentTcb->HNext); | ||
137 | } | ||
138 | else | ||
139 | { | ||
140 | cppi_log_event0("[cppi] eoq"); | ||
141 | |||
142 | /* Tx End of Queue */ | ||
143 | pTxCtl->TxActive = 0; | ||
144 | } | ||
145 | } | ||
146 | |||
147 | cppi_log_event1("[cppi]SendComplete: ", CurrentTcb->Off_BLen & 0xFFFF); | ||
148 | |||
149 | // Write the completion pointer | ||
150 | tnetv_usb_reg_write(TNETV_DMA_TX_CMPL(ch), __dma_to_vlynq_phys(CurrentTcb->dma_handle)); | ||
151 | |||
152 | |||
153 | LastTcbProcessed = CurrentTcb; | ||
154 | CurrentTcb = CurrentTcb->Next; | ||
155 | |||
156 | // clean up TCB fields | ||
157 | LastTcbProcessed->HNext = 0; | ||
158 | LastTcbProcessed->Next = 0; | ||
159 | LastTcbProcessed->BufPtr = 0; | ||
160 | LastTcbProcessed->Off_BLen = 0; | ||
161 | LastTcbProcessed->mode = 0; | ||
162 | LastTcbProcessed->Eop = 0; | ||
163 | |||
164 | /* Push Tcb(s) back onto the list */ | ||
165 | if (pTxCtl->TcbPool) | ||
166 | { | ||
167 | LastTcbProcessed->Next = pTxCtl->TcbPool->Next; | ||
168 | pTxCtl->TcbPool->Next = LastTcbProcessed; | ||
169 | } | ||
170 | else | ||
171 | { | ||
172 | pTxCtl->TcbPool = LastTcbProcessed; | ||
173 | } | ||
174 | |||
175 | consistent_sync(LastTcbProcessed, sizeof(*LastTcbProcessed), DMA_TO_DEVICE); | ||
176 | |||
177 | // get the status of the next packet | ||
178 | if (CurrentTcb) | ||
179 | { | ||
180 | // sync up the tcb from memory | ||
181 | consistent_sync(CurrentTcb, sizeof(*CurrentTcb), DMA_FROM_DEVICE); | ||
182 | |||
183 | TxFrameStatus = CurrentTcb->mode; | ||
184 | } | ||
185 | |||
186 | |||
187 | } | ||
188 | |||
189 | pTxCtl->TxActQueueHead = CurrentTcb; | ||
190 | |||
191 | if (!LastTcbProcessed) | ||
192 | { | ||
193 | cppi_log_event1(" [cppi]No Tx packets serviced on int! ch", ch); | ||
194 | return -1; | ||
195 | } | ||
196 | |||
197 | return bytes_sent; | ||
198 | } | ||
199 | |||
200 | int tnetv_cppi_flush_tx_queue(struct cppi_info *cppi, int ch) | ||
201 | { | ||
202 | cppi_txcntl *pTxCtl = &cppi->tx_ctl[ch]; | ||
203 | cppi_tcb *tcb, *next_tcb; | ||
204 | |||
205 | tcb = pTxCtl->TxActQueueHead; | ||
206 | |||
207 | cppi_log_event1("[cppi] flush TX ", (uint32_t) pTxCtl->TxActQueueHead); | ||
208 | |||
209 | while (tcb) | ||
210 | { | ||
211 | tcb->mode = 0; | ||
212 | tcb->BufPtr = 0; | ||
213 | tcb->Off_BLen = 0; | ||
214 | tcb->Eop = 0; | ||
215 | tcb->HNext = 0; | ||
216 | |||
217 | next_tcb = tcb->Next; | ||
218 | |||
219 | tcb->Next = pTxCtl->TcbPool; | ||
220 | pTxCtl->TcbPool = tcb; | ||
221 | |||
222 | tcb = next_tcb; | ||
223 | } | ||
224 | |||
225 | pTxCtl->TxActQueueHead = 0; | ||
226 | pTxCtl->TxActQueueTail = 0; | ||
227 | pTxCtl->TxActive = 0; | ||
228 | |||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | |||
233 | /** | ||
234 | * @ingroup CPHAL_Functions | ||
235 | * This function transmits the data in FragList using available transmit | ||
236 | * buffer descriptors. More information on the use of the Mode parameter | ||
237 | * is available in the module-specific appendices. Note: The OS should | ||
238 | * not call Send() for a channel that has been requested to be torndown. | ||
239 | * | ||
240 | */ | ||
241 | int tnetv_cppi_send(struct cppi_info *cppi, int ch, dma_addr_t buf, unsigned length, int send_zlp) | ||
242 | { | ||
243 | cppi_txcntl *pTxCtl; | ||
244 | cppi_tcb *first_tcb; | ||
245 | cppi_tcb *tcb; | ||
246 | int queued_len; | ||
247 | dma_addr_t buf_to_send; | ||
248 | dma_addr_t buf_ptr; | ||
249 | int total_len = length; | ||
250 | int pktlen; | ||
251 | |||
252 | pTxCtl = &cppi->tx_ctl[ch]; | ||
253 | |||
254 | if (length == 0) | ||
255 | { | ||
256 | cppi_log_event0("[cppi] len = 0, nothing to send"); | ||
257 | return -1; | ||
258 | } | ||
259 | |||
260 | // no send buffers.. try again later | ||
261 | if (!pTxCtl->TcbPool) | ||
262 | { | ||
263 | cppi_log_event0("[cppi] out of cppi buffers"); | ||
264 | return -1; | ||
265 | } | ||
266 | |||
267 | // only send 1 packet at a time | ||
268 | if (pTxCtl->TxActQueueHead || pTxCtl->TxActive) | ||
269 | { | ||
270 | cppi_log_event0("[cppi] already sending!"); | ||
271 | return -1; | ||
272 | } | ||
273 | |||
274 | buf_to_send = buf; | ||
275 | |||
276 | // usb_requests can have a 32 bit length, but CPPI DMA fragments | ||
277 | // have a (64k - 1) limit. Split the usb_request up into fragments here. | ||
278 | first_tcb = pTxCtl->TcbPool; | ||
279 | tcb = first_tcb; | ||
280 | |||
281 | cppi_log_event4("[cppi]cppi_send (buf) (len) (pool) (dma)", (uint32_t) buf_to_send, total_len, (uint32_t) first_tcb, first_tcb->dma_handle); | ||
282 | |||
283 | queued_len = 0; | ||
284 | |||
285 | do | ||
286 | { | ||
287 | buf_ptr = buf_to_send + queued_len; | ||
288 | tcb->BufPtr = __dma_to_vlynq_phys(buf_ptr); | ||
289 | tcb->HNext = 0; | ||
290 | |||
291 | // can't transfer more that 64k-1 bytes in 1 CPPI transfer | ||
292 | // need to queue up transfers if it's greater than that | ||
293 | pktlen = ((total_len - queued_len) > CPPI_MAX_FRAG) ? CPPI_MAX_FRAG : (total_len - queued_len); | ||
294 | tcb->Off_BLen = pktlen; | ||
295 | tcb->mode = (CB_OWNERSHIP_BIT | CB_SOF_BIT | CB_EOF_BIT | pktlen); | ||
296 | |||
297 | queued_len += pktlen; | ||
298 | |||
299 | if (queued_len < total_len) | ||
300 | { | ||
301 | tcb->HNext = __dma_to_vlynq_phys(((cppi_tcb *) tcb->Next)->dma_handle); | ||
302 | |||
303 | // write out the buffer to memory | ||
304 | consistent_sync(tcb, sizeof(*tcb), DMA_TO_DEVICE); | ||
305 | |||
306 | cppi_log_event4("[cppi] q tcb", (uint32_t) tcb, ((uint32_t *) tcb)[0], ((uint32_t *) tcb)[1], ((uint32_t *) tcb)[2]); | ||
307 | cppi_log_event4("[cppi] ", ((uint32_t *) tcb)[3], ((uint32_t *) tcb)[4], ((uint32_t *) tcb)[5], ((uint32_t *) tcb)[6]); | ||
308 | |||
309 | tcb = tcb->Next; | ||
310 | } | ||
311 | } while (queued_len < total_len); | ||
312 | |||
313 | /* In the Tx Interrupt handler, we will need to know which TCB is EOP, | ||
314 | so we can save that information in the SOP */ | ||
315 | first_tcb->Eop = tcb; | ||
316 | |||
317 | // set the secret ZLP bit if necessary, this will be a completely separate packet | ||
318 | if (send_zlp) | ||
319 | { | ||
320 | #if defined(AUTO_ZLP) && AUTO_ZLP | ||
321 | // add an extra buffer at the end to hold the ZLP | ||
322 | tcb->HNext = __dma_to_vlynq_phys(((cppi_tcb *) tcb->Next)->dma_handle); | ||
323 | |||
324 | // write out the buffer to memory | ||
325 | consistent_sync(tcb, sizeof(*tcb), DMA_TO_DEVICE); | ||
326 | |||
327 | tcb = tcb->Next; | ||
328 | |||
329 | /* In the Tx Interrupt handler, we will need to know which TCB is EOP, | ||
330 | so we can save that information in the SOP */ | ||
331 | first_tcb->Eop = tcb; | ||
332 | #endif | ||
333 | |||
334 | buf_ptr = buf_to_send + queued_len; | ||
335 | tcb->BufPtr = __dma_to_vlynq_phys(buf_ptr); // not used, but can't be zero | ||
336 | tcb->HNext = 0; | ||
337 | tcb->Off_BLen = 0x1; // device will send (((len - 1) / maxpacket) + 1) ZLPs | ||
338 | tcb->mode = (CB_SOF_BIT | CB_EOF_BIT | CB_OWNERSHIP_BIT | CB_ZLP_GARBAGE | 0x1); // send 1 ZLP | ||
339 | tcb->Eop = tcb; | ||
340 | |||
341 | cppi_log_event0("[cppi] Send ZLP!"); | ||
342 | } | ||
343 | |||
344 | pTxCtl->TcbPool = tcb->Next; | ||
345 | |||
346 | tcb->Next = 0; | ||
347 | tcb->HNext = 0; | ||
348 | |||
349 | // write out the buffer to memory | ||
350 | consistent_sync(tcb, sizeof(*tcb), DMA_TO_DEVICE); | ||
351 | |||
352 | cppi_log_event4("[cppi] q tcb", (uint32_t) tcb, ((uint32_t *) tcb)[0], ((uint32_t *) tcb)[1], ((uint32_t *) tcb)[2]); | ||
353 | cppi_log_event4("[cppi] ", ((uint32_t *) tcb)[3], ((uint32_t *) tcb)[4], ((uint32_t *) tcb)[5], ((uint32_t *) tcb)[6]); | ||
354 | |||
355 | cppi_log_event4("[cppi] send queued (ptr) (len) (ftcb, ltcb)", (uint32_t) tcb->BufPtr, tcb->Off_BLen, (uint32_t) first_tcb, (uint32_t) tcb); | ||
356 | |||
357 | /* put it on the queue */ | ||
358 | pTxCtl->TxActQueueHead = first_tcb; | ||
359 | pTxCtl->TxActQueueTail = tcb; | ||
360 | |||
361 | cppi_log_event3("[cppi] setting state (head) (virt) (next)", (uint32_t) first_tcb, __dma_to_vlynq_phys(first_tcb->dma_handle), (uint32_t) first_tcb->HNext); | ||
362 | |||
363 | /* write CPPI TX HDP - cache is cleaned above */ | ||
364 | tnetv_usb_reg_write(TNETV_DMA_TX_STATE(ch, TNETV_CPPI_TX_WORD_HDP), __dma_to_vlynq_phys(first_tcb->dma_handle)); | ||
365 | |||
366 | pTxCtl->TxActive = 1; | ||
367 | |||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | /* | ||
372 | * This function allocates transmit buffer descriptors (internal CPHAL function). | ||
373 | * It creates a high priority transmit queue by default for a single Tx | ||
374 | * channel. If QoS is enabled for the given CPHAL device, this function | ||
375 | * will also allocate a low priority transmit queue. | ||
376 | * | ||
377 | * @return 0 OK, Non-Zero Not OK | ||
378 | */ | ||
379 | int tnetv_cppi_init_tcb(struct cppi_info *cppi, int ch) | ||
380 | { | ||
381 | int i, num; | ||
382 | cppi_tcb *pTcb = 0; | ||
383 | char *AllTcb; | ||
384 | int tcbSize; | ||
385 | cppi_txcntl *pTxCtl = &cppi->tx_ctl[ch]; | ||
386 | |||
387 | num = pTxCtl->TxNumBuffers; | ||
388 | tcbSize = (sizeof(cppi_tcb) + 0xf) & ~0xf; | ||
389 | |||
390 | cppi_log_event4("[cppi] init_tcb (ch) (num) (dma) (tcbsz)", ch, num, pTxCtl->tcb_start_dma_addr, tcbSize); | ||
391 | |||
392 | if (pTxCtl->TxNumBuffers == 0) | ||
393 | { | ||
394 | return -1; | ||
395 | } | ||
396 | |||
397 | /* if the memory has already been allocated, simply reuse it! */ | ||
398 | AllTcb = pTxCtl->TcbStart; | ||
399 | |||
400 | // now reinitialize the TCB pool | ||
401 | pTxCtl->TcbPool = 0; | ||
402 | for (i = 0; i < num; i++) | ||
403 | { | ||
404 | pTcb = (cppi_tcb *)(AllTcb + (i * tcbSize)); | ||
405 | pTcb->dma_handle = pTxCtl->tcb_start_dma_addr + (i * tcbSize); | ||
406 | |||
407 | pTcb->BufPtr = 0; | ||
408 | pTcb->mode = 0; | ||
409 | pTcb->HNext = 0; | ||
410 | pTcb->Off_BLen = 0; | ||
411 | pTcb->Eop = 0; | ||
412 | |||
413 | pTcb->Next = (void *) pTxCtl->TcbPool; | ||
414 | |||
415 | pTxCtl->TcbPool = pTcb; | ||
416 | } | ||
417 | |||
418 | cppi_log_event2(" [cppi]TcbPool", (uint32_t) pTxCtl->TcbPool, pTxCtl->TcbPool->dma_handle); | ||
419 | |||
420 | #if USB_CPPI_LOGGING | ||
421 | { | ||
422 | // BEN DEBUG | ||
423 | cppi_tcb *first_tcb = pTxCtl->TcbPool; | ||
424 | cppi_log_event4("[cppi] init tcb", (uint32_t) first_tcb, ((uint32_t *) first_tcb)[0], ((uint32_t *) first_tcb)[1], ((uint32_t *) first_tcb)[2]); | ||
425 | cppi_log_event4("[cppi] ", ((uint32_t *) first_tcb)[3], ((uint32_t *) first_tcb)[4], ((uint32_t *) first_tcb)[5], ((uint32_t *) first_tcb)[6]); | ||
426 | } | ||
427 | #endif | ||
428 | |||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | // BEN DEBUG | ||
433 | void tnetv_cppi_dump_info(struct cppi_info *cppi) | ||
434 | { | ||
435 | int ch; | ||
436 | cppi_rxcntl *pRxCtl; | ||
437 | cppi_txcntl *pTxCtl; | ||
438 | cppi_tcb *tcb; | ||
439 | cppi_rcb *rcb; | ||
440 | |||
441 | logf("CPPI struct:\n"); | ||
442 | logf("Buf mem: %x Buf size: %d int: %x %x\n\n", (uint32_t) cppi->dma_mem, cppi->dma_size, tnetv_usb_reg_read(TNETV_USB_RX_INT_STATUS), tnetv_usb_reg_read(DM320_VLYNQ_INTST)); | ||
443 | |||
444 | for (ch = 0; ch < CPPI_NUM_CHANNELS; ch++) | ||
445 | { | ||
446 | pRxCtl = &cppi->rx_ctl[ch]; | ||
447 | pTxCtl = &cppi->tx_ctl[ch]; | ||
448 | |||
449 | logf("ch: %d\n", ch); | ||
450 | logf(" rx_numbufs: %d active %d free_buf_cnt %d\n", pRxCtl->RxNumBuffers, pRxCtl->RxActive, tnetv_usb_reg_read(TNETV_USB_RX_FREE_BUF_CNT(ch))); | ||
451 | logf(" q_cnt %d head %x tail %x\n", pRxCtl->RxActQueueCount, (uint32_t) pRxCtl->RxActQueueHead, (uint32_t) pRxCtl->RxActQueueTail); | ||
452 | logf(" fake_head: %x fake_tail: %x\n", (uint32_t) pRxCtl->RxFakeRcvHead, (uint32_t) pRxCtl->RxFakeRcvTail); | ||
453 | |||
454 | rcb = (cppi_rcb *) pRxCtl->RcbStart; | ||
455 | do | ||
456 | { | ||
457 | if (!rcb) | ||
458 | break; | ||
459 | |||
460 | logf(" Rcb: %x\n", (uint32_t) rcb); | ||
461 | logf(" HNext %x BufPtr %x Off_BLen %x mode %x\n", rcb->HNext, rcb->BufPtr, rcb->Off_BLen, rcb->mode); | ||
462 | logf(" Next %x Eop %x dma_handle %x fake_bytes %x\n", (uint32_t) rcb->Next, (uint32_t) rcb->Eop, rcb->dma_handle, rcb->fake_bytes); | ||
463 | rcb = rcb->Next; | ||
464 | |||
465 | } while (rcb && rcb != (cppi_rcb *) pRxCtl->RcbStart); | ||
466 | |||
467 | logf("\n"); | ||
468 | logf(" tx_numbufs: %d active %d\n", pTxCtl->TxNumBuffers, pTxCtl->TxActive); | ||
469 | logf(" q_cnt %d head %x tail %x\n", pTxCtl->TxActQueueCount, (uint32_t) pTxCtl->TxActQueueHead, (uint32_t) pTxCtl->TxActQueueTail); | ||
470 | |||
471 | tcb = (cppi_tcb *) pTxCtl->TcbPool; | ||
472 | do | ||
473 | { | ||
474 | if (!tcb) | ||
475 | break; | ||
476 | |||
477 | logf(" Tcb (pool): %x\n", (uint32_t) tcb); | ||
478 | logf(" HNext %x BufPtr %x Off_BLen %x mode %x\n", tcb->HNext, tcb->BufPtr, tcb->Off_BLen, tcb->mode); | ||
479 | logf(" Next %x Eop %x dma_handle %x\n", (uint32_t) tcb->Next, (uint32_t) tcb->Eop, tcb->dma_handle); | ||
480 | tcb = tcb->Next; | ||
481 | |||
482 | } while (tcb && tcb != (cppi_tcb *) pTxCtl->TcbPool); | ||
483 | |||
484 | tcb = (cppi_tcb *) pTxCtl->TxActQueueHead; | ||
485 | do | ||
486 | { | ||
487 | if (!tcb) | ||
488 | break; | ||
489 | |||
490 | logf(" Tcb (act): %x\n", (uint32_t) tcb); | ||
491 | logf(" HNext %x BufPtr %x Off_BLen %x mode %x\n", tcb->HNext, tcb->BufPtr, tcb->Off_BLen, tcb->mode); | ||
492 | logf(" Next %x Eop %x dma_handle %x\n", (uint32_t) tcb->Next, (uint32_t) tcb->Eop, tcb->dma_handle); | ||
493 | tcb = tcb->Next; | ||
494 | |||
495 | } while (tcb && tcb != (cppi_tcb *) pTxCtl->TxActQueueTail); | ||
496 | |||
497 | } | ||
498 | } | ||
499 | |||
500 | /** | ||
501 | * | ||
502 | * This function is called to indicate to the CPHAL that the upper layer | ||
503 | * software has finished processing the receive data (given to it by | ||
504 | * osReceive()). The CPHAL will then return the appropriate receive buffers | ||
505 | * and buffer descriptors to the available pool. | ||
506 | * | ||
507 | */ | ||
508 | int tnetv_cppi_rx_return(struct cppi_info *cppi, int ch, cppi_rcb *done_rcb) | ||
509 | { | ||
510 | cppi_rxcntl *pRxCtl = &cppi->rx_ctl[ch]; | ||
511 | cppi_rcb *curRcb, *lastRcb, *endRcb; | ||
512 | int num_bufs = 0; | ||
513 | |||
514 | if (!done_rcb) | ||
515 | return -1; | ||
516 | |||
517 | //cppi_log_event3("[cppi] rx_return (last) (first) bufinq", (uint32_t) done_rcb, (uint32_t) done_rcb->Eop, tnetv_usb_reg_read(TNETV_USB_RX_FREE_BUF_CNT(ch))); | ||
518 | |||
519 | curRcb = done_rcb; | ||
520 | endRcb = done_rcb->Eop; | ||
521 | do | ||
522 | { | ||
523 | curRcb->mode = CB_OWNERSHIP_BIT; | ||
524 | curRcb->Off_BLen = MAX_BUF_SIZE; | ||
525 | curRcb->Eop = 0; | ||
526 | |||
527 | pRxCtl->RxActQueueCount++; | ||
528 | num_bufs++; | ||
529 | |||
530 | lastRcb = curRcb; | ||
531 | curRcb = lastRcb->Next; | ||
532 | |||
533 | consistent_sync(lastRcb, sizeof(*lastRcb), DMA_TO_DEVICE); | ||
534 | |||
535 | } while (lastRcb != endRcb); | ||
536 | |||
537 | cppi_log_event1("[cppi] rx_return done", num_bufs); | ||
538 | |||
539 | // let the hardware know about the buffer(s) | ||
540 | tnetv_usb_reg_write(TNETV_USB_RX_FREE_BUF_CNT(ch), num_bufs); | ||
541 | |||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | int tnetv_cppi_rx_int_recv(struct cppi_info *cppi, int ch, int *buf_size, void *buf, int maxpacket) | ||
546 | { | ||
547 | cppi_rxcntl *pRxCtl = &cppi->rx_ctl[ch]; | ||
548 | cppi_rcb *CurrentRcb, *LastRcb = 0, *SopRcb; | ||
549 | uint8_t *cur_buf_data_addr; | ||
550 | int cur_buf_bytes; | ||
551 | int copy_buf_size = *buf_size; | ||
552 | int ret = -EAGAIN; | ||
553 | |||
554 | *buf_size = 0; | ||
555 | |||
556 | CurrentRcb = pRxCtl->RxFakeRcvHead; | ||
557 | if (!CurrentRcb) | ||
558 | { | ||
559 | cppi_log_event2("[cppi] rx_int recv: nothing in q", tnetv_usb_reg_read(TNETV_USB_RX_INT_STATUS), tnetv_usb_reg_read(DM320_VLYNQ_INTST)); | ||
560 | return -1; | ||
561 | } | ||
562 | |||
563 | cppi_log_event1("[cppi] rx_int recv (ch)", ch); | ||
564 | cppi_log_event4(" [cppi] recv - Processing SOP descriptor fb hd tl", (uint32_t) CurrentRcb, CurrentRcb->fake_bytes, (uint32_t) pRxCtl->RxFakeRcvHead, (uint32_t) pRxCtl->RxFakeRcvTail); | ||
565 | |||
566 | SopRcb = CurrentRcb; | ||
567 | LastRcb = 0; | ||
568 | |||
569 | do | ||
570 | { | ||
571 | // convert from vlynq phys to virt | ||
572 | cur_buf_data_addr = (uint8_t *) __vlynq_phys_to_dma(CurrentRcb->BufPtr); | ||
573 | cur_buf_data_addr = (uint8_t *) __phys_to_virt(cur_buf_data_addr); | ||
574 | cur_buf_bytes = (CurrentRcb->mode) & CB_SIZE_MASK; | ||
575 | |||
576 | // make sure we don't overflow the buffer. | ||
577 | if (cur_buf_bytes > copy_buf_size) | ||
578 | { | ||
579 | ret = 0; | ||
580 | break; | ||
581 | } | ||
582 | |||
583 | // BEN - packet can be ZLP | ||
584 | if (cur_buf_bytes) | ||
585 | { | ||
586 | consistent_sync(cur_buf_data_addr, MAX_BUF_SIZE, DMA_FROM_DEVICE); | ||
587 | |||
588 | memcpy((buf + *buf_size), cur_buf_data_addr, cur_buf_bytes); | ||
589 | |||
590 | copy_buf_size -= cur_buf_bytes; | ||
591 | *buf_size += cur_buf_bytes; | ||
592 | CurrentRcb->fake_bytes -= cur_buf_bytes; | ||
593 | } | ||
594 | else | ||
595 | { | ||
596 | CurrentRcb->fake_bytes = 0; | ||
597 | } | ||
598 | |||
599 | cppi_log_event4(" [cppi] bytes totrcvd amtleft fake", cur_buf_bytes, *buf_size, copy_buf_size, CurrentRcb->fake_bytes); | ||
600 | |||
601 | LastRcb = CurrentRcb; | ||
602 | CurrentRcb = LastRcb->Next; | ||
603 | |||
604 | // sync out fake bytes info | ||
605 | consistent_sync(LastRcb, sizeof(*LastRcb), DMA_TO_DEVICE); | ||
606 | |||
607 | // make sure each packet processed individually | ||
608 | if (cur_buf_bytes < maxpacket) | ||
609 | { | ||
610 | ret = 0; | ||
611 | break; | ||
612 | } | ||
613 | |||
614 | } while (LastRcb != pRxCtl->RxFakeRcvTail && CurrentRcb->fake_bytes && copy_buf_size > 0); | ||
615 | |||
616 | // make sure that the CurrentRcb isn't in the cache | ||
617 | consistent_sync(CurrentRcb, sizeof(*CurrentRcb), DMA_FROM_DEVICE); | ||
618 | |||
619 | if (copy_buf_size == 0) | ||
620 | { | ||
621 | ret = 0; | ||
622 | } | ||
623 | |||
624 | if (LastRcb) | ||
625 | { | ||
626 | SopRcb->Eop = LastRcb; | ||
627 | |||
628 | cppi_log_event3(" [cppi] rcv end", *buf_size, (uint32_t) CurrentRcb, (uint32_t) SopRcb->Eop); | ||
629 | |||
630 | if (LastRcb == pRxCtl->RxFakeRcvTail) | ||
631 | { | ||
632 | pRxCtl->RxFakeRcvHead = 0; | ||
633 | pRxCtl->RxFakeRcvTail = 0; | ||
634 | } | ||
635 | else | ||
636 | { | ||
637 | pRxCtl->RxFakeRcvHead = CurrentRcb; | ||
638 | } | ||
639 | |||
640 | cppi_log_event1(" [cppi] st rx return", ch); | ||
641 | cppi_log_event2(" rcv fake hd tl", (uint32_t) pRxCtl->RxFakeRcvHead, (uint32_t) pRxCtl->RxFakeRcvTail); | ||
642 | |||
643 | // all done, clean up the RCBs | ||
644 | tnetv_cppi_rx_return(cppi, ch, SopRcb); | ||
645 | } | ||
646 | |||
647 | return ret; | ||
648 | } | ||
649 | |||
650 | /* | ||
651 | * This function processes receive interrupts. It traverses the receive | ||
652 | * buffer queue, extracting the data and passing it to the upper layer software via | ||
653 | * osReceive(). It handles all error conditions and fragments without valid data by | ||
654 | * immediately returning the RCB's to the RCB pool. | ||
655 | */ | ||
656 | int tnetv_cppi_rx_int(struct cppi_info *cppi, int ch) | ||
657 | { | ||
658 | cppi_rxcntl *pRxCtl = &cppi->rx_ctl[ch]; | ||
659 | cppi_rcb *CurrentRcb, *LastRcb = 0, *SopRcb; | ||
660 | uint32_t RxBufStatus,PacketsServiced; | ||
661 | int TotalFrags; | ||
662 | |||
663 | cppi_log_event1("[cppi] rx_int (ch)", ch); | ||
664 | |||
665 | CurrentRcb = pRxCtl->RxActQueueHead; | ||
666 | |||
667 | if (!CurrentRcb) | ||
668 | { | ||
669 | cppi_log_event1("[cppi] rx_int no bufs!", (uint32_t) CurrentRcb); | ||
670 | return -1; | ||
671 | } | ||
672 | |||
673 | // make sure that all of the buffers get an invalidated cache | ||
674 | consistent_sync(pRxCtl->RcbStart, sizeof(cppi_rcb) * CPPI_RX_NUM_BUFS, DMA_FROM_DEVICE); | ||
675 | |||
676 | RxBufStatus = CurrentRcb->mode; | ||
677 | PacketsServiced = 0; | ||
678 | |||
679 | cppi_log_event4("[cppi] currentrcb, mode numleft fake", (uint32_t) CurrentRcb, CurrentRcb->mode, pRxCtl->RxActQueueCount, CurrentRcb->fake_bytes); | ||
680 | cppi_log_event4("[cppi]", ((uint32_t *) CurrentRcb)[0], ((uint32_t *) CurrentRcb)[1], ((uint32_t *) CurrentRcb)[2], ((uint32_t *) CurrentRcb)[3]); | ||
681 | |||
682 | while(((RxBufStatus & CB_OWNERSHIP_BIT) == 0) && (pRxCtl->RxActQueueCount > 0)) | ||
683 | { | ||
684 | cppi_log_event2(" [cppi]Processing SOP descriptor st", (uint32_t) CurrentRcb, RxBufStatus); | ||
685 | |||
686 | SopRcb = CurrentRcb; | ||
687 | |||
688 | TotalFrags = 0; | ||
689 | |||
690 | do | ||
691 | { | ||
692 | TotalFrags++; | ||
693 | PacketsServiced++; | ||
694 | |||
695 | // Write the completion pointer | ||
696 | tnetv_usb_reg_write(TNETV_DMA_RX_CMPL(ch), __dma_to_vlynq_phys(CurrentRcb->dma_handle)); | ||
697 | |||
698 | CurrentRcb->fake_bytes = (CurrentRcb->mode) & 0xFFFF; | ||
699 | |||
700 | // BEN - make sure this gets marked! | ||
701 | if (!CurrentRcb->fake_bytes || (CurrentRcb->mode & CB_ZLP_GARBAGE)) | ||
702 | { | ||
703 | CurrentRcb->mode &= 0xFFFF0000; | ||
704 | CurrentRcb->fake_bytes = 0x10000; | ||
705 | } | ||
706 | |||
707 | cppi_log_event1(" fake_bytes:", CurrentRcb->fake_bytes); | ||
708 | |||
709 | RxBufStatus = CurrentRcb->mode; | ||
710 | LastRcb = CurrentRcb; | ||
711 | CurrentRcb = LastRcb->Next; | ||
712 | |||
713 | // sync the fake_bytes value back to mem | ||
714 | consistent_sync(LastRcb, sizeof(*LastRcb), DMA_TO_DEVICE); | ||
715 | |||
716 | } while (((CurrentRcb->mode & CB_OWNERSHIP_BIT) == 0) && ((RxBufStatus & CB_EOF_BIT) == 0)); | ||
717 | |||
718 | SopRcb->Eop = LastRcb; | ||
719 | |||
720 | pRxCtl->RxActQueueHead = CurrentRcb; | ||
721 | pRxCtl->RxActQueueCount -= TotalFrags; | ||
722 | |||
723 | if (LastRcb->mode & CB_EOQ_BIT) | ||
724 | { | ||
725 | if (CurrentRcb) | ||
726 | { | ||
727 | cppi_log_event1(" [cppi] rcv done q next", LastRcb->HNext); | ||
728 | tnetv_usb_reg_write(TNETV_DMA_RX_STATE(ch, TNETV_CPPI_RX_WORD_HDP), LastRcb->HNext); | ||
729 | } | ||
730 | else | ||
731 | { | ||
732 | cppi_log_event0(" [cppi] rcv done"); | ||
733 | |||
734 | pRxCtl->RxActive = 0; | ||
735 | } | ||
736 | } | ||
737 | |||
738 | // BEN - add to the list of buffers we need to deal with | ||
739 | if (!pRxCtl->RxFakeRcvHead) | ||
740 | { | ||
741 | pRxCtl->RxFakeRcvHead = SopRcb; | ||
742 | pRxCtl->RxFakeRcvTail = SopRcb->Eop; | ||
743 | } | ||
744 | else | ||
745 | { | ||
746 | pRxCtl->RxFakeRcvTail = SopRcb->Eop; | ||
747 | } | ||
748 | |||
749 | // make sure we have enough buffers | ||
750 | cppi_log_event1(" nextrcb", CurrentRcb->mode); | ||
751 | |||
752 | if (CurrentRcb) | ||
753 | { | ||
754 | // continue the loop | ||
755 | RxBufStatus = CurrentRcb->mode; | ||
756 | } | ||
757 | |||
758 | } /* while */ | ||
759 | |||
760 | cppi_log_event2("[cppi] fake hd tl", (uint32_t) pRxCtl->RxFakeRcvHead, (uint32_t) pRxCtl->RxFakeRcvTail); | ||
761 | |||
762 | // sync out all buffers before leaving | ||
763 | consistent_sync(pRxCtl->RcbStart, (CPPI_RX_NUM_BUFS * sizeof(cppi_rcb)), DMA_FROM_DEVICE); | ||
764 | |||
765 | return PacketsServiced; | ||
766 | } | ||
767 | |||
768 | static void tnetv_cppi_rx_queue_init(struct cppi_info *cppi, int ch, dma_addr_t buf, unsigned length) | ||
769 | { | ||
770 | cppi_rxcntl *pRxCtl = &cppi->rx_ctl[ch]; | ||
771 | cppi_rcb *rcb, *first_rcb; | ||
772 | unsigned int queued_len = 0; | ||
773 | int rcblen; | ||
774 | int num_frags = 0; | ||
775 | dma_addr_t buf_ptr; | ||
776 | |||
777 | if (length == 0) | ||
778 | { | ||
779 | cppi_log_event0("[cppi] len = 0, nothing to recv"); | ||
780 | return; | ||
781 | } | ||
782 | |||
783 | // usb_requests can have a 32 bit length, but CPPI DMA fragments | ||
784 | // have a 64k limit. Split the usb_request up into fragments here. | ||
785 | first_rcb = pRxCtl->RcbPool; | ||
786 | rcb = first_rcb; | ||
787 | |||
788 | cppi_log_event2("[cppi] Rx queue add: head len", (uint32_t) first_rcb, length); | ||
789 | |||
790 | while (queued_len < length) | ||
791 | { | ||
792 | buf_ptr = buf + queued_len; | ||
793 | rcb->BufPtr = __dma_to_vlynq_phys(buf_ptr); | ||
794 | |||
795 | rcb->HNext = 0; | ||
796 | rcb->mode = CB_OWNERSHIP_BIT; | ||
797 | |||
798 | rcblen = ((length - queued_len) > MAX_BUF_SIZE) ? MAX_BUF_SIZE : (length - queued_len); | ||
799 | rcb->Off_BLen = rcblen; | ||
800 | |||
801 | queued_len += rcblen; | ||
802 | if (queued_len < length) | ||
803 | { | ||
804 | rcb->HNext = __dma_to_vlynq_phys(((cppi_rcb *) (rcb->Next))->dma_handle); | ||
805 | rcb = rcb->Next; | ||
806 | } | ||
807 | |||
808 | num_frags++; | ||
809 | } | ||
810 | |||
811 | pRxCtl->RcbPool = rcb->Next; | ||
812 | rcb->Next = 0; | ||
813 | |||
814 | cppi_log_event4("[cppi] Adding Rcb (dma) (paddr) (buf)", (uint32_t) rcb, rcb->dma_handle, __dma_to_vlynq_phys(rcb->dma_handle), (uint32_t) rcb->BufPtr); | ||
815 | cppi_log_event4("[cppi] Next HNext (len) of (total)", (uint32_t) rcb->Next, rcb->HNext, queued_len, length); | ||
816 | |||
817 | pRxCtl->RxActQueueCount += num_frags; | ||
818 | |||
819 | cppi_log_event4("[cppi] rx queued (ptr) (len) (ftcb, ltcb)", (uint32_t) rcb->BufPtr, rcb->Off_BLen, (uint32_t) first_rcb, (uint32_t) rcb); | ||
820 | cppi_log_event2(" [cppi] mode num_frags", rcb->mode, num_frags); | ||
821 | |||
822 | pRxCtl->RxActQueueHead = first_rcb; | ||
823 | pRxCtl->RxActQueueTail = rcb; | ||
824 | |||
825 | cppi_log_event2("[cppi] setting rx (head) (virt)", (uint32_t) first_rcb, __dma_to_vlynq_phys(first_rcb->dma_handle)); | ||
826 | cppi_log_event4("[cppi] ", ((uint32_t *) first_rcb)[0], ((uint32_t *) first_rcb)[1], ((uint32_t *) first_rcb)[2], ((uint32_t *) first_rcb)[3]); | ||
827 | |||
828 | // make this into a circular buffer so we never get caught with | ||
829 | // no free buffers left | ||
830 | rcb->Next = pRxCtl->RxActQueueHead; | ||
831 | rcb->HNext = (uint32_t) (__dma_to_vlynq_phys(pRxCtl->RxActQueueHead->dma_handle)); | ||
832 | } | ||
833 | |||
834 | int tnetv_cppi_rx_queue_add(struct cppi_info *cppi, int ch, dma_addr_t buf, unsigned length) | ||
835 | { | ||
836 | (void)buf; | ||
837 | (void)length; | ||
838 | cppi_rxcntl *pRxCtl = &cppi->rx_ctl[ch]; | ||
839 | unsigned int cur_bufs; | ||
840 | |||
841 | cur_bufs = tnetv_usb_reg_read(TNETV_USB_RX_FREE_BUF_CNT(ch)); | ||
842 | |||
843 | if (!pRxCtl->RxActive) | ||
844 | { | ||
845 | cppi_log_event0("[cppi] queue add - not active"); | ||
846 | |||
847 | pRxCtl->RcbPool = (cppi_rcb *) pRxCtl->RcbStart; | ||
848 | |||
849 | // add all the buffers to the active (circular) queue | ||
850 | tnetv_cppi_rx_queue_init(cppi, ch, (dma_addr_t) __virt_to_phys(dma_recv_buf[ch]), (MAX_BUF_SIZE * pRxCtl->RxNumBuffers)); | ||
851 | |||
852 | /* write Rx Queue Head Descriptor Pointer */ | ||
853 | tnetv_usb_reg_write(TNETV_DMA_RX_STATE(ch, TNETV_CPPI_RX_WORD_HDP), __dma_to_vlynq_phys(pRxCtl->RxActQueueHead->dma_handle)); | ||
854 | |||
855 | pRxCtl->RxActive = 1; | ||
856 | |||
857 | // sync out all buffers before starting | ||
858 | consistent_sync(pRxCtl->RcbStart, (CPPI_RX_NUM_BUFS * sizeof(cppi_rcb)), DMA_TO_DEVICE); | ||
859 | |||
860 | // sync out temp rx buffer | ||
861 | consistent_sync(dma_recv_buf[ch], CPPI_DMA_RX_BUF_SIZE, DMA_FROM_DEVICE); | ||
862 | |||
863 | if (cur_bufs < pRxCtl->RxActQueueCount) | ||
864 | { | ||
865 | // let the hardware know about the buffer(s) | ||
866 | tnetv_usb_reg_write(TNETV_USB_RX_FREE_BUF_CNT(ch), pRxCtl->RxActQueueCount - cur_bufs); | ||
867 | } | ||
868 | } | ||
869 | |||
870 | cppi_log_event3("[cppi] rx add: (cur_bufs) (avail_bufs) (now)", cur_bufs, pRxCtl->RxActQueueCount, tnetv_usb_reg_read(TNETV_USB_RX_FREE_BUF_CNT(ch))); | ||
871 | |||
872 | return 0; | ||
873 | } | ||
874 | |||
875 | int tnetv_cppi_flush_rx_queue(struct cppi_info *cppi, int ch) | ||
876 | { | ||
877 | cppi_rxcntl *pRxCtl = &cppi->rx_ctl[ch]; | ||
878 | cppi_rcb *rcb; | ||
879 | int num_bufs; | ||
880 | |||
881 | cppi_log_event1("[cppi] flush RX ", (uint32_t) pRxCtl->RxActQueueHead); | ||
882 | |||
883 | // flush out any pending receives | ||
884 | tnetv_cppi_rx_int(cppi, ch); | ||
885 | |||
886 | // now discard all received data | ||
887 | rcb = pRxCtl->RxFakeRcvHead; | ||
888 | |||
889 | if (rcb) | ||
890 | { | ||
891 | rcb->Eop = pRxCtl->RxFakeRcvTail; | ||
892 | |||
893 | // clean up any unreceived RCBs | ||
894 | tnetv_cppi_rx_return(cppi, ch, rcb); | ||
895 | } | ||
896 | |||
897 | pRxCtl->RxFakeRcvHead = 0; | ||
898 | pRxCtl->RxFakeRcvTail = 0; | ||
899 | |||
900 | pRxCtl->RxActive = 0; | ||
901 | |||
902 | // drain the HW free buffer count | ||
903 | num_bufs = tnetv_usb_reg_read(TNETV_USB_RX_FREE_BUF_CNT(ch)); | ||
904 | tnetv_usb_reg_write(TNETV_USB_RX_FREE_BUF_CNT(ch), -num_bufs); | ||
905 | |||
906 | cppi_log_event2("[cppi] flush RX queue done (freed) act: ", num_bufs, (uint32_t) pRxCtl->RxActQueueCount); | ||
907 | |||
908 | return 0; | ||
909 | } | ||
910 | |||
911 | |||
912 | /* | ||
913 | * This function allocates receive buffer descriptors (internal CPHAL function). | ||
914 | * After allocation, the function 'queues' (gives to the hardware) the newly | ||
915 | * created receive buffers to enable packet reception. | ||
916 | * | ||
917 | * @param ch Channel number. | ||
918 | * | ||
919 | * @return 0 OK, Non-Zero Not OK | ||
920 | */ | ||
921 | int tnetv_cppi_init_rcb(struct cppi_info *cppi, int ch) | ||
922 | { | ||
923 | int i, num; | ||
924 | cppi_rcb *pRcb; | ||
925 | char *AllRcb; | ||
926 | int rcbSize; | ||
927 | cppi_rxcntl *pRxCtl = &cppi->rx_ctl[ch]; | ||
928 | |||
929 | num = pRxCtl->RxNumBuffers; | ||
930 | rcbSize = (sizeof(cppi_rcb) + 0xf) & ~0xf; | ||
931 | |||
932 | cppi_log_event2("[cppi] init_rcb ch num", ch, num); | ||
933 | |||
934 | if (pRxCtl->RxNumBuffers == 0) | ||
935 | { | ||
936 | return -1; | ||
937 | } | ||
938 | |||
939 | /* if the memory has already been allocated, simply reuse it! */ | ||
940 | AllRcb = pRxCtl->RcbStart; | ||
941 | |||
942 | // now reinitialize the RCB pool | ||
943 | pRxCtl->RcbPool = 0; | ||
944 | for (i = (num - 1); i >= 0; i--) | ||
945 | { | ||
946 | pRcb = (cppi_rcb *)(AllRcb + (i * rcbSize)); | ||
947 | |||
948 | pRcb->dma_handle = pRxCtl->rcb_start_dma_addr + (i * rcbSize); | ||
949 | |||
950 | pRcb->BufPtr = 0; | ||
951 | pRcb->mode = 0; | ||
952 | pRcb->HNext = 0; | ||
953 | pRcb->Next = (void *) pRxCtl->RcbPool; | ||
954 | pRcb->Off_BLen = 0; | ||
955 | pRcb->Eop = 0; | ||
956 | pRcb->fake_bytes = 0; | ||
957 | |||
958 | pRxCtl->RcbPool = pRcb; | ||
959 | } | ||
960 | |||
961 | cppi_log_event2(" [cppi]RcbPool (dma)", (uint32_t) pRxCtl->RcbPool, pRxCtl->RcbPool->dma_handle); | ||
962 | |||
963 | pRxCtl->RxActQueueCount = 0; | ||
964 | pRxCtl->RxActQueueHead = 0; | ||
965 | pRxCtl->RxActive = 0; | ||
966 | |||
967 | pRxCtl->RxFakeRcvHead = 0; | ||
968 | pRxCtl->RxFakeRcvTail = 0; | ||
969 | |||
970 | return 0; | ||
971 | } | ||
972 | |||
973 | static uint8_t ch_buf_cnt[][2] = { | ||
974 | {CPPI_RX_NUM_BUFS, 2}, // ch0: bulk out/in | ||
975 | {CPPI_RX_NUM_BUFS, 2}, // ch1: bulk out/in | ||
976 | {0, 2}, // ch2: interrupt | ||
977 | {0, 2} // ch3: interrupt | ||
978 | }; | ||
979 | |||
980 | void tnetv_cppi_init(struct cppi_info *cppi) | ||
981 | { | ||
982 | int ch; | ||
983 | uint8_t *alloc_ptr; | ||
984 | int ch_mem_size[CPPI_NUM_CHANNELS]; | ||
985 | |||
986 | // wipe cppi memory | ||
987 | memset(cppi, 0, sizeof(*cppi)); | ||
988 | |||
989 | // find out how much memory we need to allocate | ||
990 | cppi->dma_size = 0; | ||
991 | for (ch = 0; ch < CPPI_NUM_CHANNELS; ch++) | ||
992 | { | ||
993 | ch_mem_size[ch] = (ch_buf_cnt[ch][0] * sizeof(cppi_rcb)) + (ch_buf_cnt[ch][1] * sizeof(cppi_tcb)); | ||
994 | cppi->dma_size += ch_mem_size[ch]; | ||
995 | } | ||
996 | |||
997 | // allocate DMA-able memory | ||
998 | if (cppi->dma_size != CPPI_INFO_MEM_SIZE) | ||
999 | { | ||
1000 | panicf("Invalid dma size expected %d got %d", cppi->dma_size, CPPI_INFO_MEM_SIZE); | ||
1001 | } | ||
1002 | cppi->dma_handle = (dma_addr_t) __virt_to_phys(cppi->dma_mem); | ||
1003 | |||
1004 | memset(cppi->dma_mem, 0, cppi->dma_size); | ||
1005 | |||
1006 | cppi_log_event2("[cppi] all CBs sz mem", cppi->dma_size, (uint32_t) cppi->dma_mem); | ||
1007 | |||
1008 | // now set up the pointers | ||
1009 | alloc_ptr = cppi->dma_mem; | ||
1010 | for (ch = 0; ch < CPPI_NUM_CHANNELS; ch++) | ||
1011 | { | ||
1012 | cppi->rx_ctl[ch].RxNumBuffers = ch_buf_cnt[ch][0]; | ||
1013 | cppi->rx_ctl[ch].RcbStart = alloc_ptr; | ||
1014 | cppi->rx_ctl[ch].rcb_start_dma_addr = (dma_addr_t) __virt_to_phys(alloc_ptr); | ||
1015 | alloc_ptr += (ch_buf_cnt[ch][0] * sizeof(cppi_rcb)); | ||
1016 | |||
1017 | cppi->tx_ctl[ch].TxNumBuffers = ch_buf_cnt[ch][1]; | ||
1018 | cppi->tx_ctl[ch].TcbStart = alloc_ptr; | ||
1019 | cppi->tx_ctl[ch].tcb_start_dma_addr = (dma_addr_t) __virt_to_phys(alloc_ptr); | ||
1020 | alloc_ptr += (ch_buf_cnt[ch][1] * sizeof(cppi_tcb)); | ||
1021 | |||
1022 | cppi_log_event3("[cppi] alloc bufs: ch dmarcb dmatcb", ch, cppi->rx_ctl[ch].rcb_start_dma_addr, cppi->tx_ctl[ch].tcb_start_dma_addr); | ||
1023 | |||
1024 | // set up receive buffer | ||
1025 | if (ch_buf_cnt[ch][0]) | ||
1026 | { | ||
1027 | dma_recv_buf[ch] = (ch == 0) ? ch0_rx_buf : ((ch == 1) ? ch1_rx_buf : 0); | ||
1028 | cppi_log_event3("[cppi] Alloc fake DMA buf ch", ch, (uint32_t) dma_recv_buf[ch], (uint32_t) __virt_to_phys(dma_recv_buf[ch])); | ||
1029 | } | ||
1030 | else | ||
1031 | { | ||
1032 | dma_recv_buf[ch] = 0; | ||
1033 | } | ||
1034 | } | ||
1035 | |||
1036 | } | ||
1037 | |||
1038 | void tnetv_cppi_cleanup(struct cppi_info *cppi) | ||
1039 | { | ||
1040 | cppi_log_event0("wipe cppi mem"); | ||
1041 | |||
1042 | // wipe cppi memory | ||
1043 | memset(cppi, 0, sizeof(*cppi)); | ||
1044 | } | ||
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/tnetv105_cppi.h b/firmware/target/arm/tms320dm320/sansa-connect/tnetv105_cppi.h new file mode 100644 index 0000000000..9d0ac37cd0 --- /dev/null +++ b/firmware/target/arm/tms320dm320/sansa-connect/tnetv105_cppi.h | |||
@@ -0,0 +1,144 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: $ | ||
9 | * | ||
10 | * Copyright (C) 2021 by Tomasz Moń | ||
11 | * Copied with minor modifications from Sansa Connect Linux driver | ||
12 | * Copyright (c) 2005 Zermatt Systems, Inc. | ||
13 | * Written by: Ben Bostwick | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or | ||
16 | * modify it under the terms of the GNU General Public License | ||
17 | * as published by the Free Software Foundation; either version 2 | ||
18 | * of the License, or (at your option) any later version. | ||
19 | * | ||
20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
21 | * KIND, either express or implied. | ||
22 | * | ||
23 | ****************************************************************************/ | ||
24 | |||
25 | #ifndef TNETV105_CPPI_H | ||
26 | #define TNETV105_CPPI_H | ||
27 | |||
28 | #include <stdint.h> | ||
29 | |||
30 | typedef uint32_t dma_addr_t; | ||
31 | #define USB_CPPI_LOGGING 0 | ||
32 | #define EAGAIN 11 /* Try again */ | ||
33 | #define CPPI_RX_NUM_BUFS 129 | ||
34 | #define CPPI_INFO_MEM_SIZE (2 * CPPI_RX_NUM_BUFS * sizeof(cppi_rcb) + 4 * 2 * sizeof(cppi_tcb)) | ||
35 | |||
36 | #define CPPI_NUM_CHANNELS 4 | ||
37 | #define CPPI_MAX_FRAG 0xFE00 | ||
38 | |||
39 | struct cppi_info; | ||
40 | |||
41 | typedef struct | ||
42 | { | ||
43 | uint32_t HNext; /*< Hardware's pointer to next buffer descriptor */ | ||
44 | uint32_t BufPtr; /*< Pointer to the data buffer */ | ||
45 | uint32_t Off_BLen; /*< Contains buffer offset and buffer length */ | ||
46 | uint32_t mode; /*< SOP, EOP, Ownership, EOQ, Teardown, Q Starv, Length */ | ||
47 | void *Next; | ||
48 | void *Eop; | ||
49 | dma_addr_t dma_handle; | ||
50 | uint32_t dummy; | ||
51 | |||
52 | } cppi_tcb; | ||
53 | |||
54 | typedef struct | ||
55 | { | ||
56 | uint32_t HNext; /*< Hardware's pointer to next buffer descriptor */ | ||
57 | uint32_t BufPtr; /*< Pointer to the data buffer */ | ||
58 | uint32_t Off_BLen; /*< Contains buffer offset and buffer length */ | ||
59 | uint32_t mode; /*< SOP, EOP, Ownership, EOQ, Teardown Complete bits */ | ||
60 | void *Next; | ||
61 | void *Eop; | ||
62 | dma_addr_t dma_handle; | ||
63 | uint32_t fake_bytes; | ||
64 | |||
65 | } cppi_rcb; | ||
66 | |||
67 | typedef struct cppi_txcntl | ||
68 | { | ||
69 | cppi_tcb *TcbPool; | ||
70 | cppi_tcb *TxActQueueHead; | ||
71 | cppi_tcb *TxActQueueTail; | ||
72 | uint32_t TxActQueueCount; | ||
73 | uint32_t TxActive; | ||
74 | cppi_tcb *LastTcbProcessed; | ||
75 | char *TcbStart; | ||
76 | dma_addr_t tcb_start_dma_addr; | ||
77 | int TxNumBuffers; | ||
78 | |||
79 | #ifdef _CPHAL_STATS | ||
80 | uint32_t TxMisQCnt; | ||
81 | uint32_t TxEOQCnt; | ||
82 | uint32_t TxPacketsServiced; | ||
83 | uint32_t TxMaxServiced; | ||
84 | uint32_t NumTxInt; | ||
85 | #endif | ||
86 | } cppi_txcntl; | ||
87 | |||
88 | |||
89 | typedef struct cppi_rxcntl | ||
90 | { | ||
91 | cppi_rcb *RcbPool; | ||
92 | cppi_rcb *RxActQueueHead; | ||
93 | cppi_rcb *RxActQueueTail; | ||
94 | uint32_t RxActQueueCount; | ||
95 | uint32_t RxActive; | ||
96 | char *RcbStart; | ||
97 | dma_addr_t rcb_start_dma_addr; | ||
98 | int RxNumBuffers; | ||
99 | |||
100 | cppi_rcb *RxFakeRcvHead; | ||
101 | cppi_rcb *RxFakeRcvTail; | ||
102 | |||
103 | #ifdef _CPHAL_STATS | ||
104 | uint32_t RxMisQCnt; | ||
105 | uint32_t RxEOQCnt; | ||
106 | uint32_t RxMaxServiced; | ||
107 | uint32_t RxPacketsServiced; | ||
108 | uint32_t NumRxInt; | ||
109 | #endif | ||
110 | } cppi_rxcntl; | ||
111 | |||
112 | typedef struct cppi_info | ||
113 | { | ||
114 | struct cppi_txcntl tx_ctl[CPPI_NUM_CHANNELS]; | ||
115 | struct cppi_rxcntl rx_ctl[CPPI_NUM_CHANNELS]; | ||
116 | |||
117 | uint8_t dma_mem[CPPI_INFO_MEM_SIZE]; | ||
118 | int dma_size; | ||
119 | dma_addr_t dma_handle; | ||
120 | |||
121 | } cppi_info; | ||
122 | |||
123 | #define tnetv_cppi_rx_int_recv_check(cppi, ch) (((cppi)->rx_ctl[(ch)].RxFakeRcvHead) ? 1 : 0) | ||
124 | |||
125 | int tnetv_cppi_init_tcb(struct cppi_info *cppi, int ch); | ||
126 | int tnetv_cppi_flush_tx_queue(struct cppi_info *cppi, int ch); | ||
127 | int tnetv_cppi_send(struct cppi_info *cppi, int ch, dma_addr_t buf, unsigned length, int send_zlp); | ||
128 | int tnetv_cppi_tx_int(struct cppi_info *cppi, int ch); | ||
129 | void tnetv_cppi_free_tcb(struct cppi_info *cppi, int ch); | ||
130 | |||
131 | int tnetv_cppi_init_rcb(struct cppi_info *cppi, int ch); | ||
132 | int tnetv_cppi_flush_rx_queue(struct cppi_info *cppi, int ch); | ||
133 | int tnetv_cppi_rx_return(struct cppi_info *cppi, int ch, cppi_rcb *done_rcb); | ||
134 | int tnetv_cppi_rx_queue_add(struct cppi_info *cppi, int ch, dma_addr_t buf, unsigned length); | ||
135 | int tnetv_cppi_rx_int(struct cppi_info *cppi, int ch); | ||
136 | int tnetv_cppi_rx_int_recv(struct cppi_info *cppi, int ch, int *buf_size, void *buf, int maxpacket); | ||
137 | void tnetv_cppi_free_rcb(struct cppi_info *cppi, int ch); | ||
138 | |||
139 | void tnetv_cppi_init(struct cppi_info *cppi); | ||
140 | void tnetv_cppi_cleanup(struct cppi_info *cppi); | ||
141 | |||
142 | void tnetv_cppi_dump_info(struct cppi_info *cppi); | ||
143 | |||
144 | #endif | ||
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 | } | ||
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/tnetv105_usb_drv.h b/firmware/target/arm/tms320dm320/sansa-connect/tnetv105_usb_drv.h new file mode 100644 index 0000000000..c31c9c6505 --- /dev/null +++ b/firmware/target/arm/tms320dm320/sansa-connect/tnetv105_usb_drv.h | |||
@@ -0,0 +1,335 @@ | |||
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 Zermatt Systems, Inc. | ||
13 | * Written by: Ben Bostwick | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or | ||
16 | * modify it under the terms of the GNU General Public License | ||
17 | * as published by the Free Software Foundation; either version 2 | ||
18 | * of the License, or (at your option) any later version. | ||
19 | * | ||
20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
21 | * KIND, either express or implied. | ||
22 | * | ||
23 | ****************************************************************************/ | ||
24 | |||
25 | #ifndef TNETV105_USB_DRV_H | ||
26 | #define TNETV105_USB_DRV_H | ||
27 | |||
28 | #include <stdint.h> | ||
29 | |||
30 | #define DM320_AHB_PADDR 0x00060000 | ||
31 | #define DM320_VLYNQ_PADDR 0x70000000 | ||
32 | |||
33 | /* TNETV105 Memory Map */ | ||
34 | #define VLYNQ_BASE (0x70000000) | ||
35 | |||
36 | #define TNETV_BASE (VLYNQ_BASE) | ||
37 | #define TNETV_V2USB_BASE (TNETV_BASE + 0x00000200) | ||
38 | #define TNETV_WDOG_BASE (TNETV_BASE + 0x00000280) | ||
39 | #define TNETV_USB_HOST_BASE (TNETV_BASE + 0x00010000) | ||
40 | #define TNETV_USB_DEVICE_BASE (TNETV_BASE + 0x00020000) | ||
41 | |||
42 | #define TNETV_V2USB_REG(x) (TNETV_V2USB_BASE + (x)) | ||
43 | |||
44 | #define TNETV_V2USB_RESET (TNETV_V2USB_REG(0x00)) | ||
45 | #define TNETV_V2USB_CLK_PERF (TNETV_V2USB_REG(0x04)) | ||
46 | #define TNETV_V2USB_CLK_MODE (TNETV_V2USB_REG(0x08)) | ||
47 | #define TNETV_V2USB_CLK_CFG (TNETV_V2USB_REG(0x0C)) | ||
48 | #define TNETV_V2USB_CLK_WKUP (TNETV_V2USB_REG(0x10)) | ||
49 | #define TNETV_V2USB_CLK_PWR (TNETV_V2USB_REG(0x14)) | ||
50 | |||
51 | #define TNETV_V2USB_PID_VID (TNETV_V2USB_REG(0x28)) | ||
52 | |||
53 | #define TNETV_V2USB_GPIO_DOUT (TNETV_V2USB_REG(0x40)) | ||
54 | #define TNETV_V2USB_GPIO_DIN (TNETV_V2USB_REG(0x44)) | ||
55 | #define TNETV_V2USB_GPIO_DIR (TNETV_V2USB_REG(0x48)) | ||
56 | #define TNETV_V2USB_GPIO_FS (TNETV_V2USB_REG(0x4C)) | ||
57 | #define TNETV_V2USB_GPIO_INTF (TNETV_V2USB_REG(0x50)) | ||
58 | #define TNETV_V2USB_GPIO_EOI (TNETV_V2USB_REG(0x54)) | ||
59 | |||
60 | #define TNETV_USB_DEVICE_REG(x) (TNETV_USB_DEVICE_BASE + (x)) | ||
61 | |||
62 | #define TNETV_USB_REV (TNETV_USB_DEVICE_REG(0x00)) | ||
63 | #define TNETV_USB_TX_CTL (TNETV_USB_DEVICE_REG(0x04)) | ||
64 | #define TNETV_USB_TX_TEARDOWN (TNETV_USB_DEVICE_REG(0x08)) | ||
65 | #define TNETV_USB_RX_CTL (TNETV_USB_DEVICE_REG(0x14)) | ||
66 | #define TNETV_USB_RX_TEARDOWN (TNETV_USB_DEVICE_REG(0x18)) | ||
67 | #define TNETV_USB_TX_ENDIAN_CTL (TNETV_USB_DEVICE_REG(0x40)) | ||
68 | #define TNETV_USB_RX_ENDIAN_CTL (TNETV_USB_DEVICE_REG(0x44)) | ||
69 | |||
70 | #define TNETV_USB_RX_FREE_BUF_CNT(ch) (TNETV_USB_DEVICE_REG(0x140 + ((ch) * 4))) | ||
71 | |||
72 | #define TNETV_USB_TX_INT_STATUS (TNETV_USB_DEVICE_REG(0x170)) | ||
73 | #define TNETV_USB_TX_INT_EN (TNETV_USB_DEVICE_REG(0x178)) | ||
74 | #define TNETV_USB_TX_INT_DIS (TNETV_USB_DEVICE_REG(0x17C)) | ||
75 | #define TNETV_USB_VBUS_INT (TNETV_USB_DEVICE_REG(0x180)) | ||
76 | #define TNETV_USB_VBUS_EOI (TNETV_USB_DEVICE_REG(0x184)) | ||
77 | #define TNETV_USB_RX_INT_STATUS (TNETV_USB_DEVICE_REG(0x190)) | ||
78 | #define TNETV_USB_RX_INT_EN (TNETV_USB_DEVICE_REG(0x198)) | ||
79 | #define TNETV_USB_RX_INT_DIS (TNETV_USB_DEVICE_REG(0x19C)) | ||
80 | |||
81 | #define TNETV_USB_RESET_CMPL (TNETV_USB_DEVICE_REG(0x1A0)) | ||
82 | #define TNETV_CPPI_STATE (TNETV_USB_DEVICE_REG(0x1A4)) | ||
83 | |||
84 | #define TNETV_USB_STATUS (TNETV_USB_DEVICE_REG(0x200)) | ||
85 | #define TNETV_USB_CTRL (TNETV_USB_DEVICE_REG(0x204)) | ||
86 | #define TNETV_USB_IF_STATUS (TNETV_USB_DEVICE_REG(0x210)) | ||
87 | #define TNETV_USB_IF_ERR (TNETV_USB_DEVICE_REG(0x214)) | ||
88 | #define TNETV_USB_IF_SM (TNETV_USB_DEVICE_REG(0x218)) | ||
89 | |||
90 | #define TNETV_USB_EP0_CFG (TNETV_USB_DEVICE_REG(0x220)) | ||
91 | #define TNETV_USB_EP0_CNT (TNETV_USB_DEVICE_REG(0x224)) | ||
92 | |||
93 | #define TNETV_USB_EPx_CFG(x) (TNETV_USB_DEVICE_REG(0x220 + (0x10 * (x)))) | ||
94 | #define TNETV_USB_EPx_IN_CNT(x) (TNETV_USB_DEVICE_REG(0x224 + (0x10 * (x)))) | ||
95 | #define TNETV_USB_EPx_OUT_CNT(x) (TNETV_USB_DEVICE_REG(0x228 + (0x10 * (x)))) | ||
96 | #define TNETV_USB_EPx_ADR(x) (TNETV_USB_DEVICE_REG(0x22C + (0x10 * (x)))) | ||
97 | |||
98 | /* USB CPPI Config registers (0x300 - 0x30C) */ | ||
99 | #define TNETV_USB_RNDIS_MODE (TNETV_USB_DEVICE_REG(0x300)) | ||
100 | #define TNETV_USB_CELL_DMA_EN (TNETV_USB_DEVICE_REG(0x30C)) | ||
101 | |||
102 | #define TNETV_USB_RAW_INT (TNETV_USB_DEVICE_REG(0x310)) | ||
103 | #define TNETV_USB_RAW_EOI (TNETV_USB_DEVICE_REG(0x314)) | ||
104 | |||
105 | /* USB DMA setup RAM (0x800 - 0x8FF) */ | ||
106 | #define TNETV_DMA_BASE (TNETV_USB_DEVICE_BASE + 0x800) | ||
107 | #define TNETV_DMA_TX_STATE(ch, wd) ((uint32_t *) ((TNETV_DMA_BASE) + ((ch) * 0x40) + ((wd) * 4))) | ||
108 | #define TNETV_DMA_TX_CMPL(ch) ((TNETV_DMA_BASE) + ((ch) * 0x40) + 0x1C) | ||
109 | |||
110 | #define TNETV_CPPI_TX_WORD_HDP 0 | ||
111 | |||
112 | #define TNETV_DMA_RX_STATE(ch, wd) ((uint32_t *) ((TNETV_DMA_BASE) + ((ch) * 0x40) + 0x20 + ((wd) * 4))) | ||
113 | #define TNETV_DMA_RX_CMPL(ch) ((TNETV_DMA_BASE) + ((ch) * 0x40) + 0x3C) | ||
114 | |||
115 | #define TNETV_CPPI_RX_WORD_HDP 1 | ||
116 | |||
117 | #define TNETV_DMA_NUM_CHANNELS 3 | ||
118 | |||
119 | #define TNETV_DMA_TX_NUM_WORDS 6 | ||
120 | #define TNETV_DMA_RX_NUM_WORDS 7 | ||
121 | |||
122 | |||
123 | /* USB Buffer RAM (0x1000 - 0x1A00) */ | ||
124 | #define TNETV_EP_DATA_ADDR(x) ((uint32_t *) ((TNETV_USB_DEVICE_BASE) + 0x1000 + (x))) | ||
125 | |||
126 | #define TNETV_EP_DATA_SIZE (0xA00) | ||
127 | |||
128 | #define TNETV_V2USB_RESET_DEV (1 << 0) | ||
129 | |||
130 | #define TNETV_USB_CELL_DMA_EN_RX (1 << 0) | ||
131 | #define TNETV_USB_CELL_DMA_EN_TX (1 << 1) | ||
132 | |||
133 | #define TNETV_V2USB_CLK_WKUP_VBUS (1 << 12) | ||
134 | |||
135 | #define DM320_VLYNQ_INTPND_PHY ((DM320_AHB_PADDR) + 0x0314) | ||
136 | |||
137 | |||
138 | /* macro to convert from a linux pointer to a physical address | ||
139 | * to be sent over the VLYNQ bus. The dm320 vlynq rx registers are | ||
140 | * set up so the base address is the physical address of RAM | ||
141 | */ | ||
142 | #define __dma_to_vlynq_phys(addr) ((((uint32_t) (addr)) - 0x01000000)) | ||
143 | #define __vlynq_phys_to_dma(addr) ((((uint32_t) (addr)) + 0x01000000)) | ||
144 | |||
145 | //---------------------------------------------------------------------- | ||
146 | |||
147 | #define USB_FULL_SPEED_MAXPACKET 64 | ||
148 | #define USB_HIGH_SPEED_MAXPACKET 512 | ||
149 | |||
150 | /* WORD offsets into the data memory */ | ||
151 | #define EP0_MAX_PACKET_SIZE 64 /* Control ep - 64 bytes */ | ||
152 | #define EP1_MAX_PACKET_SIZE 512 /* Bulk ep - 512 bytes */ | ||
153 | #define EP2_MAX_PACKET_SIZE 512 /* Bulk ep - 512 bytes */ | ||
154 | #define EP3_MAX_PACKET_SIZE 64 /* Int ep - 64 bytes */ | ||
155 | #define EP4_MAX_PACKET_SIZE 64 /* Int ep - 64 bytes */ | ||
156 | |||
157 | /* BEN TODO: fix this crap */ | ||
158 | #define EP0_OUTPKT_ADDRESS 0 | ||
159 | #define EP0_INPKT_ADDRESS (EP0_MAX_PACKET_SIZE) | ||
160 | #define EP1_XBUFFER_ADDRESS (EP0_MAX_PACKET_SIZE << 1) | ||
161 | #define EP1_YBUFFER_ADDRESS (EP1_XBUFFER_ADDRESS + EP1_MAX_PACKET_SIZE) | ||
162 | #define EP2_XBUFFER_ADDRESS (EP1_XBUFFER_ADDRESS + (EP1_MAX_PACKET_SIZE << 1)) | ||
163 | #define EP2_YBUFFER_ADDRESS (EP2_XBUFFER_ADDRESS + EP2_MAX_PACKET_SIZE) | ||
164 | #define EP3_XBUFFER_ADDRESS (EP2_XBUFFER_ADDRESS + (EP2_MAX_PACKET_SIZE << 1)) | ||
165 | #define EP3_YBUFFER_ADDRESS (EP3_XBUFFER_ADDRESS + EP3_MAX_PACKET_SIZE) | ||
166 | #define EP4_XBUFFER_ADDRESS (EP3_XBUFFER_ADDRESS + (EP3_MAX_PACKET_SIZE << 1)) | ||
167 | #define EP4_YBUFFER_ADDRESS (EP4_XBUFFER_ADDRESS + EP4_MAX_PACKET_SIZE) | ||
168 | #define EP5_XBUFFER_ADDRESS (EP4_XBUFFER_ADDRESS + (EP4_MAX_PACKET_SIZE << 1)) | ||
169 | #define EP5_YBUFFER_ADDRESS (EP5_XBUFFER_ADDRESS + EP1_MAX_PACKET_SIZE) | ||
170 | #define EP6_XBUFFER_ADDRESS (EP5_XBUFFER_ADDRESS + (EP1_MAX_PACKET_SIZE << 1)) | ||
171 | #define EP6_YBUFFER_ADDRESS (EP6_XBUFFER_ADDRESS + EP2_MAX_PACKET_SIZE) | ||
172 | #define EP7_XBUFFER_ADDRESS (EP6_XBUFFER_ADDRESS + (EP2_MAX_PACKET_SIZE << 1)) | ||
173 | #define EP7_YBUFFER_ADDRESS (EP7_XBUFFER_ADDRESS + EP3_MAX_PACKET_SIZE) | ||
174 | #define EP8_XBUFFER_ADDRESS (EP7_XBUFFER_ADDRESS + (EP3_MAX_PACKET_SIZE << 1)) | ||
175 | #define EP8_YBUFFER_ADDRESS (EP8_XBUFFER_ADDRESS + EP4_MAX_PACKET_SIZE) | ||
176 | |||
177 | #define SETUP_PKT_DATA_SIZE 8 | ||
178 | |||
179 | #define EP0_BUF_SIZE_8 0 | ||
180 | #define EP0_BUF_SIZE_16 1 | ||
181 | #define EP0_BUF_SIZE_32 2 | ||
182 | #define EP0_BUF_SIZE_64 3 | ||
183 | |||
184 | /* USB Status register */ | ||
185 | typedef struct { | ||
186 | uint32_t rsvd1 : 5; | ||
187 | uint32_t ep0_out_ack : 1; | ||
188 | uint32_t rsvd2 : 1; | ||
189 | uint32_t ep0_in_ack : 1; | ||
190 | uint32_t rsvd3 : 16; | ||
191 | uint32_t setup_ow : 1; | ||
192 | uint32_t setup : 1; | ||
193 | uint32_t vbus : 1; | ||
194 | uint32_t resume : 1; | ||
195 | uint32_t suspend : 1; | ||
196 | uint32_t reset : 1; | ||
197 | uint32_t sof : 1; | ||
198 | uint32_t any_int : 1; | ||
199 | } UsbStatusStruct; | ||
200 | |||
201 | typedef union { | ||
202 | uint32_t val; | ||
203 | UsbStatusStruct f; | ||
204 | } UsbStatusType; | ||
205 | |||
206 | /* USB Function control register */ | ||
207 | typedef struct { | ||
208 | uint32_t dir : 1; | ||
209 | uint32_t hs_test_mode : 3; | ||
210 | uint32_t rsvd1 : 1; | ||
211 | uint32_t wkup_en : 1; | ||
212 | uint32_t low_pwr_en : 1; | ||
213 | uint32_t connect : 1; | ||
214 | uint32_t rsvd2 : 4; | ||
215 | uint32_t ep0_in_int_en : 1; | ||
216 | uint32_t ep0_out_int_en : 1; | ||
217 | uint32_t err_cnt_en : 2; | ||
218 | uint32_t func_addr : 7; | ||
219 | uint32_t speed : 1; | ||
220 | uint32_t setupow_int_en : 1; | ||
221 | uint32_t setup_int_en : 1; | ||
222 | uint32_t vbus_int_en : 1; | ||
223 | uint32_t resume_int_en : 1; | ||
224 | uint32_t suspend_int_en : 1; | ||
225 | uint32_t reset_int_en : 1; | ||
226 | uint32_t sof_int_en : 1; | ||
227 | uint32_t rsvd3 : 1; | ||
228 | } UsbCtrlStruct; | ||
229 | |||
230 | typedef union { | ||
231 | uint32_t val; | ||
232 | UsbCtrlStruct f; | ||
233 | } UsbCtrlType; | ||
234 | |||
235 | /* Endpoint 0 Control Register */ | ||
236 | typedef struct { | ||
237 | uint32_t buf_size : 2; | ||
238 | uint32_t in_int_en : 1; | ||
239 | uint32_t in_stall : 1; | ||
240 | uint32_t dbl_buf : 1; | ||
241 | uint32_t in_toggle : 1; | ||
242 | uint32_t in_nak_int_en : 1; | ||
243 | uint32_t in_en : 1; | ||
244 | uint32_t res3 : 10; | ||
245 | uint32_t out_int_en : 1; | ||
246 | uint32_t out_stall : 1; | ||
247 | uint32_t res4 : 1; | ||
248 | uint32_t out_toggle : 1; | ||
249 | uint32_t out_nak_int_en : 1; | ||
250 | uint32_t out_en : 1; | ||
251 | uint32_t res6 : 8; | ||
252 | } UsbEp0CtrlStruct; | ||
253 | |||
254 | typedef union { | ||
255 | uint32_t val; | ||
256 | UsbEp0CtrlStruct f; | ||
257 | } UsbEp0CtrlType; | ||
258 | |||
259 | /* Endpoint 0 current packet size register */ | ||
260 | typedef struct { | ||
261 | uint32_t in_xbuf_cnt : 7; | ||
262 | uint32_t in_xbuf_nak : 1; | ||
263 | uint32_t in_ybuf_cnt : 7; | ||
264 | uint32_t in_ybuf_nak : 1; | ||
265 | uint32_t out_xbuf_cnt : 7; | ||
266 | uint32_t out_xbuf_nak : 1; | ||
267 | uint32_t out_ybuf_cnt : 7; | ||
268 | uint32_t out_ybuf_nak : 1; | ||
269 | } UsbEp0ByteCntStruct; | ||
270 | |||
271 | typedef union { | ||
272 | uint32_t val; | ||
273 | UsbEp0ByteCntStruct f; | ||
274 | } UsbEp0ByteCntType; | ||
275 | |||
276 | /* Endpoint n Configuration and Control register */ | ||
277 | typedef struct { | ||
278 | uint32_t res1 : 1; | ||
279 | uint32_t in_toggle_rst : 1; | ||
280 | uint32_t in_ack_int : 1; | ||
281 | uint32_t in_stall : 1; | ||
282 | uint32_t in_dbl_buf : 1; | ||
283 | uint32_t in_toggle : 1; | ||
284 | uint32_t in_nak_int : 1; | ||
285 | uint32_t in_en : 1; | ||
286 | uint32_t res2 : 1; | ||
287 | uint32_t out_toggle_rst : 1; | ||
288 | uint32_t out_ack_int : 1; | ||
289 | uint32_t out_stall : 1; | ||
290 | uint32_t out_dbl_buf : 1; | ||
291 | uint32_t out_toggle : 1; | ||
292 | uint32_t out_nak_int : 1; | ||
293 | uint32_t out_en : 1; | ||
294 | uint32_t in_buf_size : 8; | ||
295 | uint32_t out_buf_size : 8; | ||
296 | } UsbEpCfgCtrlStruct; | ||
297 | |||
298 | typedef union { | ||
299 | uint32_t val; | ||
300 | UsbEpCfgCtrlStruct f; | ||
301 | } UsbEpCfgCtrlType; | ||
302 | |||
303 | /* Endpoint n XY Buffer Start Address register */ | ||
304 | typedef struct { | ||
305 | uint8_t xBuffStartAddrIn; | ||
306 | uint8_t yBuffStartAddrIn; | ||
307 | uint8_t xBuffStartAddrOut; | ||
308 | uint8_t yBuffStartAddrOut; | ||
309 | } UsbEpStartAddrStruct; | ||
310 | |||
311 | typedef union { | ||
312 | uint32_t val; | ||
313 | UsbEpStartAddrStruct f; | ||
314 | } UsbEpStartAddrType; | ||
315 | |||
316 | /* Endpoint n Packet Control register */ | ||
317 | typedef struct { | ||
318 | uint32_t xBufPacketCount : 11; | ||
319 | uint32_t res1 : 4; | ||
320 | uint32_t xbuf_nak : 1; | ||
321 | uint32_t yBufPacketCount : 11; | ||
322 | uint32_t res2 : 4; | ||
323 | uint32_t ybuf_nak : 1; | ||
324 | } UsbEpByteCntStruct; | ||
325 | |||
326 | typedef union { | ||
327 | uint32_t val; | ||
328 | UsbEpByteCntStruct f; | ||
329 | } UsbEpByteCntType; | ||
330 | |||
331 | #define tnetv_usb_reg_read(x) (*((volatile uint32_t *) (x))) | ||
332 | #define tnetv_usb_reg_write(x, val) (*((volatile uint32_t *) (x)) = (uint32_t) (val)) | ||
333 | |||
334 | |||
335 | #endif | ||
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/usb-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/usb-sansaconnect.c index abe6622f0b..986efe374c 100644 --- a/firmware/target/arm/tms320dm320/sansa-connect/usb-sansaconnect.c +++ b/firmware/target/arm/tms320dm320/sansa-connect/usb-sansaconnect.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * \/ \/ \/ \/ \/ | 7 | * \/ \/ \/ \/ \/ |
8 | * $Id: $ | 8 | * $Id: $ |
9 | * | 9 | * |
10 | * Copyright (C) 2011 by Tomasz Moń | 10 | * Copyright (C) 2011-2021 by Tomasz Moń |
11 | * | 11 | * |
12 | * This program is free software; you can redistribute it and/or | 12 | * This program is free software; you can redistribute it and/or |
13 | * modify it under the terms of the GNU General Public License | 13 | * modify it under the terms of the GNU General Public License |
@@ -22,52 +22,12 @@ | |||
22 | #include "config.h" | 22 | #include "config.h" |
23 | #include "system.h" | 23 | #include "system.h" |
24 | #include "kernel.h" | 24 | #include "kernel.h" |
25 | #include "usb.h" | ||
26 | #ifdef HAVE_USBSTACK | ||
27 | #include "usb_drv.h" | ||
28 | #include "usb_core.h" | 25 | #include "usb_core.h" |
29 | #endif | ||
30 | |||
31 | static bool usb_is_connected = false; | ||
32 | 26 | ||
33 | static int usb_detect_callback(struct timeout *tmo) | 27 | static int usb_detect_callback(struct timeout *tmo) |
34 | { | 28 | { |
35 | (void)tmo; | 29 | (void)tmo; |
36 | 30 | usb_status_event(usb_detect()); | |
37 | if (IO_GIO_BITSET0 & (1 << 9)) | ||
38 | { | ||
39 | /* Set GIO33 as normal output, drive it low */ | ||
40 | IO_GIO_FSEL3 &= ~(0x0003); | ||
41 | IO_GIO_BITCLR2 = (1 << 1); | ||
42 | |||
43 | /* Disable M48XI crystal resonator */ | ||
44 | IO_CLK_LPCTL1 |= 0x01; | ||
45 | |||
46 | /* Drive reset low */ | ||
47 | IO_GIO_BITCLR0 = (1 << 7); | ||
48 | |||
49 | /* Disable VLYNQ clock */ | ||
50 | IO_CLK_MOD2 &= ~(1 << 13); | ||
51 | |||
52 | usb_is_connected = false; | ||
53 | } | ||
54 | else | ||
55 | { | ||
56 | /* Enable M48XI crystal resonator */ | ||
57 | IO_CLK_LPCTL1 &= ~(0x01); | ||
58 | |||
59 | /* Set GIO33 as CLKOUT1B */ | ||
60 | IO_GIO_FSEL3 |= 0x0003; | ||
61 | |||
62 | /* Drive reset high */ | ||
63 | IO_GIO_BITSET0 = (1 << 7); | ||
64 | |||
65 | /* Enable VLYNQ clock */ | ||
66 | IO_CLK_MOD2 |= (1 << 13); | ||
67 | |||
68 | usb_is_connected = true; | ||
69 | } | ||
70 | |||
71 | return 0; | 31 | return 0; |
72 | } | 32 | } |
73 | 33 | ||
@@ -82,20 +42,15 @@ void GIO9(void) | |||
82 | timeout_register(&usb_oneshot, usb_detect_callback, HZ, 0); | 42 | timeout_register(&usb_oneshot, usb_detect_callback, HZ, 0); |
83 | } | 43 | } |
84 | 44 | ||
85 | bool usb_drv_connected(void) | ||
86 | { | ||
87 | return false; | ||
88 | } | ||
89 | |||
90 | int usb_detect(void) | 45 | int usb_detect(void) |
91 | { | 46 | { |
92 | if (usb_is_connected == true) | 47 | if (IO_GIO_BITSET0 & (1 << 9)) |
93 | { | 48 | { |
94 | return USB_INSERTED; | 49 | return USB_EXTRACTED; |
95 | } | 50 | } |
96 | else | 51 | else |
97 | { | 52 | { |
98 | return USB_EXTRACTED; | 53 | return USB_INSERTED; |
99 | } | 54 | } |
100 | } | 55 | } |
101 | 56 | ||
@@ -127,14 +82,18 @@ void usb_init_device(void) | |||
127 | 82 | ||
128 | /* Enable USB insert detection interrupt */ | 83 | /* Enable USB insert detection interrupt */ |
129 | IO_INTC_EINT1 |= (1 << 14); | 84 | IO_INTC_EINT1 |= (1 << 14); |
130 | |||
131 | /* Check if USB is connected */ | ||
132 | usb_detect_callback(NULL); | ||
133 | } | 85 | } |
134 | 86 | ||
135 | void usb_enable(bool on) | 87 | void usb_enable(bool on) |
136 | { | 88 | { |
137 | (void)on; | 89 | if (on) |
90 | { | ||
91 | usb_core_init(); | ||
92 | } | ||
93 | else | ||
94 | { | ||
95 | usb_core_exit(); | ||
96 | } | ||
138 | } | 97 | } |
139 | 98 | ||
140 | void usb_attach(void) | 99 | void usb_attach(void) |
diff --git a/firmware/target/arm/tms320dm320/system-dm320.c b/firmware/target/arm/tms320dm320/system-dm320.c index 93cf3c51c4..935f3609a6 100644 --- a/firmware/target/arm/tms320dm320/system-dm320.c +++ b/firmware/target/arm/tms320dm320/system-dm320.c | |||
@@ -494,6 +494,13 @@ void udelay(int usec) { | |||
494 | } | 494 | } |
495 | } | 495 | } |
496 | 496 | ||
497 | void mdelay(int msec) | ||
498 | { | ||
499 | int ms_per_tick = 1000 / HZ; | ||
500 | /* Round up to next full tick */ | ||
501 | sleep((msec + ms_per_tick - 1) / ms_per_tick); | ||
502 | } | ||
503 | |||
497 | #ifdef BOOTLOADER | 504 | #ifdef BOOTLOADER |
498 | void system_prepare_fw_start(void) | 505 | void system_prepare_fw_start(void) |
499 | { | 506 | { |
diff --git a/firmware/target/arm/tms320dm320/system-target.h b/firmware/target/arm/tms320dm320/system-target.h index 59ae61f8df..1c46e909ed 100644 --- a/firmware/target/arm/tms320dm320/system-target.h +++ b/firmware/target/arm/tms320dm320/system-target.h | |||
@@ -30,6 +30,7 @@ | |||
30 | #define CPUFREQ_MAX 175000000 | 30 | #define CPUFREQ_MAX 175000000 |
31 | 31 | ||
32 | void udelay(int usec); | 32 | void udelay(int usec); |
33 | void mdelay(int msec); | ||
33 | 34 | ||
34 | #if defined(CREATIVE_ZVx) && defined(BOOTLOADER) | 35 | #if defined(CREATIVE_ZVx) && defined(BOOTLOADER) |
35 | /* hacky.. */ | 36 | /* hacky.. */ |