summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRafaël Carré <rafael.carre@gmail.com>2011-12-31 21:22:48 +0000
committerRafaël Carré <rafael.carre@gmail.com>2011-12-31 21:22:48 +0000
commit7b22ea0d377f69ec7a0d7be7215ef3c560ce13e7 (patch)
tree72666d2b75270d5809bbd31f436fab3a9c730e36
parentfd5cb720c4b922979e854ee3d07979b81f60e776 (diff)
downloadrockbox-7b22ea0d377f69ec7a0d7be7215ef3c560ce13e7.tar.gz
rockbox-7b22ea0d377f69ec7a0d7be7215ef3c560ce13e7.zip
usb-drv-as3525v2.c: merge in usb-s3c6400x.c
as3525v2 specific part is 400 LoC, ipod specific less than 300 (comments and whitespace included) TODO: merge properly git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31509 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--firmware/target/arm/as3525/usb-drv-as3525v2.c441
-rw-r--r--firmware/target/arm/usb-s3c6400x.c408
2 files changed, 407 insertions, 442 deletions
diff --git a/firmware/target/arm/as3525/usb-drv-as3525v2.c b/firmware/target/arm/as3525/usb-drv-as3525v2.c
deleted file mode 100644
index 8c19758b65..0000000000
--- a/firmware/target/arm/as3525/usb-drv-as3525v2.c
+++ /dev/null
@@ -1,441 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright © 2010 Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "usb.h"
23#include "usb_drv.h"
24#include "as3525v2.h"
25#include "clock-target.h"
26#include "ascodec.h"
27#include "as3514.h"
28#include "stdbool.h"
29#include "string.h"
30#include "stdio.h"
31#include "panic.h"
32#include "mmu-arm.h"
33#include "system.h"
34//#define LOGF_ENABLE
35#include "logf.h"
36#include "usb_core.h"
37
38static const uint8_t in_ep_list[] = {0, 1, 3, 5};
39static const uint8_t out_ep_list[] = {0, 2, 4};
40
41/* state of EP0 (to correctly schedule setup packet enqueing) */
42enum ep0state
43{
44 /* Setup packet is enqueud, waiting for actual data */
45 EP0_WAIT_SETUP = 0,
46 /* Waiting for ack (either IN or OUT) */
47 EP0_WAIT_ACK = 1,
48 /* Ack complete, waiting for data (either IN or OUT)
49 * This state is necessary because if both ack and data complete in the
50 * same interrupt, we might process data completion before ack completion
51 * so we need this bizarre state */
52 EP0_WAIT_DATA = 2,
53 /* Setup packet complete, waiting for ack and data */
54 EP0_WAIT_DATA_ACK = 3,
55};
56
57/* endpoints[ep_num][DIR_IN/DIR_OUT] */
58static struct ep_type endpoints[USB_NUM_ENDPOINTS][2];
59/* setup packet for EP0 */
60
61/* USB control requests may be up to 64 bytes in size.
62 Even though we never use anything more than the 8 header bytes,
63 we are required to accept request packets of up to 64 bytes size.
64 Provide buffer space for these additional payload bytes so that
65 e.g. write descriptor requests (which are rejected by us, but the
66 payload is transferred anyway) do not cause memory corruption.
67 Fixes FS#12310. -- Michael Sparmann (theseven) */
68static union {
69 struct usb_ctrlrequest header; /* 8 bytes */
70 unsigned char payload[64];
71} _ep0_setup_pkt USB_DEVBSS_ATTR;
72
73static struct usb_ctrlrequest *ep0_setup_pkt = AS3525_UNCACHED_ADDR(&_ep0_setup_pkt.header);
74
75/* state of EP0 */
76static enum ep0state ep0_state;
77
78void usb_attach(void)
79{
80 /* Nothing to do */
81}
82
83static void prepare_setup_ep0(void)
84{
85 DEPDMA(0, true) = (void*)AS3525_PHYSICAL_ADDR(&_ep0_setup_pkt);
86 DEPTSIZ(0, true) = (1 << DEPTSIZ0_supcnt_bitp)
87 | (1 << DEPTSIZ0_pkcnt_bitp)
88 | 8;
89 DEPCTL(0, true) |= DEPCTL_epena | DEPCTL_cnak;
90
91 ep0_state = EP0_WAIT_SETUP;
92}
93
94static size_t num_eps(bool out)
95{
96 return out ? sizeof(out_ep_list) : sizeof(in_ep_list);
97}
98
99static void reset_endpoints(void)
100{
101 for (int dir = 0; dir < 2; dir++)
102 {
103 bool out = dir == DIR_OUT;
104 for (unsigned i = 0; i < num_eps(dir == DIR_OUT); i++)
105 {
106 int ep = ((dir == DIR_IN) ? in_ep_list : out_ep_list)[i];
107 struct ep_type *endpoint = &endpoints[ep][out];
108 endpoint->active = false;
109 endpoint->busy = false;
110 endpoint->status = -1;
111 endpoint->done = false;
112 semaphore_release(&endpoint->complete);
113
114 if (i != 0)
115 DEPCTL(ep, out) = DEPCTL_setd0pid;
116 }
117 DEPCTL(0, out) = /*(DEPCTL_MPS_64 << DEPCTL_mps_bitp) | */ DEPCTL_usbactep;
118 }
119
120 /* Setup next chain for IN eps */
121 for (unsigned i = 0; i < num_eps(false); i++)
122 {
123 int ep = in_ep_list[i];
124 int next_ep = in_ep_list[(i + 1) % num_eps(false)];
125 DEPCTL(ep, false) |= next_ep << DEPCTL_nextep_bitp;
126 }
127
128 prepare_setup_ep0();
129}
130
131static void cancel_all_transfers(bool cancel_ep0)
132{
133 int flags = disable_irq_save();
134
135 for (int dir = 0; dir < 2; dir++)
136 for (unsigned i = !!cancel_ep0; i < num_eps(dir == DIR_OUT); i++)
137 {
138 int ep = ((dir == DIR_IN) ? in_ep_list : out_ep_list)[i];
139 struct ep_type *endpoint = &endpoints[ep][dir == DIR_OUT];
140 endpoint->status = -1;
141 endpoint->busy = false;
142 endpoint->done = false;
143 semaphore_release(&endpoint->complete);
144 DEPCTL(ep, dir) = (DEPCTL(ep, dir) & ~DEPCTL_usbactep);
145 }
146
147 restore_irq(flags);
148}
149
150void usb_drv_init(void)
151{
152 for (int i = 0; i < USB_NUM_ENDPOINTS; i++)
153 for (int dir = 0; dir < 2; dir++)
154 semaphore_init(&endpoints[i][dir].complete, 1, 0);
155
156 bitset32(&CGU_PERI, CGU_USB_CLOCK_ENABLE);
157 CCU_USB = (CCU_USB & ~(3<<24)) | (1 << 24); /* ?? */
158 /* PHY clock */
159 CGU_USB = 1<<5 /* enable */
160 | 0 << 2
161 | 0; /* source = ? (24MHz crystal?) */
162
163 PCGCCTL = 0;
164 DCTL = DCTL_pwronprgdone | DCTL_sftdiscon;
165
166 GRSTCTL = GRSTCTL_csftrst;
167 while (GRSTCTL & GRSTCTL_csftrst); /* Wait for OTG to ack reset */
168 while (!(GRSTCTL & GRSTCTL_ahbidle)); /* Wait for OTG AHB master idle */
169
170 GRXFSIZ = 512;
171 GNPTXFSIZ = MAKE_FIFOSIZE_DATA(512);
172
173 /* FIXME: the current code is for internal DMA only, the clip+ architecture
174 * defines the internal DMA model */
175 GAHBCFG = (GAHBCFG_INT_DMA_BURST_INCR << GAHBCFG_hburstlen_bitp)
176 | GAHBCFG_dma_enable | GAHBCFG_glblintrmsk;
177
178 /* Select UTMI+ 16 */
179 GUSBCFG = GUSBCFG_force_device_mode | GUSBCFG_phy_if | 7 << GUSBCFG_toutcal_bitp;
180
181 /* Do something that is probably CCU related but undocumented*/
182 CCU_USB |= 0x1000;
183 CCU_USB &= ~0x300000;
184
185 DCFG = DCFG_nzstsouthshk | DCFG_devspd_hs_phy_hs; /* Address 0, high speed */
186 DCTL = DCTL_pwronprgdone;
187
188 /* Check hardware capabilities */
189 if(extract(GHWCFG2, arch) != GHWCFG2_ARCH_INTERNAL_DMA)
190 panicf("usb-drv: wrong architecture (%ld)", extract(GHWCFG2, arch));
191 if(extract(GHWCFG2, hs_phy_type) != GHWCFG2_PHY_TYPE_UTMI)
192 panicf("usb-drv: wrong HS phy type (%ld)", extract(GHWCFG2, hs_phy_type));
193 if(extract(GHWCFG2, fs_phy_type) != GHWCFG2_PHY_TYPE_UNSUPPORTED)
194 panicf("usb-drv: wrong FS phy type (%ld)", extract(GHWCFG2, fs_phy_type));
195 if(extract(GHWCFG4, utmi_phy_data_width) != 0x2)
196 panicf("usb-drv: wrong utmi data width (%ld)", extract(GHWCFG4, utmi_phy_data_width));
197 if(!(GHWCFG4 & GHWCFG4_ded_fifo_en)) /* it seems to be multiple tx fifo support */
198 panicf("usb-drv: no multiple tx fifo");
199
200 if(USB_NUM_ENDPOINTS != extract(GHWCFG2, num_ep))
201 panicf("usb-drv: wrong endpoint number");
202
203 for (int dir = 0; dir < 2; dir++)
204 for (unsigned i = 0; i < num_eps(dir == DIR_OUT); i++)
205 {
206 int ep = ((dir == DIR_IN) ? in_ep_list : out_ep_list)[i];
207 int type = (GHWCFG1 >> GHWCFG1_epdir_bitp(ep)) & GHWCFG1_epdir_bits;
208 int flag = (dir == DIR_IN) ? GHWCFG1_EPDIR_IN : GHWCFG1_EPDIR_OUT;
209 if(type != GHWCFG1_EPDIR_BIDIR && type != flag)
210 panicf("usb-drv: EP%d not in correct direction", ep);
211 }
212
213 DOEPMSK = DEPINT_xfercompl | DEPINT_ahberr | DOEPINT_setup;
214 DIEPMSK = DEPINT_xfercompl | DEPINT_ahberr | DIEPINT_timeout;
215 DAINTMSK = 0xffffffff;
216
217 reset_endpoints();
218
219 GINTMSK = GINTMSK_usbreset
220 | GINTMSK_enumdone
221 | GINTMSK_inepintr
222 | GINTMSK_outepintr
223 | GINTMSK_disconnect;
224
225 VIC_INT_ENABLE = INTERRUPT_USB;
226}
227
228void usb_drv_exit(void)
229{
230 DCTL = DCTL_pwronprgdone | DCTL_sftdiscon;
231
232 VIC_INT_EN_CLEAR = INTERRUPT_USB;
233
234 sleep(HZ/20);
235
236 CGU_USB = 0;
237 bitclr32(&CGU_PERI, CGU_USB_CLOCK_ENABLE);
238}
239
240static void handle_ep_int(int ep, bool out)
241{
242 unsigned long sts = DEPINT(ep, out);
243 logf("%s(%d %s): sts = 0x%lx", __func__, ep, out?"OUT":"IN", sts);
244
245 if(sts & DEPINT_ahberr)
246 panicf("usb-drv: ahb error on EP%d %s", ep, out ? "OUT" : "IN");
247
248 if(sts & DEPINT_xfercompl)
249 {
250 struct ep_type *endpoint = &endpoints[ep][out ? DIR_OUT : DIR_IN];
251 if(endpoint->busy)
252 {
253 endpoint->busy = false;
254 endpoint->status = 0;
255 /* works even for EP0 */
256 int size = (DEPTSIZ(ep, out) & DEPTSIZ_xfersize_bits);
257 int transfered = endpoint->size - size;
258 if(ep == 0)
259 {
260 bool is_ack = endpoint->size == 0;
261 switch(ep0_state)
262 {
263 case EP0_WAIT_SETUP:
264 panicf("usb-drv: EP0 completion while waiting for SETUP");
265 case EP0_WAIT_DATA_ACK:
266 ep0_state = is_ack ? EP0_WAIT_DATA : EP0_WAIT_ACK;
267 break;
268 case EP0_WAIT_ACK:
269 case EP0_WAIT_DATA:
270 if((!is_ack && ep0_state == EP0_WAIT_ACK) || (is_ack && ep0_state == EP0_WAIT_DATA))
271 panicf("usb-drv: bad EP0 state");
272
273 prepare_setup_ep0();
274 break;
275 }
276 }
277 if (!out)
278 endpoint->size = size;
279 usb_core_transfer_complete(ep, out ? USB_DIR_OUT : USB_DIR_IN, 0, transfered);
280 endpoint->done = true;
281 semaphore_release(&endpoint->complete);
282 }
283 }
284
285 if(!out && (sts & DIEPINT_timeout))
286 panicf("usb-drv: timeout on EP%d IN", ep);
287
288 if(out && (sts & DOEPINT_setup))
289 {
290 if(ep != 0)
291 panicf("usb-drv: setup not on EP0, this is impossible");
292 if((DEPTSIZ(ep, true) & DEPTSIZ_xfersize_bits) != 0)
293 {
294 logf("usb-drv: ignore spurious setup (xfersize=%ld)", DOEPTSIZ(ep) & DEPTSIZ_xfersize_bits);
295 prepare_setup_ep0();
296 }
297 else
298 {
299 if(ep0_state == EP0_WAIT_SETUP)
300 {
301 bool data_phase = ep0_setup_pkt->wLength != 0;
302 ep0_state = data_phase ? EP0_WAIT_DATA_ACK : EP0_WAIT_ACK;
303 }
304
305 logf(" rt=%x r=%x", ep0_setup_pkt->bRequestType, ep0_setup_pkt->bRequest);
306
307 if(ep0_setup_pkt->bRequestType == USB_TYPE_STANDARD &&
308 ep0_setup_pkt->bRequest == USB_REQ_SET_ADDRESS)
309 DCFG = (DCFG & ~bitm(DCFG, devadr)) | (ep0_setup_pkt->wValue << DCFG_devadr_bitp);
310
311 usb_core_control_request(ep0_setup_pkt);
312 }
313 }
314
315 DEPINT(ep, out) = sts;
316}
317
318void INT_USB(void)
319{
320 /* some bits in GINTSTS can be set even though we didn't enable the interrupt source
321 * so AND it with the actual mask */
322 unsigned long sts = GINTSTS & GINTMSK;
323 logf("usb-drv: INT 0x%lx", sts);
324
325 if(sts & GINTMSK_usbreset)
326 {
327 DCFG &= ~bitm(DCFG, devadr); /* Address 0 */
328 reset_endpoints();
329 usb_core_bus_reset();
330 }
331
332 if(sts & GINTMSK_enumdone) /* enumeration done, we now know the speed */
333 {
334 /* Set up the maximum packet sizes accordingly */
335 uint32_t maxpacket = (usb_drv_port_speed() ? 512 : 64) << DEPCTL_mps_bitp;
336 for (int dir = 0; dir < 2; dir++)
337 {
338 bool out = dir == DIR_OUT;
339 for (unsigned i = 1; i < num_eps(out); i++)
340 {
341 int ep = (out ? out_ep_list : in_ep_list)[i];
342 DEPCTL(ep, out) &= ~(DEPCTL_mps_bits << DEPCTL_mps_bitp);
343 DEPCTL(ep, out) |= maxpacket;
344 }
345 }
346 }
347
348 if(sts & (GINTMSK_outepintr | GINTMSK_inepintr))
349 {
350 unsigned long daint = DAINT;
351
352 for (int i = 0; i < USB_NUM_ENDPOINTS; i++)
353 {
354 if (daint & DAINT_IN_EP(i))
355 handle_ep_int(i, false);
356 if (daint & DAINT_OUT_EP(i))
357 handle_ep_int(i, true);
358 }
359
360 DAINT = daint;
361 }
362
363 if(sts & GINTMSK_disconnect)
364 cancel_all_transfers(true);
365
366 GINTSTS = sts;
367}
368
369int usb_drv_request_endpoint(int type, int dir)
370{
371 bool out = dir == USB_DIR_OUT;
372 for (unsigned i = 1; i < num_eps(out); i++)
373 {
374 int ep = (out ? out_ep_list : in_ep_list)[i];
375 bool *active = &endpoints[ep][out ? DIR_OUT : DIR_IN].active;
376 if(*active)
377 continue;
378 *active = true;
379 DEPCTL(ep, out) = (DEPCTL(ep, out) & ~(DEPCTL_eptype_bits << DEPCTL_eptype_bitp))
380 | DEPCTL_setd0pid | (type << DEPCTL_eptype_bitp) | DEPCTL_usbactep;
381 return ep | dir;
382 }
383
384 return -1;
385}
386
387void usb_drv_release_endpoint(int ep)
388{
389 endpoints[EP_NUM(ep)][EP_DIR(ep)].active = false;
390}
391
392void usb_drv_cancel_all_transfers()
393{
394 cancel_all_transfers(false);
395}
396
397static void ep_transfer(int ep, void *ptr, int len, bool out)
398{
399 /* disable interrupts to avoid any race */
400 int oldlevel = disable_irq_save();
401
402 struct ep_type *endpoint = &endpoints[ep][out ? DIR_OUT : DIR_IN];
403 endpoint->busy = true;
404 endpoint->size = len;
405 endpoint->status = -1;
406
407 if (out)
408 DEPCTL(ep, out) &= ~DEPCTL_stall;
409 DEPCTL(ep, out) |= DEPCTL_usbactep;
410
411 int mps = usb_drv_port_speed() ? 512 : 64;
412 int nb_packets = (len + mps - 1) / mps;
413 if (nb_packets == 0)
414 nb_packets = 1;
415
416 DEPDMA(ep, out) = len
417 ? (void*)AS3525_PHYSICAL_ADDR(ptr)
418 : (void*)0x10000000;
419 DEPTSIZ(ep, out) = (nb_packets << DEPTSIZ_pkcnt_bitp) | len;
420 if(out)
421 discard_dcache_range(ptr, len);
422 else
423 commit_dcache_range(ptr, len);
424
425 logf("pkt=%d dma=%lx", nb_packets, DEPDMA(ep, out));
426
427 DEPCTL(ep, out) |= DEPCTL_epena | DEPCTL_cnak;
428
429 restore_irq(oldlevel);
430}
431
432int usb_drv_send(int ep, void *ptr, int len)
433{
434 ep = EP_NUM(ep);
435 struct ep_type *endpoint = &endpoints[ep][1];
436 endpoint->done = false;
437 ep_transfer(ep, ptr, len, false);
438 while (endpoint->busy && !endpoint->done)
439 semaphore_wait(&endpoint->complete, TIMEOUT_BLOCK);
440 return endpoint->status;
441}
diff --git a/firmware/target/arm/usb-s3c6400x.c b/firmware/target/arm/usb-s3c6400x.c
index 43c9f2fd77..2b221b1963 100644
--- a/firmware/target/arm/usb-s3c6400x.c
+++ b/firmware/target/arm/usb-s3c6400x.c
@@ -36,6 +36,9 @@
36#include <inttypes.h> 36#include <inttypes.h>
37#include "power.h" 37#include "power.h"
38 38
39//#define LOGF_ENABLE
40#include "logf.h"
41
39/* store per endpoint, per direction, information */ 42/* store per endpoint, per direction, information */
40struct ep_type 43struct ep_type
41{ 44{
@@ -107,7 +110,410 @@ void usb_drv_set_test_mode(int mode)
107} 110}
108 111
109#if CONFIG_CPU == AS3525v2 /* FIXME FIXME FIXME */ 112#if CONFIG_CPU == AS3525v2 /* FIXME FIXME FIXME */
110# include "as3525/usb-drv-as3525v2.c" 113static const uint8_t in_ep_list[] = {0, 1, 3, 5};
114static const uint8_t out_ep_list[] = {0, 2, 4};
115
116/* state of EP0 (to correctly schedule setup packet enqueing) */
117enum ep0state
118{
119 /* Setup packet is enqueud, waiting for actual data */
120 EP0_WAIT_SETUP = 0,
121 /* Waiting for ack (either IN or OUT) */
122 EP0_WAIT_ACK = 1,
123 /* Ack complete, waiting for data (either IN or OUT)
124 * This state is necessary because if both ack and data complete in the
125 * same interrupt, we might process data completion before ack completion
126 * so we need this bizarre state */
127 EP0_WAIT_DATA = 2,
128 /* Setup packet complete, waiting for ack and data */
129 EP0_WAIT_DATA_ACK = 3,
130};
131
132/* endpoints[ep_num][DIR_IN/DIR_OUT] */
133static struct ep_type endpoints[USB_NUM_ENDPOINTS][2];
134/* setup packet for EP0 */
135
136/* USB control requests may be up to 64 bytes in size.
137 Even though we never use anything more than the 8 header bytes,
138 we are required to accept request packets of up to 64 bytes size.
139 Provide buffer space for these additional payload bytes so that
140 e.g. write descriptor requests (which are rejected by us, but the
141 payload is transferred anyway) do not cause memory corruption.
142 Fixes FS#12310. -- Michael Sparmann (theseven) */
143static union {
144 struct usb_ctrlrequest header; /* 8 bytes */
145 unsigned char payload[64];
146} _ep0_setup_pkt USB_DEVBSS_ATTR;
147
148static struct usb_ctrlrequest *ep0_setup_pkt = AS3525_UNCACHED_ADDR(&_ep0_setup_pkt.header);
149
150/* state of EP0 */
151static enum ep0state ep0_state;
152
153void usb_attach(void)
154{
155 /* Nothing to do */
156}
157
158static void prepare_setup_ep0(void)
159{
160 DEPDMA(0, true) = (void*)AS3525_PHYSICAL_ADDR(&_ep0_setup_pkt);
161 DEPTSIZ(0, true) = (1 << DEPTSIZ0_supcnt_bitp)
162 | (1 << DEPTSIZ0_pkcnt_bitp)
163 | 8;
164 DEPCTL(0, true) |= DEPCTL_epena | DEPCTL_cnak;
165
166 ep0_state = EP0_WAIT_SETUP;
167}
168
169static size_t num_eps(bool out)
170{
171 return out ? sizeof(out_ep_list) : sizeof(in_ep_list);
172}
173
174static void reset_endpoints(void)
175{
176 for (int dir = 0; dir < 2; dir++)
177 {
178 bool out = dir == DIR_OUT;
179 for (unsigned i = 0; i < num_eps(dir == DIR_OUT); i++)
180 {
181 int ep = ((dir == DIR_IN) ? in_ep_list : out_ep_list)[i];
182 struct ep_type *endpoint = &endpoints[ep][out];
183 endpoint->active = false;
184 endpoint->busy = false;
185 endpoint->status = -1;
186 endpoint->done = false;
187 semaphore_release(&endpoint->complete);
188
189 if (i != 0)
190 DEPCTL(ep, out) = DEPCTL_setd0pid;
191 }
192 DEPCTL(0, out) = /*(DEPCTL_MPS_64 << DEPCTL_mps_bitp) | */ DEPCTL_usbactep;
193 }
194
195 /* Setup next chain for IN eps */
196 for (unsigned i = 0; i < num_eps(false); i++)
197 {
198 int ep = in_ep_list[i];
199 int next_ep = in_ep_list[(i + 1) % num_eps(false)];
200 DEPCTL(ep, false) |= next_ep << DEPCTL_nextep_bitp;
201 }
202
203 prepare_setup_ep0();
204}
205
206static void cancel_all_transfers(bool cancel_ep0)
207{
208 int flags = disable_irq_save();
209
210 for (int dir = 0; dir < 2; dir++)
211 for (unsigned i = !!cancel_ep0; i < num_eps(dir == DIR_OUT); i++)
212 {
213 int ep = ((dir == DIR_IN) ? in_ep_list : out_ep_list)[i];
214 struct ep_type *endpoint = &endpoints[ep][dir == DIR_OUT];
215 endpoint->status = -1;
216 endpoint->busy = false;
217 endpoint->done = false;
218 semaphore_release(&endpoint->complete);
219 DEPCTL(ep, dir) = (DEPCTL(ep, dir) & ~DEPCTL_usbactep);
220 }
221
222 restore_irq(flags);
223}
224
225void usb_drv_init(void)
226{
227 for (int i = 0; i < USB_NUM_ENDPOINTS; i++)
228 for (int dir = 0; dir < 2; dir++)
229 semaphore_init(&endpoints[i][dir].complete, 1, 0);
230
231 bitset32(&CGU_PERI, CGU_USB_CLOCK_ENABLE);
232 CCU_USB = (CCU_USB & ~(3<<24)) | (1 << 24); /* ?? */
233 /* PHY clock */
234 CGU_USB = 1<<5 /* enable */
235 | 0 << 2
236 | 0; /* source = ? (24MHz crystal?) */
237
238 PCGCCTL = 0;
239 DCTL = DCTL_pwronprgdone | DCTL_sftdiscon;
240
241 GRSTCTL = GRSTCTL_csftrst;
242 while (GRSTCTL & GRSTCTL_csftrst); /* Wait for OTG to ack reset */
243 while (!(GRSTCTL & GRSTCTL_ahbidle)); /* Wait for OTG AHB master idle */
244
245 GRXFSIZ = 512;
246 GNPTXFSIZ = MAKE_FIFOSIZE_DATA(512);
247
248 /* FIXME: the current code is for internal DMA only, the clip+ architecture
249 * defines the internal DMA model */
250 GAHBCFG = (GAHBCFG_INT_DMA_BURST_INCR << GAHBCFG_hburstlen_bitp)
251 | GAHBCFG_dma_enable | GAHBCFG_glblintrmsk;
252
253 /* Select UTMI+ 16 */
254 GUSBCFG = GUSBCFG_force_device_mode | GUSBCFG_phy_if | 7 << GUSBCFG_toutcal_bitp;
255
256 /* Do something that is probably CCU related but undocumented*/
257 CCU_USB |= 0x1000;
258 CCU_USB &= ~0x300000;
259
260 DCFG = DCFG_nzstsouthshk | DCFG_devspd_hs_phy_hs; /* Address 0, high speed */
261 DCTL = DCTL_pwronprgdone;
262
263 /* Check hardware capabilities */
264 if(extract(GHWCFG2, arch) != GHWCFG2_ARCH_INTERNAL_DMA)
265 panicf("usb-drv: wrong architecture (%ld)", extract(GHWCFG2, arch));
266 if(extract(GHWCFG2, hs_phy_type) != GHWCFG2_PHY_TYPE_UTMI)
267 panicf("usb-drv: wrong HS phy type (%ld)", extract(GHWCFG2, hs_phy_type));
268 if(extract(GHWCFG2, fs_phy_type) != GHWCFG2_PHY_TYPE_UNSUPPORTED)
269 panicf("usb-drv: wrong FS phy type (%ld)", extract(GHWCFG2, fs_phy_type));
270 if(extract(GHWCFG4, utmi_phy_data_width) != 0x2)
271 panicf("usb-drv: wrong utmi data width (%ld)", extract(GHWCFG4, utmi_phy_data_width));
272 if(!(GHWCFG4 & GHWCFG4_ded_fifo_en)) /* it seems to be multiple tx fifo support */
273 panicf("usb-drv: no multiple tx fifo");
274
275 if(USB_NUM_ENDPOINTS != extract(GHWCFG2, num_ep))
276 panicf("usb-drv: wrong endpoint number");
277
278 for (int dir = 0; dir < 2; dir++)
279 for (unsigned i = 0; i < num_eps(dir == DIR_OUT); i++)
280 {
281 int ep = ((dir == DIR_IN) ? in_ep_list : out_ep_list)[i];
282 int type = (GHWCFG1 >> GHWCFG1_epdir_bitp(ep)) & GHWCFG1_epdir_bits;
283 int flag = (dir == DIR_IN) ? GHWCFG1_EPDIR_IN : GHWCFG1_EPDIR_OUT;
284 if(type != GHWCFG1_EPDIR_BIDIR && type != flag)
285 panicf("usb-drv: EP%d not in correct direction", ep);
286 }
287
288 DOEPMSK = DEPINT_xfercompl | DEPINT_ahberr | DOEPINT_setup;
289 DIEPMSK = DEPINT_xfercompl | DEPINT_ahberr | DIEPINT_timeout;
290 DAINTMSK = 0xffffffff;
291
292 reset_endpoints();
293
294 GINTMSK = GINTMSK_usbreset
295 | GINTMSK_enumdone
296 | GINTMSK_inepintr
297 | GINTMSK_outepintr
298 | GINTMSK_disconnect;
299
300 VIC_INT_ENABLE = INTERRUPT_USB;
301}
302
303void usb_drv_exit(void)
304{
305 DCTL = DCTL_pwronprgdone | DCTL_sftdiscon;
306
307 VIC_INT_EN_CLEAR = INTERRUPT_USB;
308
309 sleep(HZ/20);
310
311 CGU_USB = 0;
312 bitclr32(&CGU_PERI, CGU_USB_CLOCK_ENABLE);
313}
314
315static void handle_ep_int(int ep, bool out)
316{
317 unsigned long sts = DEPINT(ep, out);
318 logf("%s(%d %s): sts = 0x%lx", __func__, ep, out?"OUT":"IN", sts);
319
320 if(sts & DEPINT_ahberr)
321 panicf("usb-drv: ahb error on EP%d %s", ep, out ? "OUT" : "IN");
322
323 if(sts & DEPINT_xfercompl)
324 {
325 struct ep_type *endpoint = &endpoints[ep][out ? DIR_OUT : DIR_IN];
326 if(endpoint->busy)
327 {
328 endpoint->busy = false;
329 endpoint->status = 0;
330 /* works even for EP0 */
331 int size = (DEPTSIZ(ep, out) & DEPTSIZ_xfersize_bits);
332 int transfered = endpoint->size - size;
333 if(ep == 0)
334 {
335 bool is_ack = endpoint->size == 0;
336 switch(ep0_state)
337 {
338 case EP0_WAIT_SETUP:
339 panicf("usb-drv: EP0 completion while waiting for SETUP");
340 case EP0_WAIT_DATA_ACK:
341 ep0_state = is_ack ? EP0_WAIT_DATA : EP0_WAIT_ACK;
342 break;
343 case EP0_WAIT_ACK:
344 case EP0_WAIT_DATA:
345 if((!is_ack && ep0_state == EP0_WAIT_ACK) || (is_ack && ep0_state == EP0_WAIT_DATA))
346 panicf("usb-drv: bad EP0 state");
347
348 prepare_setup_ep0();
349 break;
350 }
351 }
352 if (!out)
353 endpoint->size = size;
354 usb_core_transfer_complete(ep, out ? USB_DIR_OUT : USB_DIR_IN, 0, transfered);
355 endpoint->done = true;
356 semaphore_release(&endpoint->complete);
357 }
358 }
359
360 if(!out && (sts & DIEPINT_timeout))
361 panicf("usb-drv: timeout on EP%d IN", ep);
362
363 if(out && (sts & DOEPINT_setup))
364 {
365 if(ep != 0)
366 panicf("usb-drv: setup not on EP0, this is impossible");
367 if((DEPTSIZ(ep, true) & DEPTSIZ_xfersize_bits) != 0)
368 {
369 logf("usb-drv: ignore spurious setup (xfersize=%ld)", DOEPTSIZ(ep) & DEPTSIZ_xfersize_bits);
370 prepare_setup_ep0();
371 }
372 else
373 {
374 if(ep0_state == EP0_WAIT_SETUP)
375 {
376 bool data_phase = ep0_setup_pkt->wLength != 0;
377 ep0_state = data_phase ? EP0_WAIT_DATA_ACK : EP0_WAIT_ACK;
378 }
379
380 logf(" rt=%x r=%x", ep0_setup_pkt->bRequestType, ep0_setup_pkt->bRequest);
381
382 if(ep0_setup_pkt->bRequestType == USB_TYPE_STANDARD &&
383 ep0_setup_pkt->bRequest == USB_REQ_SET_ADDRESS)
384 DCFG = (DCFG & ~bitm(DCFG, devadr)) | (ep0_setup_pkt->wValue << DCFG_devadr_bitp);
385
386 usb_core_control_request(ep0_setup_pkt);
387 }
388 }
389
390 DEPINT(ep, out) = sts;
391}
392
393void INT_USB(void)
394{
395 /* some bits in GINTSTS can be set even though we didn't enable the interrupt source
396 * so AND it with the actual mask */
397 unsigned long sts = GINTSTS & GINTMSK;
398 logf("usb-drv: INT 0x%lx", sts);
399
400 if(sts & GINTMSK_usbreset)
401 {
402 DCFG &= ~bitm(DCFG, devadr); /* Address 0 */
403 reset_endpoints();
404 usb_core_bus_reset();
405 }
406
407 if(sts & GINTMSK_enumdone) /* enumeration done, we now know the speed */
408 {
409 /* Set up the maximum packet sizes accordingly */
410 uint32_t maxpacket = (usb_drv_port_speed() ? 512 : 64) << DEPCTL_mps_bitp;
411 for (int dir = 0; dir < 2; dir++)
412 {
413 bool out = dir == DIR_OUT;
414 for (unsigned i = 1; i < num_eps(out); i++)
415 {
416 int ep = (out ? out_ep_list : in_ep_list)[i];
417 DEPCTL(ep, out) &= ~(DEPCTL_mps_bits << DEPCTL_mps_bitp);
418 DEPCTL(ep, out) |= maxpacket;
419 }
420 }
421 }
422
423 if(sts & (GINTMSK_outepintr | GINTMSK_inepintr))
424 {
425 unsigned long daint = DAINT;
426
427 for (int i = 0; i < USB_NUM_ENDPOINTS; i++)
428 {
429 if (daint & DAINT_IN_EP(i))
430 handle_ep_int(i, false);
431 if (daint & DAINT_OUT_EP(i))
432 handle_ep_int(i, true);
433 }
434
435 DAINT = daint;
436 }
437
438 if(sts & GINTMSK_disconnect)
439 cancel_all_transfers(true);
440
441 GINTSTS = sts;
442}
443
444int usb_drv_request_endpoint(int type, int dir)
445{
446 bool out = dir == USB_DIR_OUT;
447 for (unsigned i = 1; i < num_eps(out); i++)
448 {
449 int ep = (out ? out_ep_list : in_ep_list)[i];
450 bool *active = &endpoints[ep][out ? DIR_OUT : DIR_IN].active;
451 if(*active)
452 continue;
453 *active = true;
454 DEPCTL(ep, out) = (DEPCTL(ep, out) & ~(DEPCTL_eptype_bits << DEPCTL_eptype_bitp))
455 | DEPCTL_setd0pid | (type << DEPCTL_eptype_bitp) | DEPCTL_usbactep;
456 return ep | dir;
457 }
458
459 return -1;
460}
461
462void usb_drv_release_endpoint(int ep)
463{
464 endpoints[EP_NUM(ep)][EP_DIR(ep)].active = false;
465}
466
467void usb_drv_cancel_all_transfers()
468{
469 cancel_all_transfers(false);
470}
471
472static void ep_transfer(int ep, void *ptr, int len, bool out)
473{
474 /* disable interrupts to avoid any race */
475 int oldlevel = disable_irq_save();
476
477 struct ep_type *endpoint = &endpoints[ep][out ? DIR_OUT : DIR_IN];
478 endpoint->busy = true;
479 endpoint->size = len;
480 endpoint->status = -1;
481
482 if (out)
483 DEPCTL(ep, out) &= ~DEPCTL_stall;
484 DEPCTL(ep, out) |= DEPCTL_usbactep;
485
486 int mps = usb_drv_port_speed() ? 512 : 64;
487 int nb_packets = (len + mps - 1) / mps;
488 if (nb_packets == 0)
489 nb_packets = 1;
490
491 DEPDMA(ep, out) = len
492 ? (void*)AS3525_PHYSICAL_ADDR(ptr)
493 : (void*)0x10000000;
494 DEPTSIZ(ep, out) = (nb_packets << DEPTSIZ_pkcnt_bitp) | len;
495 if(out)
496 discard_dcache_range(ptr, len);
497 else
498 commit_dcache_range(ptr, len);
499
500 logf("pkt=%d dma=%lx", nb_packets, DEPDMA(ep, out));
501
502 DEPCTL(ep, out) |= DEPCTL_epena | DEPCTL_cnak;
503
504 restore_irq(oldlevel);
505}
506
507int usb_drv_send(int ep, void *ptr, int len)
508{
509 ep = EP_NUM(ep);
510 struct ep_type *endpoint = &endpoints[ep][1];
511 endpoint->done = false;
512 ep_transfer(ep, ptr, len, false);
513 while (endpoint->busy && !endpoint->done)
514 semaphore_wait(&endpoint->complete, TIMEOUT_BLOCK);
515 return endpoint->status;
516}
111#else 517#else
112 518
113static struct ep_type endpoints[USB_NUM_ENDPOINTS]; 519static struct ep_type endpoints[USB_NUM_ENDPOINTS];