diff options
-rw-r--r-- | firmware/target/arm/as3525/usb-drv-as3525v2.c | 391 | ||||
-rw-r--r-- | firmware/target/arm/as3525/usb-drv-as3525v2.h | 13 |
2 files changed, 227 insertions, 177 deletions
diff --git a/firmware/target/arm/as3525/usb-drv-as3525v2.c b/firmware/target/arm/as3525/usb-drv-as3525v2.c index cea87159a6..36791e8dc9 100644 --- a/firmware/target/arm/as3525/usb-drv-as3525v2.c +++ b/firmware/target/arm/as3525/usb-drv-as3525v2.c | |||
@@ -57,23 +57,21 @@ static int __out_ep_list_ep0[NUM_OUT_EP + 1] = {0, OUT_EP_LIST}; | |||
57 | 57 | ||
58 | struct usb_endpoint | 58 | struct usb_endpoint |
59 | { | 59 | { |
60 | bool active; | ||
60 | unsigned int len; | 61 | unsigned int len; |
61 | bool wait; | 62 | bool wait; |
62 | bool busy; | 63 | bool busy; |
63 | bool done; | ||
64 | int status; | 64 | int status; |
65 | struct wakeup complete; | 65 | struct wakeup complete; |
66 | }; | 66 | }; |
67 | 67 | ||
68 | /* NOTE: the following structure is not used to EP0 | 68 | // 0:out, 1:in |
69 | * and make the assumption that each endpoint is | 69 | static struct usb_endpoint endpoints[USB_NUM_ENDPOINTS][2]; |
70 | * either IN or OUT but not bidirectional */ | ||
71 | static struct usb_endpoint endpoints[USB_NUM_ENDPOINTS]; | ||
72 | static struct usb_ctrlrequest ep0_setup_pkt USB_DEVBSS_ATTR; | 70 | static struct usb_ctrlrequest ep0_setup_pkt USB_DEVBSS_ATTR; |
73 | 71 | ||
74 | void usb_attach(void) | 72 | void usb_attach(void) |
75 | { | 73 | { |
76 | logf("usb: attach"); | 74 | logf("usb-drv: attach"); |
77 | usb_enable(true); | 75 | usb_enable(true); |
78 | } | 76 | } |
79 | 77 | ||
@@ -89,7 +87,7 @@ static void usb_delay(void) | |||
89 | 87 | ||
90 | static void as3525v2_connect(void) | 88 | static void as3525v2_connect(void) |
91 | { | 89 | { |
92 | logf("usb: init as3525v2"); | 90 | logf("usb-drv: init as3525v2"); |
93 | /* 1) enable usb core clock */ | 91 | /* 1) enable usb core clock */ |
94 | CGU_PERI |= CGU_USB_CLOCK_ENABLE; | 92 | CGU_PERI |= CGU_USB_CLOCK_ENABLE; |
95 | usb_delay(); | 93 | usb_delay(); |
@@ -134,6 +132,10 @@ static void as3525v2_connect(void) | |||
134 | usb_delay(); | 132 | usb_delay(); |
135 | } | 133 | } |
136 | 134 | ||
135 | static void as3525v2_disconnect(void) | ||
136 | { | ||
137 | } | ||
138 | |||
137 | static void enable_device_interrupts(void) | 139 | static void enable_device_interrupts(void) |
138 | { | 140 | { |
139 | /* Clear any pending interrupt */ | 141 | /* Clear any pending interrupt */ |
@@ -145,7 +147,6 @@ static void enable_device_interrupts(void) | |||
145 | | GINTMSK_enumdone | 147 | | GINTMSK_enumdone |
146 | | GINTMSK_inepintr | 148 | | GINTMSK_inepintr |
147 | | GINTMSK_outepintr | 149 | | GINTMSK_outepintr |
148 | | GINTMSK_otgintr | ||
149 | | GINTMSK_disconnect; | 150 | | GINTMSK_disconnect; |
150 | } | 151 | } |
151 | 152 | ||
@@ -158,11 +159,46 @@ static void flush_tx_fifos(int nums) | |||
158 | while(GRSTCTL & GRSTCTL_txfflsh_flush && i < 0x300) | 159 | while(GRSTCTL & GRSTCTL_txfflsh_flush && i < 0x300) |
159 | i++; | 160 | i++; |
160 | if(GRSTCTL & GRSTCTL_txfflsh_flush) | 161 | if(GRSTCTL & GRSTCTL_txfflsh_flush) |
161 | panicf("usb: hang of flush tx fifos (%x)", nums); | 162 | panicf("usb-drv: hang of flush tx fifos (%x)", nums); |
162 | /* wait 3 phy clocks */ | 163 | /* wait 3 phy clocks */ |
163 | udelay(1); | 164 | udelay(1); |
164 | } | 165 | } |
165 | 166 | ||
167 | static void flush_rx_fifos(void) | ||
168 | { | ||
169 | unsigned int i = 0; | ||
170 | |||
171 | GRSTCTL = GRSTCTL_rxfflsh_flush; | ||
172 | while(GRSTCTL & GRSTCTL_rxfflsh_flush && i < 0x300) | ||
173 | i++; | ||
174 | if(GRSTCTL & GRSTCTL_rxfflsh_flush) | ||
175 | panicf("usb-drv: hang of flush rx fifos"); | ||
176 | /* wait 3 phy clocks */ | ||
177 | udelay(1); | ||
178 | } | ||
179 | |||
180 | static void prepare_setup_ep0(void) | ||
181 | { | ||
182 | /* setup DMA */ | ||
183 | clean_dcache_range((void*)&ep0_setup_pkt, sizeof ep0_setup_pkt); /* force write back */ | ||
184 | DOEPDMA(0) = (unsigned long)&ep0_setup_pkt; /* virtual address=physical address */ | ||
185 | |||
186 | /* Setup EP0 OUT with the following parameters: | ||
187 | * packet count = 1 | ||
188 | * setup packet count = 1 | ||
189 | * transfer size = 8 (setup packet) | ||
190 | */ | ||
191 | DOEPTSIZ(0) = (1 << DEPTSIZ0_supcnt_bitp) | ||
192 | | (1 << DEPTSIZ0_pkcnt_bitp) | ||
193 | | 8; | ||
194 | |||
195 | /* Enable endpoint, clear nak */ | ||
196 | DOEPCTL(0) |= DEPCTL_epena | DEPCTL_cnak; | ||
197 | |||
198 | if(!(DOEPCTL(0) & DEPCTL_epena)) | ||
199 | panicf("usb-drv: failed to enable EP0 !"); | ||
200 | } | ||
201 | |||
166 | static void reset_endpoints(void) | 202 | static void reset_endpoints(void) |
167 | { | 203 | { |
168 | int i, ep; | 204 | int i, ep; |
@@ -178,34 +214,17 @@ static void reset_endpoints(void) | |||
178 | DOEPCTL(ep) = DEPCTL_epdis | DEPCTL_snak; | 214 | DOEPCTL(ep) = DEPCTL_epdis | DEPCTL_snak; |
179 | else | 215 | else |
180 | DOEPCTL(ep) = 0; | 216 | DOEPCTL(ep) = 0; |
181 | /* Setup EP0 OUT with the following parameters: | ||
182 | * packet count = 1 | ||
183 | * setup packet count = 1 | ||
184 | * transfer size = 8 (setup packet) | ||
185 | * Setup EP0 IN/OUT with 64 byte maximum packet size and activate both. Enable transfer on EP0 OUT | ||
186 | */ | ||
187 | DOEPTSIZ(0) = (1 << DEPTSIZ0_supcnt_bitp) | ||
188 | | (1 << DEPTSIZ0_pkcnt_bitp) | ||
189 | | 8; | ||
190 | |||
191 | /* setup DMA */ | ||
192 | clean_dcache_range((void*)&ep0_setup_pkt, sizeof ep0_setup_pkt); /* force write back */ | ||
193 | DOEPDMA(0) = (unsigned long)&ep0_setup_pkt; /* virtual address=physical address */ | ||
194 | |||
195 | /* Enable endpoint, clear nak */ | ||
196 | DOEPCTL(0) = DEPCTL_epena | DEPCTL_cnak | DEPCTL_usbactep | ||
197 | | (DEPCTL_MPS_64 << DEPCTL_mps_bitp); | ||
198 | 217 | ||
199 | /* 64 bytes packet size, active endpoint */ | 218 | /* 64 bytes packet size, active endpoint */ |
200 | DIEPCTL(0) = (DEPCTL_MPS_64 << DEPCTL_mps_bitp) | 219 | DOEPCTL(0) = (DEPCTL_MPS_64 << DEPCTL_mps_bitp) | DEPCTL_usbactep; |
201 | | DEPCTL_usbactep; | 220 | DIEPCTL(0) = (DEPCTL_MPS_64 << DEPCTL_mps_bitp) | DEPCTL_usbactep; |
221 | |||
222 | prepare_setup_ep0(); | ||
202 | } | 223 | } |
203 | 224 | ||
204 | static void core_dev_init(void) | 225 | static void core_dev_init(void) |
205 | { | 226 | { |
206 | unsigned int num_in_ep = 0; | 227 | unsigned int i, ep; |
207 | unsigned int num_out_ep = 0; | ||
208 | unsigned int i; | ||
209 | /* Restart the phy clock */ | 228 | /* Restart the phy clock */ |
210 | PCGCCTL = 0; | 229 | PCGCCTL = 0; |
211 | /* Set phy speed : high speed */ | 230 | /* Set phy speed : high speed */ |
@@ -213,99 +232,45 @@ static void core_dev_init(void) | |||
213 | 232 | ||
214 | /* Check hardware capabilities */ | 233 | /* Check hardware capabilities */ |
215 | if(extract(GHWCFG2, arch) != GHWCFG2_ARCH_INTERNAL_DMA) | 234 | if(extract(GHWCFG2, arch) != GHWCFG2_ARCH_INTERNAL_DMA) |
216 | panicf("usb: wrong architecture (%ld)", extract(GHWCFG2, arch)); | 235 | panicf("usb-drv: wrong architecture (%ld)", extract(GHWCFG2, arch)); |
217 | if(extract(GHWCFG2, hs_phy_type) != GHWCFG2_PHY_TYPE_UTMI) | 236 | if(extract(GHWCFG2, hs_phy_type) != GHWCFG2_PHY_TYPE_UTMI) |
218 | panicf("usb: wrong HS phy type (%ld)", extract(GHWCFG2, hs_phy_type)); | 237 | panicf("usb-drv: wrong HS phy type (%ld)", extract(GHWCFG2, hs_phy_type)); |
219 | if(extract(GHWCFG2, fs_phy_type) != GHWCFG2_PHY_TYPE_UNSUPPORTED) | 238 | if(extract(GHWCFG2, fs_phy_type) != GHWCFG2_PHY_TYPE_UNSUPPORTED) |
220 | panicf("usb: wrong FS phy type (%ld)", extract(GHWCFG2, fs_phy_type)); | 239 | panicf("usb-drv: wrong FS phy type (%ld)", extract(GHWCFG2, fs_phy_type)); |
221 | if(extract(GHWCFG4, utmi_phy_data_width) != 0x2) | 240 | if(extract(GHWCFG4, utmi_phy_data_width) != 0x2) |
222 | panicf("usb: wrong utmi data width (%ld)", extract(GHWCFG4, utmi_phy_data_width)); | 241 | panicf("usb-drv: wrong utmi data width (%ld)", extract(GHWCFG4, utmi_phy_data_width)); |
223 | if(!(GHWCFG4 & GHWCFG4_ded_fifo_en)) /* it seems to be multiple tx fifo support */ | 242 | if(!(GHWCFG4 & GHWCFG4_ded_fifo_en)) /* it seems to be multiple tx fifo support */ |
224 | panicf("usb: no multiple tx fifo"); | 243 | panicf("usb-drv: no multiple tx fifo"); |
225 | 244 | ||
226 | #ifdef USE_CUSTOM_FIFO_LAYOUT | 245 | #ifdef USE_CUSTOM_FIFO_LAYOUT |
227 | if(!(GHWCFG2 & GHWCFG2_dyn_fifo)) | 246 | if(!(GHWCFG2 & GHWCFG2_dyn_fifo)) |
228 | panicf("usb: no dynamic fifo"); | 247 | panicf("usb-drv: no dynamic fifo"); |
229 | if(GRXFSIZ != DATA_FIFO_DEPTH) | 248 | if(GRXFSIZ != DATA_FIFO_DEPTH) |
230 | panicf("usb: wrong data fifo size"); | 249 | panicf("usb-drv: wrong data fifo size"); |
231 | #endif /* USE_CUSTOM_FIFO_LAYOUT */ | 250 | #endif /* USE_CUSTOM_FIFO_LAYOUT */ |
232 | 251 | ||
233 | /* do some logging */ | 252 | /* do some logging */ |
253 | /* | ||
234 | logf("hwcfg1: %08lx", GHWCFG1); | 254 | logf("hwcfg1: %08lx", GHWCFG1); |
235 | logf("hwcfg2: %08lx", GHWCFG2); | 255 | logf("hwcfg2: %08lx", GHWCFG2); |
236 | logf("hwcfg3: %08lx", GHWCFG3); | 256 | logf("hwcfg3: %08lx", GHWCFG3); |
237 | logf("hwcfg4: %08lx", GHWCFG4); | 257 | logf("hwcfg4: %08lx", GHWCFG4); |
258 | */ | ||
238 | 259 | ||
239 | logf("%ld endpoints", extract(GHWCFG2, num_ep)); | 260 | if(USB_NUM_ENDPOINTS != extract(GHWCFG2, num_ep)) |
240 | num_in_ep = 0; | 261 | panicf("usb-drv: wrong endpoint number"); |
241 | num_out_ep = 0; | ||
242 | for(i = 0; i < extract(GHWCFG2, num_ep); i++) | ||
243 | { | ||
244 | bool in = false, out = false; | ||
245 | switch((GHWCFG1 >> GHWCFG1_epdir_bitp(i)) & GHWCFG1_epdir_bits) | ||
246 | { | ||
247 | case GHWCFG1_EPDIR_BIDIR: in = out = true; break; | ||
248 | case GHWCFG1_EPDIR_IN: in = true; break; | ||
249 | case GHWCFG1_EPDIR_OUT: out = true; break; | ||
250 | default: panicf("usb: invalid epdir"); | ||
251 | } | ||
252 | /* don't count EP0 which is special and always bidirectional */ | ||
253 | if(in && i != 0) | ||
254 | num_in_ep++; | ||
255 | if(out && i != 0) | ||
256 | num_out_ep++; | ||
257 | logf(" EP%d: IN=%s OUT=%s", i, in ? "yes" : "no", out ? "yes" : "no"); | ||
258 | } | ||
259 | |||
260 | if(num_in_ep != extract(GHWCFG4, num_in_ep)) | ||
261 | panicf("usb: num in ep mismatch(%d,%lu)", num_in_ep, extract(GHWCFG4, num_in_ep)); | ||
262 | if(num_in_ep != NUM_IN_EP) | ||
263 | panicf("usb: num in ep static mismatch(%u,%u)", num_in_ep, NUM_IN_EP); | ||
264 | if(num_out_ep != NUM_OUT_EP) | ||
265 | panicf("usb: num out ep static mismatch(%u,%u)", num_out_ep, NUM_OUT_EP); | ||
266 | |||
267 | logf("%d in ep, %d out ep", num_in_ep, num_out_ep); | ||
268 | |||
269 | logf("initial:"); | ||
270 | logf(" tot fifo sz: %lx", extract(GHWCFG3, dfifo_len)); | ||
271 | logf(" rx fifo: [%04x,+%4lx]", 0, GRXFSIZ); | ||
272 | logf(" nptx fifo: [%04lx,+%4lx]", GET_FIFOSIZE_START_ADR(GNPTXFSIZ), | ||
273 | GET_FIFOSIZE_DEPTH(GNPTXFSIZ)); | ||
274 | |||
275 | #ifdef USE_CUSTOM_FIFO_LAYOUT | ||
276 | /* Setup FIFOs */ | ||
277 | /* Organize FIFO as follow: | ||
278 | * 0 -> rxfsize : RX fifo | ||
279 | * rxfsize -> rxfsize + nptxfsize : TX fifo for first IN ep | ||
280 | * rxfsize + nptxfsize -> rxfsize + 2 * nptxfsize : TX fifo for second IN ep | ||
281 | * rxfsize + 2 * nptxfsize -> rxfsize + 3 * nptxfsize : TX fifo for third IN ep | ||
282 | * ... | ||
283 | */ | ||
284 | |||
285 | unsigned short adr = 0; | ||
286 | unsigned short depth = RX_FIFO_SIZE; | ||
287 | GRXFSIZ = depth; | ||
288 | adr += depth; | ||
289 | depth = NPTX_FIFO_SIZE; | ||
290 | GNPTXFSIZ = MAKE_FIFOSIZE_DATA(adr, depth); | ||
291 | adr += depth; | ||
292 | 262 | ||
293 | for(i = 1; i <= NUM_IN_EP; i++) | 263 | FOR_EACH_IN_EP_AND_EP0(i, ep) |
294 | { | 264 | { |
295 | depth = EPTX_FIFO_SIZE; | 265 | int type = (GHWCFG1 >> GHWCFG1_epdir_bitp(ep)) & GHWCFG1_epdir_bits; |
296 | DIEPTXFSIZ(i) = MAKE_FIFOSIZE_DATA(adr, depth); | 266 | if(type != GHWCFG1_EPDIR_BIDIR && type != GHWCFG1_EPDIR_IN) |
297 | adr += depth; | 267 | panicf("usb-drv: EP%d is no IN or BIDIR", ep); |
298 | } | 268 | } |
299 | 269 | FOR_EACH_OUT_EP_AND_EP0(i, ep) | |
300 | if(adr > DATA_FIFO_DEPTH) | ||
301 | panicf("usb: total data fifo size exceeded"); | ||
302 | #endif /* USE_CUSTOM_FIFO_LAYOUT */ | ||
303 | |||
304 | for(i = 1; i <= NUM_IN_EP; i++) | ||
305 | { | 270 | { |
306 | logf(" dieptx fifo(%2u): [%04lx,+%4lx]", i, | 271 | int type = (GHWCFG1 >> GHWCFG1_epdir_bitp(ep)) & GHWCFG1_epdir_bits; |
307 | GET_FIFOSIZE_START_ADR(DIEPTXFSIZ(i)), | 272 | if(type != GHWCFG1_EPDIR_BIDIR && type != GHWCFG1_EPDIR_OUT) |
308 | GET_FIFOSIZE_DEPTH(DIEPTXFSIZ(i))); | 273 | panicf("usb-drv: EP%d is no OUT or BIDIR", ep); |
309 | } | 274 | } |
310 | 275 | ||
311 | /* Setup interrupt masks for endpoints */ | 276 | /* Setup interrupt masks for endpoints */ |
@@ -367,12 +332,19 @@ static void disable_global_interrupts(void) | |||
367 | 332 | ||
368 | void usb_drv_init(void) | 333 | void usb_drv_init(void) |
369 | { | 334 | { |
335 | unsigned i, ep; | ||
370 | logf("usb_drv_init"); | 336 | logf("usb_drv_init"); |
337 | /* Boost cpu */ | ||
338 | cpu_boost(1); | ||
371 | /* Enable PHY and clocks (but leave pullups disabled) */ | 339 | /* Enable PHY and clocks (but leave pullups disabled) */ |
372 | as3525v2_connect(); | 340 | as3525v2_connect(); |
373 | logf("usb: synopsis id: %lx", GSNPSID); | 341 | logf("usb-drv: synopsis id: %lx", GSNPSID); |
374 | /* Core init */ | 342 | /* Core init */ |
375 | core_init(); | 343 | core_init(); |
344 | FOR_EACH_IN_EP_AND_EP0(i, ep) | ||
345 | wakeup_init(&endpoints[ep][DIR_IN].complete); | ||
346 | FOR_EACH_OUT_EP_AND_EP0(i, ep) | ||
347 | wakeup_init(&endpoints[ep][DIR_OUT].complete); | ||
376 | /* Enable global interrupts */ | 348 | /* Enable global interrupts */ |
377 | enable_global_interrupts(); | 349 | enable_global_interrupts(); |
378 | } | 350 | } |
@@ -382,40 +354,52 @@ void usb_drv_exit(void) | |||
382 | logf("usb_drv_exit"); | 354 | logf("usb_drv_exit"); |
383 | 355 | ||
384 | disable_global_interrupts(); | 356 | disable_global_interrupts(); |
357 | as3525v2_disconnect(); | ||
358 | cpu_boost(0); | ||
385 | } | 359 | } |
386 | 360 | ||
387 | static void handle_ep_int(int ep, bool dir_in) | 361 | static void handle_ep_int(int ep, bool dir_in) |
388 | { | 362 | { |
363 | struct usb_endpoint *endpoint = &endpoints[ep][dir_in]; | ||
389 | if(dir_in) | 364 | if(dir_in) |
390 | { | 365 | { |
391 | if(DIEPINT(ep) & DIEPINT_ahberr) | 366 | if(DIEPINT(ep) & DIEPINT_ahberr) |
392 | panicf("usb: ahb error on EP%d IN", ep); | 367 | panicf("usb-drv: ahb error on EP%d IN", ep); |
393 | if(DIEPINT(ep) & DIEPINT_xfercompl) | 368 | if(DIEPINT(ep) & DIEPINT_xfercompl) |
394 | { | 369 | { |
395 | logf("usb: xfer complete on EP%d IN", ep); | 370 | logf("usb-drv: xfer complete on EP%d IN", ep); |
396 | if(endpoints[ep].busy) | 371 | if(endpoint->busy) |
397 | { | 372 | { |
398 | endpoints[ep].busy = false; | 373 | endpoint->busy = false; |
399 | endpoints[ep].status = 0; | 374 | endpoint->status = 0; |
400 | endpoints[ep].done = true; | ||
401 | /* works even for PE0 */ | 375 | /* works even for PE0 */ |
402 | int transfered = endpoints[ep].len - (DIEPTSIZ(ep) & DEPTSIZ_xfersize_bits); | 376 | int transfered = endpoint->len - (DIEPTSIZ(ep) & DEPTSIZ_xfersize_bits); |
403 | clean_dcache_range((void *)DIEPDMA(ep), transfered); | 377 | logf("len=%d reg=%ld xfer=%d", endpoint->len, |
378 | (DIEPTSIZ(ep) & DEPTSIZ_xfersize_bits), | ||
379 | transfered); | ||
380 | invalidate_dcache_range((void *)DIEPDMA(ep), transfered); | ||
381 | DIEPCTL(ep) |= DEPCTL_snak; | ||
382 | /* if the transfer length is 0 on EP0, this is a ack | ||
383 | * so we setup EP0 to receive next setup */ | ||
384 | if(ep == 0 && endpoint->len == 0) | ||
385 | prepare_setup_ep0(); | ||
386 | DIEPCTL(ep) |= DEPCTL_snak; | ||
404 | usb_core_transfer_complete(ep, USB_DIR_IN, 0, transfered); | 387 | usb_core_transfer_complete(ep, USB_DIR_IN, 0, transfered); |
388 | wakeup_signal(&endpoint->complete); | ||
405 | } | 389 | } |
406 | } | 390 | } |
407 | if(DIEPINT(ep) & DIEPINT_timeout) | 391 | if(DIEPINT(ep) & DIEPINT_timeout) |
408 | { | 392 | { |
409 | logf("usb: timeout on EP%d IN", ep); | 393 | logf("usb-drv: timeout on EP%d IN", ep); |
410 | if(endpoints[ep].busy) | 394 | if(endpoint->busy) |
411 | { | 395 | { |
412 | endpoints[ep].busy = false; | 396 | endpoint->busy = false; |
413 | endpoints[ep].status = 1; | 397 | endpoint->status = 1; |
414 | endpoints[ep].done = true; | ||
415 | /* for safety, act as if no bytes as been transfered */ | 398 | /* for safety, act as if no bytes as been transfered */ |
416 | endpoints[ep].len = 0; | 399 | endpoint->len = 0; |
400 | DIEPCTL(ep) |= DEPCTL_snak; | ||
417 | usb_core_transfer_complete(ep, USB_DIR_IN, 1, 0); | 401 | usb_core_transfer_complete(ep, USB_DIR_IN, 1, 0); |
418 | wakeup_signal(&endpoints[ep].complete); | 402 | wakeup_signal(&endpoint->complete); |
419 | } | 403 | } |
420 | } | 404 | } |
421 | /* clear interrupts */ | 405 | /* clear interrupts */ |
@@ -424,34 +408,44 @@ static void handle_ep_int(int ep, bool dir_in) | |||
424 | else | 408 | else |
425 | { | 409 | { |
426 | if(DOEPINT(ep) & DOEPINT_ahberr) | 410 | if(DOEPINT(ep) & DOEPINT_ahberr) |
427 | panicf("usb: ahb error on EP%d OUT", ep); | 411 | panicf("usb-drv: ahb error on EP%d OUT", ep); |
428 | if(DOEPINT(ep) & DOEPINT_xfercompl) | 412 | if(DOEPINT(ep) & DOEPINT_xfercompl) |
429 | { | 413 | { |
430 | logf("usb: xfer complete on EP%d OUT", ep); | 414 | logf("usb-drv: xfer complete on EP%d OUT", ep); |
431 | if(endpoints[ep].busy) | 415 | if(endpoint->busy) |
432 | { | 416 | { |
433 | endpoints[ep].busy = false; | 417 | endpoint->busy = false; |
434 | endpoints[ep].status = 0; | 418 | endpoint->status = 0; |
435 | endpoints[ep].done = true; | 419 | /* works even for EP0 */ |
436 | /* works even for PE0 */ | 420 | int transfered = endpoint->len - (DOEPTSIZ(ep) & DEPTSIZ_xfersize_bits); |
437 | int transfered = endpoints[ep].len - (DOEPTSIZ(ep) & DEPTSIZ_xfersize_bits); | 421 | logf("len=%d reg=%ld xfer=%d", endpoint->len, |
438 | clean_dcache_range((void *)DOEPDMA(ep), transfered); | 422 | (DOEPTSIZ(ep) & DEPTSIZ_xfersize_bits), |
423 | transfered); | ||
424 | invalidate_dcache_range((void *)DOEPDMA(ep), transfered); | ||
425 | /* if the transfer length is 0 on EP0, this is a ack | ||
426 | * so we setup EP0 to receive next setup */ | ||
427 | if(ep == 0 && endpoint->len == 0) | ||
428 | prepare_setup_ep0(); | ||
429 | else | ||
430 | DOEPCTL(ep) |= DEPCTL_snak; | ||
439 | usb_core_transfer_complete(ep, USB_DIR_OUT, 0, transfered); | 431 | usb_core_transfer_complete(ep, USB_DIR_OUT, 0, transfered); |
432 | wakeup_signal(&endpoint->complete); | ||
440 | } | 433 | } |
441 | } | 434 | } |
442 | if(DOEPINT(ep) & DOEPINT_setup) | 435 | if(DOEPINT(ep) & DOEPINT_setup) |
443 | { | 436 | { |
444 | logf("usb: setup on EP%d OUT", ep); | 437 | logf("usb-drv: setup on EP%d OUT", ep); |
438 | logf("rt=%x r=%x", ep0_setup_pkt.bRequestType, ep0_setup_pkt.bRequest); | ||
445 | if(ep != 0) | 439 | if(ep != 0) |
446 | panicf("usb: setup not on EP0, this is impossible"); | 440 | panicf("usb-drv: setup not on EP0, this is impossible"); |
447 | clean_dcache_range((void*)&ep0_setup_pkt, sizeof ep0_setup_pkt); /* force write back */ | 441 | DOEPCTL(ep) |= DEPCTL_snak; |
442 | /* handle the set address here because of a bug in the usb core */ | ||
443 | invalidate_dcache_range((void*)&ep0_setup_pkt, sizeof ep0_setup_pkt); /* force write back */ | ||
444 | if(ep0_setup_pkt.bRequestType == USB_TYPE_STANDARD && | ||
445 | ep0_setup_pkt.bRequest == USB_REQ_SET_ADDRESS) | ||
446 | usb_drv_set_address(ep0_setup_pkt.wValue); | ||
448 | usb_core_control_request(&ep0_setup_pkt); | 447 | usb_core_control_request(&ep0_setup_pkt); |
449 | } | 448 | } |
450 | /* setup EP0 for the next transfer */ | ||
451 | DOEPTSIZ(0) = (1 << DEPTSIZ0_supcnt_bitp) | (1 << DEPTSIZ0_pkcnt_bitp) | 8; | ||
452 | DOEPDMA(0) = (unsigned long)&ep0_setup_pkt; /* virtual address=physical address */ | ||
453 | DOEPCTL(0) |= DEPCTL_epena | DEPCTL_cnak; | ||
454 | |||
455 | /* clear interrupts */ | 449 | /* clear interrupts */ |
456 | DOEPINT(ep) = DOEPINT(ep); | 450 | DOEPINT(ep) = DOEPINT(ep); |
457 | } | 451 | } |
@@ -459,7 +453,7 @@ static void handle_ep_int(int ep, bool dir_in) | |||
459 | 453 | ||
460 | static void handle_ep_ints(void) | 454 | static void handle_ep_ints(void) |
461 | { | 455 | { |
462 | logf("usb: ep int"); | 456 | logf("usb-drv: ep int"); |
463 | /* we must read it */ | 457 | /* we must read it */ |
464 | unsigned long daint = DAINT; | 458 | unsigned long daint = DAINT; |
465 | unsigned i, ep; | 459 | unsigned i, ep; |
@@ -485,38 +479,39 @@ void INT_USB(void) | |||
485 | /* device part */ | 479 | /* device part */ |
486 | if(sts & GINTMSK_usbreset) | 480 | if(sts & GINTMSK_usbreset) |
487 | { | 481 | { |
488 | logf("usb: bus reset"); | 482 | logf("usb-drv: bus reset"); |
489 | 483 | ||
490 | /* Clear the Remote Wakeup Signalling */ | 484 | /* Clear the Remote Wakeup Signalling */ |
491 | DCTL &= ~DCTL_rmtwkupsig; | 485 | //DCTL &= ~DCTL_rmtwkupsig; |
492 | 486 | ||
493 | /* Flush FIFOs */ | 487 | /* Flush FIFOs */ |
494 | flush_tx_fifos(0x10); | 488 | flush_tx_fifos(0x10); |
489 | flush_rx_fifos(); | ||
495 | 490 | ||
496 | reset_endpoints(); | 491 | reset_endpoints(); |
497 | 492 | ||
498 | /* Reset Device Address */ | 493 | /* Reset Device Address */ |
499 | DCFG &= bitm(DCFG, devadr); | 494 | DCFG &= ~bitm(DCFG, devadr); |
500 | 495 | ||
501 | usb_core_bus_reset(); | 496 | usb_core_bus_reset(); |
502 | } | 497 | } |
503 | 498 | ||
504 | if(sts & GINTMSK_enumdone) | 499 | if(sts & GINTMSK_enumdone) |
505 | { | 500 | { |
506 | logf("usb: enum done"); | 501 | logf("usb-drv: enum done"); |
507 | 502 | ||
508 | /* read speed */ | 503 | /* read speed */ |
509 | switch(extract(DSTS, enumspd)) | 504 | switch(extract(DSTS, enumspd)) |
510 | { | 505 | { |
511 | case DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ: | 506 | case DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ: |
512 | logf("usb: HS"); | 507 | logf("usb-drv: HS"); |
513 | break; | 508 | break; |
514 | case DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ: | 509 | case DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ: |
515 | case DSTS_ENUMSPD_FS_PHY_48MHZ: | 510 | case DSTS_ENUMSPD_FS_PHY_48MHZ: |
516 | logf("usb: FS"); | 511 | logf("usb-drv: FS"); |
517 | break; | 512 | break; |
518 | case DSTS_ENUMSPD_LS_PHY_6MHZ: | 513 | case DSTS_ENUMSPD_LS_PHY_6MHZ: |
519 | panicf("usb: LS is not supported"); | 514 | panicf("usb-drv: LS is not supported"); |
520 | } | 515 | } |
521 | 516 | ||
522 | /* fixme: change EP0 mps here */ | 517 | /* fixme: change EP0 mps here */ |
@@ -527,11 +522,8 @@ void INT_USB(void) | |||
527 | handle_ep_ints(); | 522 | handle_ep_ints(); |
528 | } | 523 | } |
529 | 524 | ||
530 | /* common part */ | 525 | if(sts & GINTMSK_disconnect) |
531 | if(sts & GINTMSK_otgintr) | 526 | panicf("usb-drv: disconnect"); |
532 | { | ||
533 | panicf("usb: otg int"); | ||
534 | } | ||
535 | 527 | ||
536 | GINTSTS = GINTSTS; | 528 | GINTSTS = GINTSTS; |
537 | } | 529 | } |
@@ -545,40 +537,105 @@ int usb_drv_request_endpoint(int type, int dir) | |||
545 | { | 537 | { |
546 | (void) type; | 538 | (void) type; |
547 | (void) dir; | 539 | (void) dir; |
540 | logf("usb-drv: request endpoint (type=%d,dir=%s)", type, dir == USB_DIR_IN ? "IN" : "OUT"); | ||
548 | return -1; | 541 | return -1; |
549 | } | 542 | } |
550 | 543 | ||
551 | void usb_drv_release_endpoint(int ep) | 544 | void usb_drv_release_endpoint(int ep) |
552 | { | 545 | { |
553 | (void) ep; | 546 | //logf("usb-drv: release EP%d %s", EP_NUM(ep), EP_DIR(ep) == DIR_IN ? "IN" : "OUT"); |
547 | endpoints[EP_NUM(ep)][EP_DIR(ep)].active = false; | ||
554 | } | 548 | } |
555 | 549 | ||
556 | void usb_drv_cancel_all_transfers(void) | 550 | void usb_drv_cancel_all_transfers(void) |
557 | { | 551 | { |
552 | logf("usb-drv: cancel all transfers"); | ||
553 | int flags = disable_irq_save(); | ||
554 | unsigned i, ep; | ||
555 | FOR_EACH_IN_EP(i, ep) | ||
556 | { | ||
557 | endpoints[ep][DIR_IN].status = 1; | ||
558 | endpoints[ep][DIR_IN].wait = false; | ||
559 | endpoints[ep][DIR_IN].busy = false; | ||
560 | wakeup_signal(&endpoints[ep][DIR_IN].complete); | ||
561 | DIEPCTL(ep) = (DIEPCTL(ep) & ~DEPCTL_usbactep) | DEPCTL_epdis; | ||
562 | } | ||
563 | FOR_EACH_OUT_EP(i, ep) | ||
564 | { | ||
565 | endpoints[ep][DIR_OUT].status = 1; | ||
566 | endpoints[ep][DIR_OUT].wait = false; | ||
567 | endpoints[ep][DIR_OUT].busy = false; | ||
568 | wakeup_signal(&endpoints[ep][DIR_OUT].complete); | ||
569 | DOEPCTL(ep) = (DOEPCTL(ep) & ~DEPCTL_usbactep) | DEPCTL_epdis; | ||
570 | } | ||
571 | |||
572 | restore_irq(flags); | ||
573 | } | ||
574 | |||
575 | static int usb_drv_transfer(int ep, void *ptr, int len, bool dir_in, bool blocking) | ||
576 | { | ||
577 | ep = EP_NUM(ep); | ||
578 | logf("usb-drv: xfer EP%d, len=%d, dir_in=%d, blocking=%d", ep, | ||
579 | len, dir_in, blocking); | ||
580 | |||
581 | volatile unsigned long *epctl = dir_in ? &DIEPCTL(ep) : &DOEPCTL(ep); | ||
582 | volatile unsigned long *eptsiz = dir_in ? &DIEPTSIZ(ep) : &DOEPTSIZ(ep); | ||
583 | volatile unsigned long *epdma = dir_in ? &DIEPDMA(ep) : &DOEPDMA(ep); | ||
584 | struct usb_endpoint *endpoint = &endpoints[ep][dir_in]; | ||
585 | #define DEPCTL *epctl | ||
586 | #define DEPTSIZ *eptsiz | ||
587 | #define DEPDMA *epdma | ||
588 | |||
589 | if(endpoint->busy) | ||
590 | panicf("usb-drv: EP%d %s is already busy", ep, dir_in ? "IN" : "OUT"); | ||
591 | |||
592 | if(DEPCTL & DEPCTL_stall) | ||
593 | { | ||
594 | logf("usb-drv: cannot receive on a stalled endpoint"); | ||
595 | return -1; | ||
596 | } | ||
597 | endpoint->busy = true; | ||
598 | endpoint->len = len; | ||
599 | endpoint->wait = blocking; | ||
600 | DEPCTL |= DEPCTL_usbactep; | ||
601 | |||
602 | int mps = 64; | ||
603 | int nb_packets = (len + mps - 1) / mps; | ||
604 | |||
605 | if(len == 0) | ||
606 | DEPTSIZ = 1 << DEPTSIZ_pkcnt_bitp; | ||
607 | else | ||
608 | DEPTSIZ = (nb_packets << DEPTSIZ_pkcnt_bitp) | len; | ||
609 | clean_dcache_range(ptr, len); | ||
610 | DEPDMA = (unsigned long)ptr; | ||
611 | DEPCTL |= DEPCTL_epena | DEPCTL_cnak; | ||
612 | |||
613 | /* fixme: check if endpoint was really enabled ? */ | ||
614 | |||
615 | if(blocking) | ||
616 | wakeup_wait(&endpoint->complete, TIMEOUT_BLOCK); | ||
617 | if(endpoint->status != 0) | ||
618 | return -1; | ||
619 | return 0; | ||
620 | |||
621 | #undef DEPCTL | ||
622 | #undef DEPTSIZ | ||
623 | #undef DEPDMA | ||
558 | } | 624 | } |
559 | 625 | ||
560 | int usb_drv_recv(int ep, void *ptr, int len) | 626 | int usb_drv_recv(int ep, void *ptr, int len) |
561 | { | 627 | { |
562 | (void) ep; | 628 | return usb_drv_transfer(ep, ptr, len, false, false); |
563 | (void) ptr; | ||
564 | (void) len; | ||
565 | return -1; | ||
566 | } | 629 | } |
567 | 630 | ||
568 | int usb_drv_send(int ep, void *ptr, int len) | 631 | int usb_drv_send(int ep, void *ptr, int len) |
569 | { | 632 | { |
570 | (void) ep; | 633 | return usb_drv_transfer(ep, ptr, len, true, true); |
571 | (void) ptr; | ||
572 | (void) len; | ||
573 | return -1; | ||
574 | } | 634 | } |
575 | 635 | ||
576 | int usb_drv_send_nonblocking(int ep, void *ptr, int len) | 636 | int usb_drv_send_nonblocking(int ep, void *ptr, int len) |
577 | { | 637 | { |
578 | (void) ep; | 638 | return usb_drv_transfer(ep, ptr, len, true, false); |
579 | (void) ptr; | ||
580 | (void) len; | ||
581 | return -1; | ||
582 | } | 639 | } |
583 | 640 | ||
584 | 641 | ||
@@ -589,7 +646,12 @@ void usb_drv_set_test_mode(int mode) | |||
589 | 646 | ||
590 | void usb_drv_set_address(int address) | 647 | void usb_drv_set_address(int address) |
591 | { | 648 | { |
592 | (void) address; | 649 | /* ignore it if addres is already set */ |
650 | if(extract(DCFG, devadr) == 0) | ||
651 | { | ||
652 | logf("usb-drv: set address %x", address); | ||
653 | DCFG = (DCFG & ~bitm(DCFG, devadr)) | (address << DCFG_devadr_bitp); | ||
654 | } | ||
593 | } | 655 | } |
594 | 656 | ||
595 | void usb_drv_stall(int ep, bool stall, bool in) | 657 | void usb_drv_stall(int ep, bool stall, bool in) |
@@ -597,6 +659,7 @@ void usb_drv_stall(int ep, bool stall, bool in) | |||
597 | (void) ep; | 659 | (void) ep; |
598 | (void) stall; | 660 | (void) stall; |
599 | (void) in; | 661 | (void) in; |
662 | logf("usb-drv: %sstall EP%d %s", stall ? "" : "un", ep, in ? "IN" : "OUT"); | ||
600 | } | 663 | } |
601 | 664 | ||
602 | bool usb_drv_stalled(int ep, bool in) | 665 | bool usb_drv_stalled(int ep, bool in) |
diff --git a/firmware/target/arm/as3525/usb-drv-as3525v2.h b/firmware/target/arm/as3525/usb-drv-as3525v2.h index be4b2da992..e5cad2ee05 100644 --- a/firmware/target/arm/as3525/usb-drv-as3525v2.h +++ b/firmware/target/arm/as3525/usb-drv-as3525v2.h | |||
@@ -453,19 +453,6 @@ | |||
453 | /** | 453 | /** |
454 | * Parameters | 454 | * Parameters |
455 | */ | 455 | */ |
456 | /*#define USE_CUSTOM_FIFO_LAYOUT*/ | ||
457 | |||
458 | #ifdef USE_CUSTOM_FIFO_LAYOUT | ||
459 | /* Data fifo: includes RX fifo, non period TX fifo and periodic fifos | ||
460 | * NOTE: this is a hardware parameter, it cannot be changed ! */ | ||
461 | #define DATA_FIFO_DEPTH 0x535 | ||
462 | /* size of the FX fifo */ | ||
463 | #define RX_FIFO_SIZE 0x100 | ||
464 | /* size of the non periodic TX fifo */ | ||
465 | #define NPTX_FIFO_SIZE 0x100 | ||
466 | /* size of each TX ep fifo size */ | ||
467 | #define EPTX_FIFO_SIZE 0x100 | ||
468 | #endif /* USE_CUSTOM_FIFO_LAYOUT */ | ||
469 | 456 | ||
470 | /* Number of IN/OUT endpoints */ | 457 | /* Number of IN/OUT endpoints */ |
471 | #define NUM_IN_EP 3 | 458 | #define NUM_IN_EP 3 |