summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcin Bukat <marcin.bukat@gmail.com>2013-07-24 22:46:08 +0200
committerAmaury Pouly <amaury.pouly@gmail.com>2013-08-06 21:27:46 +0200
commit310f9e068d58d3113358e86d6dd239500cdd11c4 (patch)
tree0aa97c8ff13ae28791a4b7a0329fea35f874d083
parent21672ba31cbcd6bf4b70d7dbbdcaa8db86effc0b (diff)
downloadrockbox-310f9e068d58d3113358e86d6dd239500cdd11c4.tar.gz
rockbox-310f9e068d58d3113358e86d6dd239500cdd11c4.zip
rk27xx: implement usb driver
Change-Id: Iee3036944652fd6431d3177ab619e5df1f9bd44c
-rw-r--r--firmware/export/config.h4
-rw-r--r--firmware/export/rk27xx.h5
-rw-r--r--firmware/target/arm/rk27xx/usb-drv-rk27xx.c714
-rw-r--r--firmware/target/arm/rk27xx/usb-rk27xx.c14
4 files changed, 449 insertions, 288 deletions
diff --git a/firmware/export/config.h b/firmware/export/config.h
index 7252d62c5e..c252b44f4e 100644
--- a/firmware/export/config.h
+++ b/firmware/export/config.h
@@ -834,7 +834,6 @@ Lyre prototype 1 */
834#define USB_STATUS_BY_EVENT 834#define USB_STATUS_BY_EVENT
835#define USB_DETECT_BY_REQUEST 835#define USB_DETECT_BY_REQUEST
836#elif CONFIG_USBOTG == USBOTG_RK27XX 836#elif CONFIG_USBOTG == USBOTG_RK27XX
837#define USB_STATUS_BY_EVENT
838#define USB_DETECT_BY_REQUEST 837#define USB_DETECT_BY_REQUEST
839#endif /* CONFIG_USB == */ 838#endif /* CONFIG_USB == */
840#endif /* HAVE_USBSTACK */ 839#endif /* HAVE_USBSTACK */
@@ -1069,7 +1068,8 @@ Lyre prototype 1 */
1069#elif (CONFIG_USBOTG == USBOTG_ARC) || \ 1068#elif (CONFIG_USBOTG == USBOTG_ARC) || \
1070 (CONFIG_USBOTG == USBOTG_JZ4740) || \ 1069 (CONFIG_USBOTG == USBOTG_JZ4740) || \
1071 (CONFIG_USBOTG == USBOTG_M66591) || \ 1070 (CONFIG_USBOTG == USBOTG_M66591) || \
1072 (CONFIG_USBOTG == USBOTG_AS3525) 1071 (CONFIG_USBOTG == USBOTG_AS3525) || \
1072 (CONFIG_USBOTG == USBOTG_RK27XX)
1073#define USB_HAS_BULK 1073#define USB_HAS_BULK
1074#define USB_HAS_INTERRUPT 1074#define USB_HAS_INTERRUPT
1075#elif defined(CPU_TCC780X) || defined(CPU_TCC77X) 1075#elif defined(CPU_TCC780X) || defined(CPU_TCC77X)
diff --git a/firmware/export/rk27xx.h b/firmware/export/rk27xx.h
index 58b3fe8166..dc6bca7cbd 100644
--- a/firmware/export/rk27xx.h
+++ b/firmware/export/rk27xx.h
@@ -8,7 +8,8 @@
8#define FLASH_BANK1 0x11000000 8#define FLASH_BANK1 0x11000000
9 9
10#define USB_NUM_ENDPOINTS 16 10#define USB_NUM_ENDPOINTS 16
11#define USB_DEVBSS_ATTR 11/* cache aligned */
12#define USB_DEVBSS_ATTR __attribute__((aligned(CACHEALIGN_SIZE)))
12 13
13/* Timers */ 14/* Timers */
14#define APB0_TIMER (ARM_BUS0_BASE + 0x00000000) 15#define APB0_TIMER (ARM_BUS0_BASE + 0x00000000)
@@ -811,6 +812,7 @@
811#define RXVOIDINTEN (1<<5) 812#define RXVOIDINTEN (1<<5)
812#define RXERRINTEN (1<<6) 813#define RXERRINTEN (1<<6)
813#define RXACKINTEN (1<<7) 814#define RXACKINTEN (1<<7)
815#define RXCFINTE (1<<12)
814/* bits 31:8 reserved for EP0 */ 816/* bits 31:8 reserved for EP0 */
815/* bits 31:14 reserved for others */ 817/* bits 31:14 reserved for others */
816 818
@@ -833,6 +835,7 @@
833#define TXERRINTEN (1<<5) 835#define TXERRINTEN (1<<5)
834#define TXACKINTEN (1<<6) 836#define TXACKINTEN (1<<6)
835#define TXDMADNEN (1<<7) /* reserved for EP0 */ 837#define TXDMADNEN (1<<7) /* reserved for EP0 */
838#define TXCFINTE (1<<12)
836/* bits 31:8 reserved */ 839/* bits 31:8 reserved */
837 840
838/* TXnBUF bits */ 841/* TXnBUF bits */
diff --git a/firmware/target/arm/rk27xx/usb-drv-rk27xx.c b/firmware/target/arm/rk27xx/usb-drv-rk27xx.c
index 9380f54193..af613e7024 100644
--- a/firmware/target/arm/rk27xx/usb-drv-rk27xx.c
+++ b/firmware/target/arm/rk27xx/usb-drv-rk27xx.c
@@ -5,9 +5,9 @@
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/ 7 * \/ \/ \/ \/ \/
8 * $Id$
9 * 8 *
10 * Copyright (C) 2011 by Marcin Bukat 9 * Copyright (C) 2011 by Marcin Bukat
10 * Copyright (C) 2012 by Amaury Pouly
11 * 11 *
12 * This program is free software; you can redistribute it and/or 12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License 13 * modify it under the terms of the GNU General Public License
@@ -28,13 +28,12 @@
28#include "kernel.h" 28#include "kernel.h"
29#include "panic.h" 29#include "panic.h"
30 30
31//#include "usb-s3c6400x.h"
32
33#include "usb_ch9.h" 31#include "usb_ch9.h"
34#include "usb_core.h" 32#include "usb_core.h"
35#include <inttypes.h> 33#include <inttypes.h>
36#include "power.h" 34#include "power.h"
37 35
36/*#define LOGF_ENABLE*/
38#include "logf.h" 37#include "logf.h"
39 38
40typedef volatile uint32_t reg32; 39typedef volatile uint32_t reg32;
@@ -59,6 +58,16 @@ typedef volatile uint32_t reg32;
59#define IIN_DMAINCTL(ep_num) (*(reg32*)(AHB0_UDC+0x84+0x38*((ep_num/3)-1))) 58#define IIN_DMAINCTL(ep_num) (*(reg32*)(AHB0_UDC+0x84+0x38*((ep_num/3)-1)))
60#define IIN_DMAINLMADDR(ep_num) (*(reg32*)(AHB0_UDC+0x88+0x38*((ep_num/3)-1))) 59#define IIN_DMAINLMADDR(ep_num) (*(reg32*)(AHB0_UDC+0x88+0x38*((ep_num/3)-1)))
61 60
61#define USB_FULL_SPEED 0
62#define USB_HIGH_SPEED 1
63
64/* max allowed packet size definitions */
65#define CTL_MAX_SIZE 64
66#define BLK_HS_MAX_SIZE 512
67#define BLK_FS_MAX_SIZE 64
68#define INT_HS_MAX_SIZE 1024
69#define INT_FS_MAX_SIZE 64
70
62#ifdef LOGF_ENABLE 71#ifdef LOGF_ENABLE
63#define XFER_DIR_STR(dir) ((dir) ? "IN" : "OUT") 72#define XFER_DIR_STR(dir) ((dir) ? "IN" : "OUT")
64#define XFER_TYPE_STR(type) \ 73#define XFER_TYPE_STR(type) \
@@ -71,6 +80,7 @@ typedef volatile uint32_t reg32;
71struct endpoint_t { 80struct endpoint_t {
72 const int type; /* EP type */ 81 const int type; /* EP type */
73 const int dir; /* DIR_IN/DIR_OUT */ 82 const int dir; /* DIR_IN/DIR_OUT */
83 const unsigned int intr_mask;
74 bool allocated; /* flag to mark EPs taken */ 84 bool allocated; /* flag to mark EPs taken */
75 volatile void *buf; /* tx/rx buffer address */ 85 volatile void *buf; /* tx/rx buffer address */
76 volatile int len; /* size of the transfer (bytes) */ 86 volatile int len; /* size of the transfer (bytes) */
@@ -80,30 +90,33 @@ struct endpoint_t {
80}; 90};
81 91
82static struct endpoint_t ctrlep[2] = { 92static struct endpoint_t ctrlep[2] = {
83 {USB_ENDPOINT_XFER_CONTROL, DIR_OUT, true, NULL, 0, 0, true, {0, 0, 0}}, 93 {USB_ENDPOINT_XFER_CONTROL, DIR_OUT, 0, true, NULL, 0, 0, true, {0, 0, 0}},
84 {USB_ENDPOINT_XFER_CONTROL, DIR_IN, true, NULL, 0, 0, true, {0, 0, 0}} 94 {USB_ENDPOINT_XFER_CONTROL, DIR_IN, 0, true, NULL, 0, 0, true, {0, 0, 0}}
85}; 95};
86 96
87static struct endpoint_t endpoints[16] = { 97static struct endpoint_t endpoints[16] = {
88 {USB_ENDPOINT_XFER_CONTROL, 3, true, NULL, 0, 0, true, {0, 0, 0}}, /* stub */ 98 {USB_ENDPOINT_XFER_CONTROL, 3, 0, true, NULL, 0, 0, true, {0, 0, 0}}, /* stub */
89 {USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false, {0, 0, 0}}, /* BOUT1 */ 99 {USB_ENDPOINT_XFER_BULK, DIR_OUT, BOUT1_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* BOUT1 */
90 {USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false, {0, 0, 0}}, /* BIN2 */ 100 {USB_ENDPOINT_XFER_BULK, DIR_IN, BIN2_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* BIN2 */
91 {USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false, {0, 0, 0}}, /* IIN3 */ 101 {USB_ENDPOINT_XFER_INT, DIR_IN, IIN3_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* IIN3 */
92 {USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false, {0, 0, 0}}, /* BOUT4 */ 102 {USB_ENDPOINT_XFER_BULK, DIR_OUT, BOUT4_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* BOUT4 */
93 {USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false, {0, 0, 0}}, /* BIN5 */ 103 {USB_ENDPOINT_XFER_BULK, DIR_IN, BIN5_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* BIN5 */
94 {USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false, {0, 0, 0}}, /* IIN6 */ 104 {USB_ENDPOINT_XFER_INT, DIR_IN, IIN6_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* IIN6 */
95 {USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false, {0, 0, 0}}, /* BOUT7 */ 105 {USB_ENDPOINT_XFER_BULK, DIR_OUT, BOUT7_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* BOUT7 */
96 {USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false, {0, 0, 0}}, /* BIN8 */ 106 {USB_ENDPOINT_XFER_BULK, DIR_IN, BIN8_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* BIN8 */
97 {USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false, {0, 0, 0}}, /* IIN9 */ 107 {USB_ENDPOINT_XFER_INT, DIR_IN, IIN9_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* IIN9 */
98 {USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false, {0, 0, 0}}, /* BOUT10 */ 108 {USB_ENDPOINT_XFER_BULK, DIR_OUT, BOUT10_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* BOUT10 */
99 {USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false, {0, 0, 0}}, /* BIN11 */ 109 {USB_ENDPOINT_XFER_BULK, DIR_IN, BIN11_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* BIN11 */
100 {USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false, {0, 0, 0}}, /* IIN12 */ 110 {USB_ENDPOINT_XFER_INT, DIR_IN, IIN12_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* IIN12 */
101 {USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false, {0, 0, 0}}, /* BOUT13 */ 111 {USB_ENDPOINT_XFER_BULK, DIR_OUT, BOUT13_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* BOUT13 */
102 {USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false, {0, 0, 0}}, /* BIN14 */ 112 {USB_ENDPOINT_XFER_BULK, DIR_IN, BIN14_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* BIN14 */
103 {USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false, {0, 0, 0}}, /* IIN15 */ 113 {USB_ENDPOINT_XFER_INT, DIR_IN, IIN15_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* IIN15 */
104}; 114};
105 115
106static void setup_received(void) 116static volatile bool set_address = false;
117static volatile bool set_configuration = false;
118
119static void setup_irq_handler(void)
107{ 120{
108 static uint32_t setup_data[2]; 121 static uint32_t setup_data[2];
109 122
@@ -111,10 +124,6 @@ static void setup_received(void)
111 setup_data[0] = SETUP1; 124 setup_data[0] = SETUP1;
112 setup_data[1] = SETUP2; 125 setup_data[1] = SETUP2;
113 126
114 /* clear all pending control transfers
115 * do we need this here?
116 */
117
118 /* pass setup data to the upper layer */ 127 /* pass setup data to the upper layer */
119 usb_core_control_request((struct usb_ctrlrequest*)setup_data); 128 usb_core_control_request((struct usb_ctrlrequest*)setup_data);
120} 129}
@@ -122,12 +131,12 @@ static void setup_received(void)
122/* service ep0 IN transaction */ 131/* service ep0 IN transaction */
123static void ctr_write(void) 132static void ctr_write(void)
124{ 133{
125 int xfer_size = (ctrlep[DIR_IN].cnt > 64) ? 64 : ctrlep[DIR_IN].cnt; 134 int xfer_size = MIN(ctrlep[DIR_IN].cnt, CTL_MAX_SIZE);
126 unsigned int timeout = current_tick + HZ/10; 135 unsigned int timeout = current_tick + HZ/10;
127 136
128 while (TX0BUF & TXFULL) /* TX0FULL flag */ 137 while (TX0BUF & TXFULL) /* TX0FULL flag */
129 { 138 {
130 if(TIME_AFTER(current_tick, timeout)) 139 if (TIME_AFTER(current_tick, timeout))
131 break; 140 break;
132 } 141 }
133 142
@@ -143,7 +152,7 @@ static void ctr_write(void)
143 * get zero len after transfer which indicates we need to send 152 * get zero len after transfer which indicates we need to send
144 * zero length packet to signal host end of the transfer. 153 * zero length packet to signal host end of the transfer.
145 */ 154 */
146 ctrlep[DIR_IN].cnt -= 64; 155 ctrlep[DIR_IN].cnt -= CTL_MAX_SIZE;
147 ctrlep[DIR_IN].buf += xfer_size; 156 ctrlep[DIR_IN].buf += xfer_size;
148} 157}
149 158
@@ -161,60 +170,147 @@ static void ctr_read(void)
161 RX0DMACTLO = DMA_START; /* start DMA */ 170 RX0DMACTLO = DMA_START; /* start DMA */
162} 171}
163 172
164static void blk_write(int ep) 173static void blk_write(int ep_num)
165{ 174{
166 int ep_num = EP_NUM(ep);
167 int max = usb_drv_port_speed() ? 512 : 64;
168 int xfer_size = (endpoints[ep_num].cnt > max) ? max : endpoints[ep_num].cnt;
169 unsigned int timeout = current_tick + HZ/10; 175 unsigned int timeout = current_tick + HZ/10;
170 176 int max = usb_drv_port_speed() ? BLK_HS_MAX_SIZE : BLK_FS_MAX_SIZE;
177 int xfer_size = MIN(endpoints[ep_num].cnt, max);
178
171 while (BIN_TXBUF(ep_num) & TXFULL) /* TXFULL flag */ 179 while (BIN_TXBUF(ep_num) & TXFULL) /* TXFULL flag */
172 { 180 {
173 if(TIME_AFTER(current_tick, timeout)) 181 if (TIME_AFTER(current_tick, timeout))
174 break; 182 break;
175 } 183 }
176 184
177 BIN_TXSTAT(ep_num) = xfer_size; /* size */ 185 BIN_TXSTAT(ep_num) = xfer_size; /* size */
178 BIN_DMAINLMADDR(ep_num) = (uint32_t)endpoints[ep_num].buf; /* buf address */ 186 BIN_DMAINLMADDR(ep_num) = (uint32_t)endpoints[ep_num].buf; /* buf address */
179 BIN_DMAINCTL(ep_num) = DMA_START; /* start DMA */ 187 BIN_DMAINCTL(ep_num) = DMA_START; /* start DMA */
180 BIN_TXCON(ep_num) &= ~TXNAK; /* clear NAK */ 188 BIN_TXCON(ep_num) &= ~TXNAK; /* clear NAK */
181 189
182 /* Decrement by max packet size is intentional. 190 /* Decrement by max packet size is intentional.
183 * This way if we have final packet short one we will get negative len 191 * This way if we have final packet short one we will get negative len
184 * after transfer, which in turn indicates we *don't* need to send 192 * after transfer, which in turn indicates we *don't* need to send
185 * zero length packet. If the final packet is max sized packet we will 193 * zero length packet. If the final packet is max sized packet we will
186 * get zero len after transfer which indicates we need to send 194 * get zero len after transfer which indicates we need to send
187 * zero length packet to signal host end of the transfer. 195 * zero length packet to signal host end of the transfer.
188 */ 196 */
189 endpoints[ep_num].cnt -= max; 197 endpoints[ep_num].cnt -= max;
190 endpoints[ep_num].buf += xfer_size; 198 endpoints[ep_num].buf += xfer_size;
191} 199}
192 200
193static void blk_read(int ep) 201static void blk_in_irq_handler(int ep_num)
194{ 202{
195 int ep_num = EP_NUM(ep); 203 uint32_t txstat = BIN_TXSTAT(ep_num);
196 int xfer_size = BOUT_RXSTAT(ep_num) & 0xffff; 204 struct endpoint_t *endp = &endpoints[ep_num];
197 205
198 /* clear NAK bit */ 206 if (txstat & TXERR)
199 BOUT_RXCON(ep_num) &= ~RXNAK; 207 {
200 208 panicf("error condition ep%d, %ld", ep_num, current_tick);
201 endpoints[ep_num].cnt -= xfer_size; 209 }
202 endpoints[ep_num].buf += xfer_size; 210
203 211 if (txstat & TXCFINT)
204 BOUT_DMAOUTLMADDR(ep_num) = (uint32_t)endpoints[ep_num].buf; 212 {
205 BOUT_DMAOUTCTL(ep_num) = DMA_START; 213 logf("blk_write: cf(0x%x), %ld", ep_num, current_tick);
214 /* bit cleared by read */
215 usb_drv_stall(ep_num, false, true);
216 }
217
218 if (txstat & TXACK) /* check TxACK flag */
219 {
220 if (endp->cnt > 0)
221 {
222 logf("blk_write: ack(0x%x), %ld", ep_num, current_tick);
223 /* we still have data to send (or ZLP) */
224 blk_write(ep_num);
225 }
226 else
227 {
228 logf("udc_intr: usb_core_transfer_complete(0x%x, USB_DIR_IN, 0, 0x%x), %ld",
229 ep_num, endp->len, current_tick);
230
231 /* final ack received */
232 usb_core_transfer_complete(ep_num, /* ep */
233 USB_DIR_IN, /* dir */
234 0, /* status */
235 endp->len); /* length */
236
237 /* release semaphore for blocking transfer */
238 if (endp->block)
239 {
240 logf("udc_intr: ep=0x%x, semaphore_release(), %ld",
241 ep_num, current_tick);
242
243 semaphore_release(&endp->complete);
244 }
245 }
246 }
247}
248
249static void blk_out_irq_handler(int ep_num)
250{
251 uint32_t rxstat = BOUT_RXSTAT(ep_num);
252 int xfer_size = rxstat & 0xffff;
253 int max = usb_drv_port_speed() ? BLK_HS_MAX_SIZE : BLK_FS_MAX_SIZE;
254 struct endpoint_t *endp = &endpoints[ep_num];
255
256 if (rxstat & RXERR)
257 {
258 panicf("error condition ep%d, %ld", ep_num, current_tick);
259 }
260
261 if (rxstat & RXOVF)
262 {
263 panicf("rxovf ep%d, %ld", ep_num, current_tick);
264 }
265
266 if (rxstat & RXCFINT)
267 {
268 logf("blk_read:cf(0x%x), %ld", ep_num, current_tick);
269 usb_drv_stall(ep_num, false, false);
270 }
271
272 if ((rxstat & RXACK) && endp->cnt > 0)
273 {
274 logf("blk_read:ack(0x%x,0x%x), %ld", ep_num, xfer_size, current_tick);
275
276 /* clear NAK bit */
277 BOUT_RXCON(ep_num) &= ~RXNAK;
278
279 endp->cnt -= xfer_size;
280 endp->buf += xfer_size;
281
282 /* if the transfer was short or if the total count is zero,
283 * transfer is complete
284 */
285 if (endp->cnt == 0 || xfer_size < max)
286 {
287 logf("udc_intr: usb_core_transfer_complete(0x%x, USB_DIR_OUT, 0, 0x%x), %ld",
288 ep_num, endp->len, current_tick);
289
290 usb_core_transfer_complete(ep_num, /* ep */
291 USB_DIR_OUT, /* dir */
292 0, /* status */
293 endp->len - endp->cnt); /* length */
294 endp->cnt = 0;
295 }
296 else
297 {
298 BOUT_DMAOUTLMADDR(ep_num) = (uint32_t)endp->buf;
299 BOUT_DMAOUTCTL(ep_num) = DMA_START;
300 }
301 }
206} 302}
207 303
208static void int_write(int ep) 304static void int_write(int ep)
209{ 305{
210 int ep_num = EP_NUM(ep); 306 int ep_num = EP_NUM(ep);
211 int max = usb_drv_port_speed() ? 1024 : 64; 307 int max = usb_drv_port_speed() ? INT_HS_MAX_SIZE : INT_FS_MAX_SIZE;
212 int xfer_size = (endpoints[ep_num].cnt > max) ? max : endpoints[ep_num].cnt; 308 int xfer_size = MIN(endpoints[ep_num].cnt, max);
213 unsigned int timeout = current_tick + HZ/10; 309 unsigned int timeout = current_tick + HZ/10;
214 310
215 while (IIN_TXBUF(ep_num) & TXFULL) /* TXFULL flag */ 311 while (IIN_TXBUF(ep_num) & TXFULL)
216 { 312 {
217 if(TIME_AFTER(current_tick, timeout)) 313 if (TIME_AFTER(current_tick, timeout))
218 break; 314 break;
219 } 315 }
220 316
@@ -234,167 +330,99 @@ static void int_write(int ep)
234 endpoints[ep_num].buf += xfer_size; 330 endpoints[ep_num].buf += xfer_size;
235} 331}
236 332
237/* UDC ISR function */ 333static void int_in_irq_handler(int ep_num)
238void INT_UDC(void)
239{ 334{
240 uint32_t txstat, rxstat; 335 uint32_t txstat = IIN_TXSTAT(ep_num);
241 int tmp, ep_num; 336 struct endpoint_t *endp = &endpoints[ep_num];
242
243 /* read what caused UDC irq */
244 uint32_t intsrc = INT2FLAG & 0x7fffff;
245
246 if (intsrc & SETUP_INTR) /* setup interrupt */
247 {
248 setup_received();
249 }
250 else if (intsrc & IN0_INTR) /* ep0 in interrupt */
251 {
252 txstat = TX0STAT; /* read clears flags */
253
254 /* TODO handle errors */
255 if (txstat & TXACK) /* check TxACK flag */
256 {
257 if (ctrlep[DIR_IN].cnt >= 0)
258 {
259 /* we still have data to send (or ZLP) */
260 ctr_write();
261 }
262 else
263 {
264 /* final ack received */
265 usb_core_transfer_complete(0, /* ep */
266 USB_DIR_IN, /* dir */
267 0, /* status */
268 ctrlep[DIR_IN].len); /* length */
269
270 /* release semaphore for blocking transfer */
271 if (ctrlep[DIR_IN].block)
272 semaphore_release(&ctrlep[DIR_IN].complete);
273 }
274 }
275 }
276 else if (intsrc & OUT0_INTR) /* ep0 out interrupt */
277 {
278 rxstat = RX0STAT;
279 337
280 /* TODO handle errors */ 338 if (txstat & TXCFINT)
281 if (rxstat & RXACK) /* RxACK */
282 {
283 if (ctrlep[DIR_OUT].cnt > 0)
284 ctr_read();
285 else
286 usb_core_transfer_complete(0, /* ep */
287 USB_DIR_OUT, /* dir */
288 0, /* status */
289 ctrlep[DIR_OUT].len); /* length */
290 }
291 }
292 else if (intsrc & USBRST_INTR) /* usb reset */
293 {
294 usb_drv_init();
295 }
296 else if (intsrc & RESUME_INTR) /* usb resume */
297 { 339 {
298 TX0CON |= TXCLR; /* TxClr */ 340 logf("int_write: cf(0x%x), %ld", ep_num, current_tick);
299 TX0CON &= ~TXCLR; 341 /* bit cleared by read */
300 RX0CON |= RXCLR; /* RxClr */ 342 usb_drv_stall(ep_num, false, true);
301 RX0CON &= ~RXCLR;
302 } 343 }
303 else if (intsrc & SUSP_INTR) /* usb suspend */ 344
304 { 345 if (txstat & TXERR)
305 }
306 else if (intsrc & CONN_INTR) /* usb connect */
307 { 346 {
347 panicf("error condition ep%d, %ld", ep_num, current_tick);
308 } 348 }
309 else 349
350 if (txstat & TXACK) /* check TxACK flag */
310 { 351 {
311 /* lets figure out which ep generated irq */ 352 if (endp->cnt > 0)
312 tmp = intsrc >> 7;
313 for (ep_num=1; ep_num < 15; ep_num++)
314 { 353 {
315 tmp >>= ep_num; 354 logf("int_write: ack(0x%x), %ld", ep_num, current_tick);
316 if (tmp & 0x01) 355 /* we still have data to send (or ZLP) */
317 break; 356 int_write(ep_num);
318 } 357 }
319 358 else
320 if (intsrc & ((1<<8)|(1<<11)|(1<<14)|(1<<17)|(1<<20)))
321 { 359 {
322 /* bulk out */ 360 logf("udc_intr: usb_core_transfer_complete(0x%x, USB_DIR_IN, 0, 0x%x), %ld",
323 rxstat = BOUT_RXSTAT(ep_num); 361 ep_num, endp->len, current_tick);
324 362
325 /* TODO handle errors */ 363 /* final ack received */
326 if (rxstat & (1<<18)) /* RxACK */ 364 usb_core_transfer_complete(ep_num, /* ep */
365 USB_DIR_IN, /* dir */
366 0, /* status */
367 endp->len); /* length */
368
369 /* release semaphore for blocking transfer */
370 if (endp->block)
327 { 371 {
328 if (endpoints[ep_num].cnt > 0) 372 logf("udc_intr: ep=0x%x, semaphore_release(), %ld",
329 blk_read(ep_num); 373 ep_num, current_tick);
330 else 374
331 usb_core_transfer_complete(ep_num, /* ep */ 375 semaphore_release(&endp->complete);
332 USB_DIR_OUT, /* dir */
333 0, /* status */
334 endpoints[ep_num].len); /* length */
335 } 376 }
336 } 377 }
337 else if (intsrc & ((1<<9)|(1<<12)|(1<<15)|(1<<18)|(1<<21))) 378 }
379}
380
381static void udc_phy_reset(void)
382{
383 DEV_CTL |= SOFT_POR;
384 udelay(10000); /* min 10ms */
385 DEV_CTL &= ~SOFT_POR;
386}
387
388static void udc_soft_connect(void)
389{
390 DEV_CTL |= CSR_DONE |
391 DEV_SOFT_CN |
392 DEV_SELF_PWR;
393}
394
395static void udc_helper(void)
396{
397 uint32_t dev_info = DEV_INFO;
398
399 /* This polls for DEV_EN bit set in DEV_INFO register
400 * as well as tracks current requested configuration
401 * (DEV_INFO [11:8]). On state change it notifies usb stack
402 * about it.
403 */
404
405 /* SET ADDRESS request */
406 if (set_address == false)
407 if ((dev_info & 0x7f))
338 { 408 {
339 /* bulk in */ 409 set_address = true;
340 txstat = BIN_TXSTAT(ep_num); 410 usb_core_notify_set_address(dev_info & 0x7f);
341
342 /* TODO handle errors */
343 if (txstat & (1<<18)) /* check TxACK flag */
344 {
345 if (endpoints[ep_num].cnt >= 0)
346 {
347 /* we still have data to send (or ZLP) */
348 blk_write(ep_num);
349 }
350 else
351 {
352 /* final ack received */
353 usb_core_transfer_complete(ep_num, /* ep */
354 USB_DIR_IN, /* dir */
355 0, /* status */
356 endpoints[ep_num].len); /* length */
357
358 /* release semaphore for blocking transfer */
359 if (endpoints[ep_num].block)
360 semaphore_release(&endpoints[ep_num].complete);
361 }
362 }
363 } 411 }
364 else if (intsrc & ((1<<10)|(1<13)|(1<<16)|(1<<19)|(1<<22)))
365 {
366 /* int in */
367 txstat = IIN_TXSTAT(ep_num);
368 412
369 /* TODO handle errors */ 413 /* SET CONFIGURATION request */
370 if (txstat & TXACK) /* check TxACK flag */ 414 if (set_configuration == false)
371 { 415 if (dev_info & DEV_EN)
372 if (endpoints[ep_num].cnt >= 0) 416 {
373 { 417 set_configuration = true;
374 /* we still have data to send (or ZLP) */ 418 usb_core_notify_set_config(((dev_info >> 7) & 0xf) + 1);
375 int_write(ep_num);
376 }
377 else
378 {
379 /* final ack received */
380 usb_core_transfer_complete(ep_num, /* ep */
381 USB_DIR_IN, /* dir */
382 0, /* status */
383 endpoints[ep_num].len); /* length */
384
385 /* release semaphore for blocking transfer */
386 if (endpoints[ep_num].block)
387 semaphore_release(&endpoints[ep_num].complete);
388 }
389 }
390 } 419 }
391 }
392} 420}
393 421
394/* return port speed FS=0, HS=1 */ 422/* return port speed */
395int usb_drv_port_speed(void) 423int usb_drv_port_speed(void)
396{ 424{
397 return ((DEV_INFO & DEV_SPEED) == 0) ? 0 : 1; 425 return ((DEV_INFO & DEV_SPEED) ? USB_FULL_SPEED : USB_HIGH_SPEED);
398} 426}
399 427
400/* Reserve endpoint */ 428/* Reserve endpoint */
@@ -410,7 +438,7 @@ int usb_drv_request_endpoint(int type, int dir)
410 logf("req: %s %s", XFER_DIR_STR(ep_dir), XFER_TYPE_STR(ep_type)); 438 logf("req: %s %s", XFER_DIR_STR(ep_dir), XFER_TYPE_STR(ep_type));
411 439
412 /* Find an available ep/dir pair */ 440 /* Find an available ep/dir pair */
413 for (ep_num=1;ep_num<USB_NUM_ENDPOINTS;ep_num++) 441 for (ep_num = 1; ep_num < USB_NUM_ENDPOINTS; ep_num++)
414 { 442 {
415 struct endpoint_t* endpoint = &endpoints[ep_num]; 443 struct endpoint_t* endpoint = &endpoints[ep_num];
416 444
@@ -420,7 +448,35 @@ int usb_drv_request_endpoint(int type, int dir)
420 { 448 {
421 /* mark endpoint as taken */ 449 /* mark endpoint as taken */
422 endpoint->allocated = true; 450 endpoint->allocated = true;
423 451
452 if (ep_num%3 == 0) /* IIN 3, 6, 9, 12, 15 */
453 {
454 IIN_TXCON(ep_num) = (ep_num<<8) | /* set ep number */
455 TXERRINTEN |
456 TXEPEN | /* endpoint enable */
457 TXNAK | /* respond with NAK */
458 TXACKINTEN | /* irq on ACK */
459 TXCFINTE; /* irq on Clear feature */
460 }
461 else if (ep_num%3 == 1) /* BOUT 1, 4, 7, 10, 13 */
462 {
463 BOUT_RXCON(ep_num) = (ep_num<<8) | /* set ep number */
464 RXERRINTEN |
465 RXEPEN | /* endpoint enable */
466 RXNAK | /* respond with NAK */
467 RXACKINTEN | /* irq on ACK */
468 RXCFINTE; /* irq on Clear feature */
469 }
470 else if (ep_num%3 == 2) /* BIN 2, 5, 8, 11, 14 */
471 {
472 BIN_TXCON(ep_num) = (ep_num<<8) | /* set ep number */
473 TXERRINTEN |
474 TXEPEN | /* endpoint enable */
475 TXNAK | /* respond with NAK */
476 TXACKINTEN | /* irq on ACK */
477 TXCFINTE; /* irq on Clear feature */
478 }
479
424 /* enable interrupt from this endpoint */ 480 /* enable interrupt from this endpoint */
425 EN_INT |= (1<<(ep_num+7)); 481 EN_INT |= (1<<(ep_num+7));
426 482
@@ -435,10 +491,7 @@ int usb_drv_request_endpoint(int type, int dir)
435void usb_drv_release_endpoint(int ep) 491void usb_drv_release_endpoint(int ep)
436{ 492{
437 int ep_num = EP_NUM(ep); 493 int ep_num = EP_NUM(ep);
438 int ep_dir = EP_DIR(ep); 494 logf("rel: ep%d %s", ep_num, XFER_DIR_STR(EP_DIR(ep)));
439 (void) ep_dir;
440
441 logf("rel: ep%d %s", ep_num, XFER_DIR_STR(ep_dir));
442 endpoints[ep_num].allocated = false; 495 endpoints[ep_num].allocated = false;
443 496
444 /* disable interrupt from this endpoint */ 497 /* disable interrupt from this endpoint */
@@ -454,14 +507,20 @@ void usb_drv_release_endpoint(int ep)
454void usb_drv_set_address(int address) 507void usb_drv_set_address(int address)
455{ 508{
456 (void)address; 509 (void)address;
457 /* UDC seems to set this automaticaly */ 510 /* UDC sets this automaticaly */
458} 511}
459 512
460static int _usb_drv_send(int endpoint, void *ptr, int length, bool block) 513static int _usb_drv_send(int endpoint, void *ptr, int length, bool block)
461{ 514{
462 struct endpoint_t *ep; 515 struct endpoint_t *ep;
463 int ep_num = EP_NUM(endpoint); 516 int ep_num = EP_NUM(endpoint);
464 517
518 /* for send transfers, make sure the data is committed */
519 commit_discard_dcache_range(ptr, length);
520
521 logf("_usb_drv_send: endpt=0x%x, len=0x%x, block=%d",
522 endpoint, length, block);
523
465 if (ep_num == 0) 524 if (ep_num == 0)
466 ep = &ctrlep[DIR_IN]; 525 ep = &ctrlep[DIR_IN];
467 else 526 else
@@ -477,7 +536,7 @@ static int _usb_drv_send(int endpoint, void *ptr, int length, bool block)
477 536
478 switch (ep->type) 537 switch (ep->type)
479 { 538 {
480 case USB_ENDPOINT_XFER_CONTROL: 539 case USB_ENDPOINT_XFER_CONTROL:
481 ctr_write(); 540 ctr_write();
482 break; 541 break;
483 542
@@ -515,30 +574,40 @@ int usb_drv_recv(int endpoint, void* ptr, int length)
515 struct endpoint_t *ep; 574 struct endpoint_t *ep;
516 int ep_num = EP_NUM(endpoint); 575 int ep_num = EP_NUM(endpoint);
517 576
577 logf("usb_drv_recv: endpt=0x%x, len=0x%x, %ld",
578 endpoint, length, current_tick);
579
580 /* for recv, discard the cache lines related to the buffer */
581 commit_discard_dcache_range(ptr, length);
582
518 if (ep_num == 0) 583 if (ep_num == 0)
519 { 584 {
520 ep = &ctrlep[DIR_OUT]; 585 ep = &ctrlep[DIR_OUT];
521 586 ep->buf = ptr;
522 ctr_read(); 587 ep->len = ep->cnt = length;
588
589 /* clear NAK bit */
590 RX0CON &= ~RXNAK;
591 RX0DMAOUTLMADDR = (uint32_t)ptr; /* buffer address */
592 RX0DMACTLO = DMA_START; /* start DMA */
523 } 593 }
524 else 594 else
525 { 595 {
526 ep = &endpoints[ep_num]; 596 ep = &endpoints[ep_num];
527 597 ep->buf = ptr;
598 ep->len = ep->cnt = length;
599
528 /* clear NAK bit */ 600 /* clear NAK bit */
529 BOUT_RXCON(ep_num) &= ~RXNAK; 601 BOUT_RXCON(ep_num) &= ~RXNAK;
530 BOUT_DMAOUTLMADDR(ep_num) = (uint32_t)ptr; 602 BOUT_DMAOUTLMADDR(ep_num) = (uint32_t)ptr;
531 BOUT_DMAOUTCTL(ep_num) = DMA_START; 603 BOUT_DMAOUTCTL(ep_num) = DMA_START;
532 } 604 }
533
534 ep->buf = ptr;
535 ep->len = ep->cnt = length;
536 605
537 return 0; 606 return 0;
538} 607}
539 608
540/* Kill all transfers. Usually you need to set a bit for each endpoint 609/* Kill all transfers. Usually you need to set a bit for each endpoint
541 * and flush fifos. You should also call the completion handler with 610 * and flush fifos. You should also call the completion handler with
542 * error status for everything 611 * error status for everything
543 */ 612 */
544void usb_drv_cancel_all_transfers(void) 613void usb_drv_cancel_all_transfers(void)
@@ -592,6 +661,8 @@ bool usb_drv_stalled(int endpoint, bool in)
592void usb_drv_stall(int endpoint, bool stall, bool in) 661void usb_drv_stall(int endpoint, bool stall, bool in)
593{ 662{
594 int ep_num = EP_NUM(endpoint); 663 int ep_num = EP_NUM(endpoint);
664 logf("usb_drv: %sstall EP%d %s",
665 stall ? "": "un", ep_num, in ? "IN" : "OUT");
595 666
596 switch (endpoints[ep_num].type) 667 switch (endpoints[ep_num].type)
597 { 668 {
@@ -645,87 +716,23 @@ void usb_drv_stall(int endpoint, bool stall, bool in)
645void usb_drv_init(void) 716void usb_drv_init(void)
646{ 717{
647 int ep_num; 718 int ep_num;
648
649 /* enable USB clock */
650 SCU_CLKCFG &= ~CLKCFG_UDC;
651
652 /* 1. do soft disconnect */
653 DEV_CTL = DEV_SELF_PWR;
654
655 /* 2. do power on reset to PHY */
656 DEV_CTL = DEV_SELF_PWR |
657 SOFT_POR;
658
659 /* 3. wait more than 10ms */
660 udelay(20000);
661
662 /* 4. clear SOFT_POR bit */
663 DEV_CTL &= ~SOFT_POR;
664
665 /* 5. configure minimal EN_INT */
666 EN_INT = EN_SUSP_INTR | /* Enable Suspend Interrupt */
667 EN_RESUME_INTR | /* Enable Resume Interrupt */
668 EN_USBRST_INTR | /* Enable USB Reset Interrupt */
669 EN_OUT0_INTR | /* Enable OUT Token receive Interrupt EP0 */
670 EN_IN0_INTR | /* Enable IN Token transmits Interrupt EP0 */
671 EN_SETUP_INTR; /* Enable SETUP Packet Receive Interrupt */
672
673 /* 6. configure INTCON */
674 INTCON = UDC_INTHIGH_ACT | /* interrupt high active */
675 UDC_INTEN; /* enable EP0 interrupts */
676
677 /* 7. configure EP0 control registers */
678 TX0CON = TXACKINTEN | /* Set as one to enable the EP0 tx irq */
679 TXNAK; /* Set as one to response NAK handshake */
680
681 RX0CON = RXACKINTEN |
682 RXEPEN | /* Endpoint 0 Enable. When cleared the endpoint does
683 * not respond to an SETUP or OUT token
684 */
685
686 RXNAK; /* Set as one to response NAK handshake */
687
688 /* 8. write final bits to DEV_CTL */
689 DEV_CTL = CSR_DONE | /* Configure CSR done */
690 DEV_PHY16BIT | /* 16-bit data path enabled. udc_clk = 30MHz */
691 DEV_SOFT_CN | /* Device soft connect */
692 DEV_SELF_PWR; /* Device self power */
693 719
694 /* init semaphore of ep0 */ 720 /* init semaphore of ep0 */
695 semaphore_init(&ctrlep[DIR_OUT].complete, 1, 0); 721 semaphore_init(&ctrlep[DIR_OUT].complete, 1, 0);
696 semaphore_init(&ctrlep[DIR_IN].complete, 1, 0); 722 semaphore_init(&ctrlep[DIR_IN].complete, 1, 0);
697 723
724 /* init semaphores for other endpoints */
698 for (ep_num = 1; ep_num < USB_NUM_ENDPOINTS; ep_num++) 725 for (ep_num = 1; ep_num < USB_NUM_ENDPOINTS; ep_num++)
699 {
700 semaphore_init(&endpoints[ep_num].complete, 1, 0); 726 semaphore_init(&endpoints[ep_num].complete, 1, 0);
701
702 if (ep_num%3 == 0) /* IIN 3, 6, 9, 12, 15 */
703 {
704 IIN_TXCON(ep_num) |= (ep_num<<8)|TXEPEN|TXNAK; /* ep_num, enable, NAK */
705 }
706 else if (ep_num%3 == 1) /* BOUT 1, 4, 7, 10, 13 */
707 {
708 BOUT_RXCON(ep_num) |= (ep_num<<8)|RXEPEN|RXNAK; /* ep_num, NAK, enable */
709 }
710 else if (ep_num%3 == 2) /* BIN 2, 5, 8, 11, 14 */
711 {
712 BIN_TXCON(ep_num) |= (ep_num<<8)|TXEPEN|TXNAK; /* ep_num, enable, NAK */
713 }
714 }
715} 727}
716 728
717/* turn off usb core */ 729/* turn off usb core */
718void usb_drv_exit(void) 730void usb_drv_exit(void)
719{ 731{
720 DEV_CTL = DEV_SELF_PWR; 732 /* udc module reset */
721 733 SCU_RSTCFG |= (1<<1);
722 /* disable USB interrupts in interrupt controller */ 734 udelay(10);
723 INTC_IMR &= ~IRQ_ARM_UDC; 735 SCU_RSTCFG &= ~(1<<1);
724 INTC_IECR &= ~IRQ_ARM_UDC;
725
726 /* we cannot disable UDC clock since this causes data abort
727 * when reading DEV_INFO in order to check usb connect event
728 */
729} 736}
730 737
731int usb_detect(void) 738int usb_detect(void)
@@ -736,3 +743,140 @@ int usb_detect(void)
736 return USB_EXTRACTED; 743 return USB_EXTRACTED;
737} 744}
738 745
746/* UDC ISR function */
747void INT_UDC(void)
748{
749 uint32_t txstat, rxstat;
750 int ep_num;
751
752 /* read what caused UDC irq */
753 uint32_t intsrc = INT2FLAG & 0x7fffff;
754
755 if (intsrc & USBRST_INTR) /* usb reset */
756 {
757 logf("udc_int: reset, %ld", current_tick);
758
759 EN_INT = EN_SUSP_INTR | /* Enable Suspend Irq */
760 EN_RESUME_INTR | /* Enable Resume Irq */
761 EN_USBRST_INTR | /* Enable USB Reset Irq */
762 EN_OUT0_INTR | /* Enable OUT Token receive Irq EP0 */
763 EN_IN0_INTR | /* Enable IN Token transmit Irq EP0 */
764 EN_SETUP_INTR; /* Enable SETUP Packet Receive Irq */
765
766 INTCON = UDC_INTHIGH_ACT | /* interrupt high active */
767 UDC_INTEN; /* enable EP0 irqs */
768
769 TX0CON = TXACKINTEN | /* Set as one to enable the EP0 tx irq */
770 TXNAK; /* Set as one to response NAK handshake */
771
772 RX0CON = RXACKINTEN |
773 RXEPEN | /* Endpoint 0 Enable. When cleared the
774 * endpoint does not respond to an SETUP
775 * or OUT token */
776 RXNAK; /* Set as one to response NAK handshake */
777
778 set_address = false;
779 set_configuration = false;
780 }
781
782 /* This needs to be processed AFTER usb reset */
783 udc_helper();
784
785 if (intsrc & SETUP_INTR) /* setup interrupt */
786 {
787 setup_irq_handler();
788 }
789
790 if (intsrc & IN0_INTR) /* ep0 in interrupt */
791 {
792 txstat = TX0STAT; /* read clears flags */
793
794 /* TODO handle errors */
795 if (txstat & TXACK) /* check TxACK flag */
796 {
797 if (ctrlep[DIR_IN].cnt >= 0)
798 {
799 /* we still have data to send (or ZLP) */
800 ctr_write();
801 }
802 else
803 {
804 /* final ack received */
805 usb_core_transfer_complete(0, /* ep */
806 USB_DIR_IN, /* dir */
807 0, /* status */
808 ctrlep[DIR_IN].len); /* length */
809
810 /* release semaphore for blocking transfer */
811 if (ctrlep[DIR_IN].block)
812 semaphore_release(&ctrlep[DIR_IN].complete);
813 }
814 }
815 }
816
817 if (intsrc & OUT0_INTR) /* ep0 out interrupt */
818 {
819 rxstat = RX0STAT;
820
821 /* TODO handle errors */
822 if (rxstat & RXACK) /* RxACK */
823 {
824 if (ctrlep[DIR_OUT].cnt > 0)
825 ctr_read();
826 else
827 usb_core_transfer_complete(0, /* ep */
828 USB_DIR_OUT, /* dir */
829 0, /* status */
830 ctrlep[DIR_OUT].len); /* length */
831 }
832 }
833
834 if (intsrc & RESUME_INTR) /* usb resume */
835 {
836 TX0CON |= TXCLR; /* TxClr */
837 TX0CON &= ~TXCLR;
838
839 RX0CON |= RXCLR; /* RxClr */
840 RX0CON &= ~RXCLR;
841 }
842
843 if (intsrc & SUSP_INTR) /* usb suspend */
844 {
845 }
846
847 if (intsrc & CONN_INTR) /* usb connect */
848 {
849 udc_phy_reset();
850 udelay(10000); /* wait at least 10ms */
851 udc_soft_connect();
852 }
853
854 /* endpoints other then EP0 */
855 if (intsrc & 0x7fff00)
856 {
857 /* lets figure out which ep generated irq */
858 for (ep_num = 1; ep_num < USB_NUM_ENDPOINTS; ep_num++)
859 {
860 struct endpoint_t *ep = &endpoints[ep_num];
861
862 if ((intsrc & ep->intr_mask) && ep->allocated)
863 {
864 switch (ep->type)
865 {
866 case USB_ENDPOINT_XFER_BULK:
867 if (ep->dir == DIR_OUT)
868 blk_out_irq_handler(ep_num);
869 else
870 blk_in_irq_handler(ep_num);
871
872 break;
873
874 case USB_ENDPOINT_XFER_INT:
875 int_in_irq_handler(ep_num);
876
877 break;
878 }
879 }
880 }
881 }
882}
diff --git a/firmware/target/arm/rk27xx/usb-rk27xx.c b/firmware/target/arm/rk27xx/usb-rk27xx.c
index 20bf867c8d..09c9090a3b 100644
--- a/firmware/target/arm/rk27xx/usb-rk27xx.c
+++ b/firmware/target/arm/rk27xx/usb-rk27xx.c
@@ -32,6 +32,20 @@ int usb_status = USB_EXTRACTED;
32 32
33void usb_init_device(void) 33void usb_init_device(void)
34{ 34{
35 /* enable UDC interrupt */
36 INTC_IMR |= (1<<16);
37 INTC_IECR |= (1<<16);
38
39 EN_INT = EN_SUSP_INTR | /* Enable Suspend Interrupt */
40 EN_RESUME_INTR | /* Enable Resume Interrupt */
41 EN_USBRST_INTR | /* Enable USB Reset Interrupt */
42 EN_OUT0_INTR | /* Enable OUT Token receive Interrupt EP0 */
43 EN_IN0_INTR | /* Enable IN Token transmits Interrupt EP0 */
44 EN_SETUP_INTR; /* Enable SETUP Packet Receive Interrupt */
45
46 /* configure INTCON */
47 INTCON = UDC_INTHIGH_ACT | /* interrupt high active */
48 UDC_INTEN; /* enable EP0 interrupts */
35} 49}
36 50
37void usb_attach(void) 51void usb_attach(void)