summaryrefslogtreecommitdiff
path: root/firmware/target/arm
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm')
-rw-r--r--firmware/target/arm/rk27xx/usb-drv-rk27xx.c733
-rw-r--r--firmware/target/arm/rk27xx/usb-rk27xx.c59
2 files changed, 792 insertions, 0 deletions
diff --git a/firmware/target/arm/rk27xx/usb-drv-rk27xx.c b/firmware/target/arm/rk27xx/usb-drv-rk27xx.c
new file mode 100644
index 0000000000..a8b1bea1fe
--- /dev/null
+++ b/firmware/target/arm/rk27xx/usb-drv-rk27xx.c
@@ -0,0 +1,733 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 by Marcin Bukat
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 "config.h"
23#include "usb.h"
24#include "usb-target.h"
25#include "usb_drv.h"
26
27#include "cpu.h"
28#include "system.h"
29#include "kernel.h"
30#include "panic.h"
31
32//#include "usb-s3c6400x.h"
33
34#include "usb_ch9.h"
35#include "usb_core.h"
36#include <inttypes.h>
37#include "power.h"
38
39#include "logf.h"
40
41typedef volatile uint32_t reg32;
42
43/* Bulk OUT: ep1, ep4, ep7, ep10, ep13 */
44#define BOUT_RXSTAT(ep_num) (*(reg32*)(AHB0_UDC+0x54+0x38*(ep_num/3)))
45#define BOUT_RXCON(ep_num) (*(reg32*)(AHB0_UDC+0x58+0x38*(ep_num/3)))
46#define BOUT_DMAOUTCTL(ep_num) (*(reg32*)(AHB0_UDC+0x5C+0x38*(ep_num/3)))
47#define BOUT_DMAOUTLMADDR(ep_num) (*(reg32*)(AHB0_UDC+0x60+0x38*(ep_num/3)))
48
49/* Bulk IN: ep2, ep5, ep8, ep11, ep4 */
50#define BIN_TXSTAT(ep_num) (*(reg32*)(AHB0_UDC+0x64+0x38*(ep_num/3)))
51#define BIN_TXCON(ep_num) (*(reg32*)(AHB0_UDC+0x68+0x38*(ep_num/3)))
52#define BIN_TXBUF(ep_num) (*(reg32*)(AHB0_UDC+0x6C+0x38*(ep_num/3)))
53#define BIN_DMAINCTL(ep_num) (*(reg32*)(AHB0_UDC+0x70+0x38*(ep_num/3)))
54#define BIN_DMAINLMADDR(ep_num) (*(reg32*)(AHB0_UDC+0x74+0x38*(ep_num/3)))
55
56/* INTERRUPT IN: ep3, ep6, ep9, ep12, ep15 */
57#define IIN_TXSTAT(ep_num) (*(reg32*)(AHB0_UDC+0x78+0x38*((ep_num/3)-1)))
58#define IIN_TXCON(ep_num) (*(reg32*)(AHB0_UDC+0x7C+0x38*((ep_num/3)-1)))
59#define IIN_TXBUF(ep_num) (*(reg32*)(AHB0_UDC+0x80+0x38*((ep_num/3)-1)))
60#define IIN_DMAINCTL(ep_num) (*(reg32*)(AHB0_UDC+0x84+0x38*((ep_num/3)-1)))
61#define IIN_DMAINLMADDR(ep_num) (*(reg32*)(AHB0_UDC+0x88+0x38*((ep_num/3)-1)))
62
63#ifdef LOGF_ENABLE
64#define XFER_DIR_STR(dir) ((dir) ? "IN" : "OUT")
65#endif
66
67struct endpoint_t {
68 const int type; /* EP type */
69 const int dir; /* DIR_IN/DIR_OUT */
70 bool allocated; /* flag to mark EPs taken */
71 volatile void *buf; /* tx/rx buffer address */
72 volatile int len; /* size of the transfer (bytes) */
73 volatile int cnt; /* number of bytes transfered/received */
74 volatile bool block; /* flag indicating that transfer is blocking */
75 struct semaphore complete; /* semaphore for blocking transfers */
76};
77
78static struct endpoint_t ctrlep[2] = {
79 {USB_ENDPOINT_XFER_CONTROL, DIR_OUT, true, NULL, 0, 0, true},
80 {USB_ENDPOINT_XFER_CONTROL, DIR_IN, true, NULL, 0, 0, true}
81};
82
83static struct endpoint_t endpoints[16] = {
84 {USB_ENDPOINT_XFER_CONTROL, 3, true, NULL, 0, 0, true}, /* stub */
85 {USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false}, /* BOUT1 */
86 {USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false}, /* BIN2 */
87 {USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false}, /* IIN3 */
88 {USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false}, /* BOUT4 */
89 {USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false}, /* BIN5 */
90 {USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false}, /* IIN6 */
91 {USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false}, /* BOUT7 */
92 {USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false}, /* BIN8 */
93 {USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false}, /* IIN9 */
94 {USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false}, /* BOUT10 */
95 {USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false}, /* BIN11 */
96 {USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false}, /* IIN12 */
97 {USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false}, /* BOUT13 */
98 {USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false}, /* BIN14 */
99 {USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false}, /* IIN15 */
100};
101
102static void setup_received(void)
103{
104 static uint32_t setup_data[2];
105
106 /* copy setup data from packet */
107 setup_data[0] = SETUP1;
108 setup_data[1] = SETUP2;
109
110 /* clear all pending control transfers
111 * do we need this here?
112 */
113
114 /* pass setup data to the upper layer */
115 usb_core_control_request((struct usb_ctrlrequest*)setup_data);
116}
117
118/* service ep0 IN transaction */
119static void ctr_write(void)
120{
121 int xfer_size = (ctrlep[DIR_IN].cnt > 64) ? 64 : ctrlep[DIR_IN].cnt;
122 unsigned int timeout = current_tick + HZ/10;
123
124 while (TX0BUF & (1<<0)) /* TX0FULL flag */
125 {
126 if(TIME_AFTER(current_tick, timeout))
127 break;
128 }
129
130 TX0STAT = xfer_size; /* size of the transfer */
131 TX0DMALM_IADDR = (uint32_t)ctrlep[DIR_IN].buf; /* local buffer address */
132 TX0DMAINCTL = (1<<1); /* start DMA */
133 TX0CON &= ~(1<<2); /* clear NAK */
134
135 /* Decrement by max packet size is intentional.
136 * This way if we have final packet short one we will get negative len
137 * after transfer, which in turn indicates we *don't* need to send
138 * zero length packet. If the final packet is max sized packet we will
139 * get zero len after transfer which indicates we need to send
140 * zero length packet to signal host end of the transfer.
141 */
142 ctrlep[DIR_IN].cnt -= 64;
143 ctrlep[DIR_IN].buf += xfer_size;
144}
145
146static void ctr_read(void)
147{
148 int xfer_size = RX0STAT & 0xffff;
149
150 /* clear NAK bit */
151 RX0CON &= ~(1<<3);
152
153 ctrlep[DIR_OUT].cnt -= xfer_size;
154 ctrlep[DIR_OUT].buf += xfer_size;
155
156 RX0DMAOUTLMADDR = (uint32_t)ctrlep[DIR_OUT].buf;
157 RX0DMACTLO = (1<<0);
158}
159
160static void blk_write(int ep)
161{
162 int ep_num = EP_NUM(ep);
163 int max = usb_drv_port_speed() ? 512 : 64;
164 int xfer_size = (endpoints[ep_num].cnt > max) ? max : endpoints[ep_num].cnt;
165 unsigned int timeout = current_tick + HZ/10;
166
167 while (BIN_TXBUF(ep_num) & (1<<0)) /* TXFULL flag */
168 {
169 if(TIME_AFTER(current_tick, timeout))
170 break;
171 }
172
173 BIN_TXSTAT(ep_num) = xfer_size; /* size of the transfer */
174 BIN_DMAINLMADDR(ep_num) = (uint32_t)endpoints[ep_num].buf; /* buf address */
175 BIN_DMAINCTL(ep_num) = (1<<0); /* start DMA */
176 BIN_TXCON(ep_num) &= ~(1<<2); /* clear NAK */
177
178 /* Decrement by max packet size is intentional.
179 * This way if we have final packet short one we will get negative len
180 * after transfer, which in turn indicates we *don't* need to send
181 * zero length packet. If the final packet is max sized packet we will
182 * get zero len after transfer which indicates we need to send
183 * zero length packet to signal host end of the transfer.
184 */
185 endpoints[ep_num].cnt -= max;
186 endpoints[ep_num].buf += xfer_size;
187}
188
189static void blk_read(int ep)
190{
191 int ep_num = EP_NUM(ep);
192 int xfer_size = BOUT_RXSTAT(ep_num) & 0xffff;
193
194 /* clear NAK bit */
195 BOUT_RXCON(ep_num) &= ~(1<<3);
196
197 endpoints[ep_num].cnt -= xfer_size;
198 endpoints[ep_num].buf += xfer_size;
199
200 BOUT_DMAOUTLMADDR(ep_num) = (uint32_t)endpoints[ep_num].buf;
201 BOUT_DMAOUTCTL(ep_num) = (1<<1);
202}
203
204static void int_write(int ep)
205{
206 int ep_num = EP_NUM(ep);
207 int max = usb_drv_port_speed() ? 1024 : 64;
208 int xfer_size = (endpoints[ep_num].cnt > max) ? max : endpoints[ep_num].cnt;
209 unsigned int timeout = current_tick + HZ/10;
210
211 while (IIN_TXBUF(ep_num) & (1<<0)) /* TXFULL flag */
212 {
213 if(TIME_AFTER(current_tick, timeout))
214 break;
215 }
216
217 IIN_TXSTAT(ep_num) = xfer_size; /* size of the transfer */
218 IIN_DMAINLMADDR(ep_num) = (uint32_t)endpoints[ep_num].buf; /* buf address */
219 IIN_DMAINCTL(ep_num) = (1<<0); /* start DMA */
220 IIN_TXCON(ep_num) &= ~(1<<2); /* clear NAK */
221
222 /* Decrement by max packet size is intentional.
223 * This way if we have final packet short one we will get negative len
224 * after transfer, which in turn indicates we *don't* need to send
225 * zero length packet. If the final packet is max sized packet we will
226 * get zero len after transfer which indicates we need to send
227 * zero length packet to signal host end of the transfer.
228 */
229 endpoints[ep_num].cnt -= max;
230 endpoints[ep_num].buf += xfer_size;
231}
232
233/* UDC ISR function */
234void INT_UDC(void)
235{
236 uint32_t txstat, rxstat;
237 int tmp, ep_num;
238
239 /* read what caused UDC irq */
240 uint32_t intsrc = INT2FLAG & 0x7fffff;
241
242 if (intsrc & (1<<1)) /* setup interrupt */
243 {
244 setup_received();
245 }
246 else if (intsrc & (1<<2)) /* ep0 in interrupt */
247 {
248 txstat = TX0STAT; /* read clears flags */
249
250 /* TODO handle errors */
251 if (txstat & (1<<18)) /* check TxACK flag */
252 {
253 if (ctrlep[DIR_IN].cnt >= 0)
254 {
255 /* we still have data to send (or ZLP) */
256 ctr_write();
257 }
258 else
259 {
260 /* final ack received */
261 usb_core_transfer_complete(0, /* ep */
262 USB_DIR_IN, /* dir */
263 0, /* status */
264 ctrlep[DIR_IN].len); /* length */
265
266 /* release semaphore for blocking transfer */
267 if (ctrlep[DIR_IN].block)
268 semaphore_release(&ctrlep[DIR_IN].complete);
269 }
270 }
271 }
272 else if (intsrc & (1<<3)) /* ep0 out interrupt */
273 {
274 rxstat = RX0STAT;
275
276 /* TODO handle errors */
277 if (rxstat & (1<<18)) /* RxACK */
278 {
279 if (ctrlep[DIR_OUT].cnt > 0)
280 ctr_read();
281 else
282 usb_core_transfer_complete(0, /* ep */
283 USB_DIR_OUT, /* dir */
284 0, /* status */
285 ctrlep[DIR_OUT].len); /* length */
286 }
287 }
288 else if (intsrc & (1<<4)) /* usb reset */
289 {
290 usb_drv_init();
291 }
292 else if (intsrc & (1<<5)) /* usb resume */
293 {
294 TX0CON |= (1<<0); /* TxClr */
295 TX0CON &= ~(1<<0);
296 RX0CON |= (1<<1); /* RxClr */
297 RX0CON &= (1<<1);
298 }
299 else if (intsrc & (1<<6)) /* usb suspend */
300 {
301 }
302 else if (intsrc & (1<<7)) /* usb connect */
303 {
304 }
305 else
306 {
307 /* lets figure out which ep generated irq */
308 tmp = intsrc >> 7;
309 for (ep_num=1; ep_num < 15; ep_num++)
310 {
311 tmp >>= ep_num;
312 if (tmp & 0x01)
313 break;
314 }
315
316 if (intsrc & ((1<<8)|(1<<11)|(1<<14)|(1<<17)|(1<<20)))
317 {
318 /* bulk out */
319 rxstat = BOUT_RXSTAT(ep_num);
320
321 /* TODO handle errors */
322 if (rxstat & (1<<18)) /* RxACK */
323 {
324 if (endpoints[ep_num].cnt > 0)
325 blk_read(ep_num);
326 else
327 usb_core_transfer_complete(ep_num, /* ep */
328 USB_DIR_OUT, /* dir */
329 0, /* status */
330 endpoints[ep_num].len); /* length */
331 }
332 }
333 else if (intsrc & ((1<<9)|(1<<12)|(1<<15)|(1<<18)|(1<<21)))
334 {
335 /* bulk in */
336 txstat = BIN_TXSTAT(ep_num);
337
338 /* TODO handle errors */
339 if (txstat & (1<<18)) /* check TxACK flag */
340 {
341 if (endpoints[ep_num].cnt >= 0)
342 {
343 /* we still have data to send (or ZLP) */
344 blk_write(ep_num);
345 }
346 else
347 {
348 /* final ack received */
349 usb_core_transfer_complete(ep_num, /* ep */
350 USB_DIR_IN, /* dir */
351 0, /* status */
352 endpoints[ep_num].len); /* length */
353
354 /* release semaphore for blocking transfer */
355 if (endpoints[ep_num].block)
356 semaphore_release(&endpoints[ep_num].complete);
357 }
358 }
359 }
360 else if (intsrc & ((1<<10)|(1<13)|(1<<16)|(1<<19)|(1<<22)))
361 {
362 /* int in */
363 txstat = IIN_TXSTAT(ep_num);
364
365 /* TODO handle errors */
366 if (txstat & (1<<18)) /* check TxACK flag */
367 {
368 if (endpoints[ep_num].cnt >= 0)
369 {
370 /* we still have data to send (or ZLP) */
371 int_write(ep_num);
372 }
373 else
374 {
375 /* final ack received */
376 usb_core_transfer_complete(ep_num, /* ep */
377 USB_DIR_IN, /* dir */
378 0, /* status */
379 endpoints[ep_num].len); /* length */
380
381 /* release semaphore for blocking transfer */
382 if (endpoints[ep_num].block)
383 semaphore_release(&endpoints[ep_num].complete);
384 }
385 }
386 }
387 }
388}
389
390/* return port speed FS=0, HS=1 */
391int usb_drv_port_speed(void)
392{
393 return ((DEV_INFO & (3<<21)) == 0) ? 0 : 1;
394}
395
396/* Reserve endpoint */
397int usb_drv_request_endpoint(int type, int dir)
398{
399 int ep_num, ep_dir;
400 int ep_type;
401
402 /* Safety */
403 ep_dir = EP_DIR(dir);
404 ep_type = type & USB_ENDPOINT_XFERTYPE_MASK;
405
406 logf("req: %s %s", XFER_DIR_STR(ep_dir), XFER_TYPE_STR(ep_type));
407
408 /* Find an available ep/dir pair */
409 for (ep_num=1;ep_num<USB_NUM_ENDPOINTS;ep_num++)
410 {
411 struct endpoint_t* endpoint = &endpoints[ep_num];
412
413 if (endpoint->type == ep_type &&
414 endpoint->dir == ep_dir &&
415 !endpoint->allocated)
416 {
417 /* mark endpoint as taken */
418 endpoint->allocated = true;
419
420 /* enable interrupt from this endpoint */
421 EN_INT |= (1<<(ep_num+7));
422
423 logf("add: ep%d %s", ep_num, XFER_DIR_STR(ep_dir));
424 return (ep_num | (dir & USB_ENDPOINT_DIR_MASK));
425 }
426 }
427 return -1;
428}
429
430/* Free endpoint */
431void usb_drv_release_endpoint(int ep)
432{
433 int ep_num = EP_NUM(ep);
434 int ep_dir = EP_DIR(ep);
435
436 logf("rel: ep%d %s", ep_num, XFER_DIR_STR(ep_dir));
437 endpoints[ep_num].allocated = false;
438
439 /* disable interrupt from this endpoint */
440 EN_INT &= ~(1<<(ep_num+7));
441}
442
443/* Set the address (usually it's in a register).
444 * There is a problem here: some controller want the address to be set between
445 * control out and ack and some want to wait for the end of the transaction.
446 * In the first case, you need to write some code special code when getting
447 * setup packets and ignore this function (have a look at other drives)
448 */
449void usb_drv_set_address(int address)
450{
451 (void)address;
452 /* UDC seems to set this automaticaly */
453}
454
455static int _usb_drv_send(int endpoint, void *ptr, int length, bool block)
456{
457 struct endpoint_t *ep;
458 int ep_num = EP_NUM(endpoint);
459
460 if (ep_num == 0)
461 ep = &ctrlep[DIR_IN];
462 else
463 ep = &endpoints[ep_num];
464
465 ep->buf = ptr;
466 ep->len = ep->cnt = length;
467
468 if (block)
469 ep->block = true;
470 else
471 ep->block = false;
472
473 switch (ep->type)
474 {
475 case USB_ENDPOINT_XFER_CONTROL:
476 ctr_write();
477 break;
478
479 case USB_ENDPOINT_XFER_BULK:
480 blk_write(ep_num);
481 break;
482
483 case USB_ENDPOINT_XFER_INT:
484 int_write(ep_num);
485 break;
486 }
487
488 if (block)
489 /* wait for transfer to end */
490 semaphore_wait(&ep->complete, TIMEOUT_BLOCK);
491
492 return 0;
493}
494
495/* Setup a send transfer. (blocking) */
496int usb_drv_send(int endpoint, void *ptr, int length)
497{
498 return _usb_drv_send(endpoint, ptr, length, true);
499}
500
501/* Setup a send transfer. (non blocking) */
502int usb_drv_send_nonblocking(int endpoint, void *ptr, int length)
503{
504 return _usb_drv_send(endpoint, ptr, length, false);
505}
506
507/* Setup a receive transfer. (non blocking) */
508int usb_drv_recv(int endpoint, void* ptr, int length)
509{
510 struct endpoint_t *ep;
511 int ep_num = EP_NUM(endpoint);
512
513 if (ep_num == 0)
514 {
515 ep = &ctrlep[DIR_OUT];
516
517 ctr_read();
518 }
519 else
520 {
521 ep = &endpoints[ep_num];
522
523 /* clear NAK bit */
524 BOUT_RXCON(ep_num) &= ~(1<<3);
525 BOUT_DMAOUTLMADDR(ep_num) = (uint32_t)ptr;
526 BOUT_DMAOUTCTL(ep_num) = (1<<1);
527 }
528
529 ep->buf = ptr;
530 ep->len = ep->cnt = length;
531
532 return 0;
533}
534
535/* Kill all transfers. Usually you need to set a bit for each endpoint
536 * and flush fifos. You should also call the completion handler with
537 * error status for everything
538 */
539void usb_drv_cancel_all_transfers(void)
540{
541}
542
543/* Set test mode, you can forget that for now, usually it's sufficient
544 * to bit copy the argument into some register of the controller
545 */
546void usb_drv_set_test_mode(int mode)
547{
548 (void)mode;
549}
550
551/* Check if endpoint is in stall state */
552bool usb_drv_stalled(int endpoint, bool in)
553{
554 int ep_num = EP_NUM(endpoint);
555
556 switch (endpoints[ep_num].type)
557 {
558 case USB_ENDPOINT_XFER_CONTROL:
559 if (in)
560 return (TX0CON & (1<<1)) ? true : false;
561 else
562 return (RX0CON & (1<<2)) ? true : false;
563
564 break;
565
566 case USB_ENDPOINT_XFER_BULK:
567 if (in)
568 return (BIN_TXCON(ep_num) & (1<<1)) ? true : false;
569 else
570 return (BOUT_RXCON(ep_num) & (1<<2)) ? true : false;
571
572 break;
573
574 case USB_ENDPOINT_XFER_INT:
575 if (in)
576 return (IIN_TXCON(ep_num) & (1<<1)) ? true : false;
577 else
578 return false; /* we don't have such endpoint anyway */
579
580 break;
581 }
582
583 return false;
584}
585
586/* Stall the endpoint. Usually set a flag in the controller */
587void usb_drv_stall(int endpoint, bool stall, bool in)
588{
589 int ep_num = EP_NUM(endpoint);
590
591 switch (endpoints[ep_num].type)
592 {
593 case USB_ENDPOINT_XFER_CONTROL:
594 if (in)
595 {
596 if (stall)
597 TX0CON |= (1<<1);
598 else
599 TX0CON &= ~(1<<1);
600 }
601 else
602 {
603 if (stall)
604 RX0CON |= (1<<2);
605 else
606 RX0CON &= ~(1<<2); /* doc says Auto clear by UDC 2.0 */
607 }
608 break;
609
610 case USB_ENDPOINT_XFER_BULK:
611 if (in)
612 {
613 if (stall)
614 BIN_TXCON(ep_num) |= (1<<1);
615 else
616 BIN_TXCON(ep_num) &= ~(1<<1);
617 }
618 else
619 {
620 if (stall)
621 BOUT_RXCON(ep_num) |= (1<<2);
622 else
623 BOUT_RXCON(ep_num) &= ~(1<<2);
624 }
625 break;
626
627 case USB_ENDPOINT_XFER_INT:
628 if (in)
629 {
630 if (stall)
631 IIN_TXCON(ep_num) |= (1<<1);
632 else
633 IIN_TXCON(ep_num) &= ~(1<<1);
634 }
635 break;
636 }
637}
638
639/* one time init (once per connection) - basicaly enable usb core */
640void usb_drv_init(void)
641{
642 int ep_num;
643
644 /* enable USB clock */
645 SCU_CLKCFG &= ~(1<<6);
646
647 /* 1. do soft disconnect */
648 DEV_CTL = (1<<3); /* DEV_SELF_PWR */
649
650 /* 2. do power on reset to PHY */
651 DEV_CTL = (1<<3) | /* DEV_SELF_PWR */
652 (1<<7); /* SOFT_POR */
653
654 /* 3. wait more than 10ms */
655 udelay(20000);
656
657 /* 4. clear SOFT_POR bit */
658 DEV_CTL &= ~(1<<7);
659
660 /* 5. configure minimal EN_INT */
661 EN_INT = (1<<6) | /* Enable Suspend Interrupt */
662 (1<<5) | /* Enable Resume Interrupt */
663 (1<<4) | /* Enable USB Reset Interrupt */
664 (1<<3) | /* Enable OUT Token receive Interrupt EP0 */
665 (1<<2) | /* Enable IN Token transmits Interrupt EP0 */
666 (1<<1); /* Enable SETUP Packet Receive Interrupt */
667
668 /* 6. configure INTCON */
669 INTCON = (1<<2) | /* interrupt high active */
670 (1<<0); /* enable EP0 interrupts */
671
672 /* 7. configure EP0 control registers */
673 TX0CON = (1<<6) | /* Set as one to enable the EP0 tx irq */
674 (1<<2); /* Set as one to response NAK handshake */
675
676 RX0CON = (1<<7) |
677 (1<<4) | /* Endpoint 0 Enable. When cleared the endpoint does
678 * not respond to an SETUP or OUT token
679 */
680
681 (1<<3); /* Set as one to response NAK handshake */
682
683 /* 8. write final bits to DEV_CTL */
684 DEV_CTL = (1<<8) | /* Configure CSR done */
685 (1<<6) | /* 16-bit data path enabled. udc_clk = 30MHz */
686 (1<<4) | /* Device soft connect */
687 (1<<3); /* Device self power */
688
689 /* init semaphore of ep0 */
690 semaphore_init(&ctrlep[DIR_OUT].complete, 1, 0);
691 semaphore_init(&ctrlep[DIR_IN].complete, 1, 0);
692
693 for (ep_num = 1; ep_num < USB_NUM_ENDPOINTS; ep_num++)
694 {
695 semaphore_init(&endpoints[ep_num].complete, 1, 0);
696
697 if (ep_num%3 == 0) /* IIN 3, 6, 9, 12, 15 */
698 {
699 IIN_TXCON(ep_num) |= (ep_num<<8)|(1<<3)|(1<<2); /* ep_num, enable, NAK */
700 }
701 else if (ep_num%3 == 1) /* BOUT 1, 4, 7, 10, 13 */
702 {
703 BOUT_RXCON(ep_num) |= (ep_num<<8)|(1<<4)|(1<<3); /* ep_num, NAK, enable */
704 }
705 else if (ep_num%3 == 2) /* BIN 2, 5, 8, 11, 14 */
706 {
707 BIN_TXCON(ep_num) |= (ep_num<<8)|(1<<3)|(1<<2); /* ep_num, enable, NAK */
708 }
709 }
710}
711
712/* turn off usb core */
713void usb_drv_exit(void)
714{
715 DEV_CTL = (1<<3); /* DEV_SELF_PWR */
716
717 /* disable USB interrupts in interrupt controller */
718 INTC_IMR &= ~(1<<16);
719 INTC_IECR &= ~(1<<16);
720
721 /* we cannot disable UDC clock since this causes data abort
722 * when reading DEV_INFO in order to check usb connect event
723 */
724}
725
726int usb_detect(void)
727{
728 if (DEV_INFO & (1<<20))
729 return USB_INSERTED;
730 else
731 return USB_EXTRACTED;
732}
733
diff --git a/firmware/target/arm/rk27xx/usb-rk27xx.c b/firmware/target/arm/rk27xx/usb-rk27xx.c
new file mode 100644
index 0000000000..2eb6bed480
--- /dev/null
+++ b/firmware/target/arm/rk27xx/usb-rk27xx.c
@@ -0,0 +1,59 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 by Marcin Bukat
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 "config.h"
23#include "cpu.h"
24#include "string.h"
25#include "usb.h"
26#include "usb_drv.h"
27#include "usb_core.h"
28#include "usb-target.h"
29#include "system.h"
30#include "system-target.h"
31
32int usb_status = USB_EXTRACTED;
33
34void usb_drv_usb_detect_event()
35{
36 usb_status_event(USB_INSERTED);
37}
38
39void usb_init_device(void)
40{
41}
42
43void usb_attach(void)
44{
45 usb_enable(true);
46}
47
48bool usb_plugged(void)
49{
50 return true;
51}
52
53void usb_enable(bool on)
54{
55 if(on)
56 usb_core_init();
57 else
58 usb_core_exit();
59}