summaryrefslogtreecommitdiff
path: root/firmware/target/arm/as3525/usb-drv-as3525v2.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/as3525/usb-drv-as3525v2.c')
-rw-r--r--firmware/target/arm/as3525/usb-drv-as3525v2.c441
1 files changed, 0 insertions, 441 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}