summaryrefslogtreecommitdiff
path: root/firmware/target/arm/rk27xx/usb-drv-rk27xx.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/rk27xx/usb-drv-rk27xx.c')
-rw-r--r--firmware/target/arm/rk27xx/usb-drv-rk27xx.c714
1 files changed, 285 insertions, 429 deletions
diff --git a/firmware/target/arm/rk27xx/usb-drv-rk27xx.c b/firmware/target/arm/rk27xx/usb-drv-rk27xx.c
index af613e7024..9380f54193 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$
8 * 9 *
9 * Copyright (C) 2011 by Marcin Bukat 10 * 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,12 +28,13 @@
28#include "kernel.h" 28#include "kernel.h"
29#include "panic.h" 29#include "panic.h"
30 30
31//#include "usb-s3c6400x.h"
32
31#include "usb_ch9.h" 33#include "usb_ch9.h"
32#include "usb_core.h" 34#include "usb_core.h"
33#include <inttypes.h> 35#include <inttypes.h>
34#include "power.h" 36#include "power.h"
35 37
36/*#define LOGF_ENABLE*/
37#include "logf.h" 38#include "logf.h"
38 39
39typedef volatile uint32_t reg32; 40typedef volatile uint32_t reg32;
@@ -58,16 +59,6 @@ typedef volatile uint32_t reg32;
58#define IIN_DMAINCTL(ep_num) (*(reg32*)(AHB0_UDC+0x84+0x38*((ep_num/3)-1))) 59#define IIN_DMAINCTL(ep_num) (*(reg32*)(AHB0_UDC+0x84+0x38*((ep_num/3)-1)))
59#define IIN_DMAINLMADDR(ep_num) (*(reg32*)(AHB0_UDC+0x88+0x38*((ep_num/3)-1))) 60#define IIN_DMAINLMADDR(ep_num) (*(reg32*)(AHB0_UDC+0x88+0x38*((ep_num/3)-1)))
60 61
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
71#ifdef LOGF_ENABLE 62#ifdef LOGF_ENABLE
72#define XFER_DIR_STR(dir) ((dir) ? "IN" : "OUT") 63#define XFER_DIR_STR(dir) ((dir) ? "IN" : "OUT")
73#define XFER_TYPE_STR(type) \ 64#define XFER_TYPE_STR(type) \
@@ -80,7 +71,6 @@ typedef volatile uint32_t reg32;
80struct endpoint_t { 71struct endpoint_t {
81 const int type; /* EP type */ 72 const int type; /* EP type */
82 const int dir; /* DIR_IN/DIR_OUT */ 73 const int dir; /* DIR_IN/DIR_OUT */
83 const unsigned int intr_mask;
84 bool allocated; /* flag to mark EPs taken */ 74 bool allocated; /* flag to mark EPs taken */
85 volatile void *buf; /* tx/rx buffer address */ 75 volatile void *buf; /* tx/rx buffer address */
86 volatile int len; /* size of the transfer (bytes) */ 76 volatile int len; /* size of the transfer (bytes) */
@@ -90,33 +80,30 @@ struct endpoint_t {
90}; 80};
91 81
92static struct endpoint_t ctrlep[2] = { 82static struct endpoint_t ctrlep[2] = {
93 {USB_ENDPOINT_XFER_CONTROL, DIR_OUT, 0, true, NULL, 0, 0, true, {0, 0, 0}}, 83 {USB_ENDPOINT_XFER_CONTROL, DIR_OUT, true, NULL, 0, 0, true, {0, 0, 0}},
94 {USB_ENDPOINT_XFER_CONTROL, DIR_IN, 0, true, NULL, 0, 0, true, {0, 0, 0}} 84 {USB_ENDPOINT_XFER_CONTROL, DIR_IN, true, NULL, 0, 0, true, {0, 0, 0}}
95}; 85};
96 86
97static struct endpoint_t endpoints[16] = { 87static struct endpoint_t endpoints[16] = {
98 {USB_ENDPOINT_XFER_CONTROL, 3, 0, true, NULL, 0, 0, true, {0, 0, 0}}, /* stub */ 88 {USB_ENDPOINT_XFER_CONTROL, 3, true, NULL, 0, 0, true, {0, 0, 0}}, /* stub */
99 {USB_ENDPOINT_XFER_BULK, DIR_OUT, BOUT1_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* BOUT1 */ 89 {USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false, {0, 0, 0}}, /* BOUT1 */
100 {USB_ENDPOINT_XFER_BULK, DIR_IN, BIN2_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* BIN2 */ 90 {USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false, {0, 0, 0}}, /* BIN2 */
101 {USB_ENDPOINT_XFER_INT, DIR_IN, IIN3_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* IIN3 */ 91 {USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false, {0, 0, 0}}, /* IIN3 */
102 {USB_ENDPOINT_XFER_BULK, DIR_OUT, BOUT4_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* BOUT4 */ 92 {USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false, {0, 0, 0}}, /* BOUT4 */
103 {USB_ENDPOINT_XFER_BULK, DIR_IN, BIN5_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* BIN5 */ 93 {USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false, {0, 0, 0}}, /* BIN5 */
104 {USB_ENDPOINT_XFER_INT, DIR_IN, IIN6_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* IIN6 */ 94 {USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false, {0, 0, 0}}, /* IIN6 */
105 {USB_ENDPOINT_XFER_BULK, DIR_OUT, BOUT7_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* BOUT7 */ 95 {USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false, {0, 0, 0}}, /* BOUT7 */
106 {USB_ENDPOINT_XFER_BULK, DIR_IN, BIN8_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* BIN8 */ 96 {USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false, {0, 0, 0}}, /* BIN8 */
107 {USB_ENDPOINT_XFER_INT, DIR_IN, IIN9_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* IIN9 */ 97 {USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false, {0, 0, 0}}, /* IIN9 */
108 {USB_ENDPOINT_XFER_BULK, DIR_OUT, BOUT10_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* BOUT10 */ 98 {USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false, {0, 0, 0}}, /* BOUT10 */
109 {USB_ENDPOINT_XFER_BULK, DIR_IN, BIN11_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* BIN11 */ 99 {USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false, {0, 0, 0}}, /* BIN11 */
110 {USB_ENDPOINT_XFER_INT, DIR_IN, IIN12_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* IIN12 */ 100 {USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false, {0, 0, 0}}, /* IIN12 */
111 {USB_ENDPOINT_XFER_BULK, DIR_OUT, BOUT13_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* BOUT13 */ 101 {USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false, {0, 0, 0}}, /* BOUT13 */
112 {USB_ENDPOINT_XFER_BULK, DIR_IN, BIN14_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* BIN14 */ 102 {USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false, {0, 0, 0}}, /* BIN14 */
113 {USB_ENDPOINT_XFER_INT, DIR_IN, IIN15_INTR, false, NULL, 0, 0, false, {0, 0, 0}}, /* IIN15 */ 103 {USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false, {0, 0, 0}}, /* IIN15 */
114}; 104};
115 105
116static volatile bool set_address = false; 106static void setup_received(void)
117static volatile bool set_configuration = false;
118
119static void setup_irq_handler(void)
120{ 107{
121 static uint32_t setup_data[2]; 108 static uint32_t setup_data[2];
122 109
@@ -124,6 +111,10 @@ static void setup_irq_handler(void)
124 setup_data[0] = SETUP1; 111 setup_data[0] = SETUP1;
125 setup_data[1] = SETUP2; 112 setup_data[1] = SETUP2;
126 113
114 /* clear all pending control transfers
115 * do we need this here?
116 */
117
127 /* pass setup data to the upper layer */ 118 /* pass setup data to the upper layer */
128 usb_core_control_request((struct usb_ctrlrequest*)setup_data); 119 usb_core_control_request((struct usb_ctrlrequest*)setup_data);
129} 120}
@@ -131,12 +122,12 @@ static void setup_irq_handler(void)
131/* service ep0 IN transaction */ 122/* service ep0 IN transaction */
132static void ctr_write(void) 123static void ctr_write(void)
133{ 124{
134 int xfer_size = MIN(ctrlep[DIR_IN].cnt, CTL_MAX_SIZE); 125 int xfer_size = (ctrlep[DIR_IN].cnt > 64) ? 64 : ctrlep[DIR_IN].cnt;
135 unsigned int timeout = current_tick + HZ/10; 126 unsigned int timeout = current_tick + HZ/10;
136 127
137 while (TX0BUF & TXFULL) /* TX0FULL flag */ 128 while (TX0BUF & TXFULL) /* TX0FULL flag */
138 { 129 {
139 if (TIME_AFTER(current_tick, timeout)) 130 if(TIME_AFTER(current_tick, timeout))
140 break; 131 break;
141 } 132 }
142 133
@@ -152,7 +143,7 @@ static void ctr_write(void)
152 * get zero len after transfer which indicates we need to send 143 * get zero len after transfer which indicates we need to send
153 * zero length packet to signal host end of the transfer. 144 * zero length packet to signal host end of the transfer.
154 */ 145 */
155 ctrlep[DIR_IN].cnt -= CTL_MAX_SIZE; 146 ctrlep[DIR_IN].cnt -= 64;
156 ctrlep[DIR_IN].buf += xfer_size; 147 ctrlep[DIR_IN].buf += xfer_size;
157} 148}
158 149
@@ -170,147 +161,60 @@ static void ctr_read(void)
170 RX0DMACTLO = DMA_START; /* start DMA */ 161 RX0DMACTLO = DMA_START; /* start DMA */
171} 162}
172 163
173static void blk_write(int ep_num) 164static void blk_write(int ep)
174{ 165{
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;
175 unsigned int timeout = current_tick + HZ/10; 169 unsigned int timeout = current_tick + HZ/10;
176 int max = usb_drv_port_speed() ? BLK_HS_MAX_SIZE : BLK_FS_MAX_SIZE; 170
177 int xfer_size = MIN(endpoints[ep_num].cnt, max);
178
179 while (BIN_TXBUF(ep_num) & TXFULL) /* TXFULL flag */ 171 while (BIN_TXBUF(ep_num) & TXFULL) /* TXFULL flag */
180 { 172 {
181 if (TIME_AFTER(current_tick, timeout)) 173 if(TIME_AFTER(current_tick, timeout))
182 break; 174 break;
183 } 175 }
184 176
185 BIN_TXSTAT(ep_num) = xfer_size; /* size */ 177 BIN_TXSTAT(ep_num) = xfer_size; /* size */
186 BIN_DMAINLMADDR(ep_num) = (uint32_t)endpoints[ep_num].buf; /* buf address */ 178 BIN_DMAINLMADDR(ep_num) = (uint32_t)endpoints[ep_num].buf; /* buf address */
187 BIN_DMAINCTL(ep_num) = DMA_START; /* start DMA */ 179 BIN_DMAINCTL(ep_num) = DMA_START; /* start DMA */
188 BIN_TXCON(ep_num) &= ~TXNAK; /* clear NAK */ 180 BIN_TXCON(ep_num) &= ~TXNAK; /* clear NAK */
189 181
190 /* Decrement by max packet size is intentional. 182 /* Decrement by max packet size is intentional.
191 * This way if we have final packet short one we will get negative len 183 * This way if we have final packet short one we will get negative len
192 * after transfer, which in turn indicates we *don't* need to send 184 * after transfer, which in turn indicates we *don't* need to send
193 * zero length packet. If the final packet is max sized packet we will 185 * zero length packet. If the final packet is max sized packet we will
194 * get zero len after transfer which indicates we need to send 186 * get zero len after transfer which indicates we need to send
195 * zero length packet to signal host end of the transfer. 187 * zero length packet to signal host end of the transfer.
196 */ 188 */
197 endpoints[ep_num].cnt -= max; 189 endpoints[ep_num].cnt -= max;
198 endpoints[ep_num].buf += xfer_size; 190 endpoints[ep_num].buf += xfer_size;
199} 191}
200 192
201static void blk_in_irq_handler(int ep_num) 193static void blk_read(int ep)
202{
203 uint32_t txstat = BIN_TXSTAT(ep_num);
204 struct endpoint_t *endp = &endpoints[ep_num];
205
206 if (txstat & TXERR)
207 {
208 panicf("error condition ep%d, %ld", ep_num, current_tick);
209 }
210
211 if (txstat & TXCFINT)
212 {
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{ 194{
251 uint32_t rxstat = BOUT_RXSTAT(ep_num); 195 int ep_num = EP_NUM(ep);
252 int xfer_size = rxstat & 0xffff; 196 int xfer_size = BOUT_RXSTAT(ep_num) & 0xffff;
253 int max = usb_drv_port_speed() ? BLK_HS_MAX_SIZE : BLK_FS_MAX_SIZE; 197
254 struct endpoint_t *endp = &endpoints[ep_num]; 198 /* clear NAK bit */
255 199 BOUT_RXCON(ep_num) &= ~RXNAK;
256 if (rxstat & RXERR) 200
257 { 201 endpoints[ep_num].cnt -= xfer_size;
258 panicf("error condition ep%d, %ld", ep_num, current_tick); 202 endpoints[ep_num].buf += xfer_size;
259 } 203
260 204 BOUT_DMAOUTLMADDR(ep_num) = (uint32_t)endpoints[ep_num].buf;
261 if (rxstat & RXOVF) 205 BOUT_DMAOUTCTL(ep_num) = DMA_START;
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 }
302} 206}
303 207
304static void int_write(int ep) 208static void int_write(int ep)
305{ 209{
306 int ep_num = EP_NUM(ep); 210 int ep_num = EP_NUM(ep);
307 int max = usb_drv_port_speed() ? INT_HS_MAX_SIZE : INT_FS_MAX_SIZE; 211 int max = usb_drv_port_speed() ? 1024 : 64;
308 int xfer_size = MIN(endpoints[ep_num].cnt, max); 212 int xfer_size = (endpoints[ep_num].cnt > max) ? max : endpoints[ep_num].cnt;
309 unsigned int timeout = current_tick + HZ/10; 213 unsigned int timeout = current_tick + HZ/10;
310 214
311 while (IIN_TXBUF(ep_num) & TXFULL) 215 while (IIN_TXBUF(ep_num) & TXFULL) /* TXFULL flag */
312 { 216 {
313 if (TIME_AFTER(current_tick, timeout)) 217 if(TIME_AFTER(current_tick, timeout))
314 break; 218 break;
315 } 219 }
316 220
@@ -330,99 +234,167 @@ static void int_write(int ep)
330 endpoints[ep_num].buf += xfer_size; 234 endpoints[ep_num].buf += xfer_size;
331} 235}
332 236
333static void int_in_irq_handler(int ep_num) 237/* UDC ISR function */
238void INT_UDC(void)
334{ 239{
335 uint32_t txstat = IIN_TXSTAT(ep_num); 240 uint32_t txstat, rxstat;
336 struct endpoint_t *endp = &endpoints[ep_num]; 241 int tmp, ep_num;
337 242
338 if (txstat & TXCFINT) 243 /* read what caused UDC irq */
244 uint32_t intsrc = INT2FLAG & 0x7fffff;
245
246 if (intsrc & SETUP_INTR) /* setup interrupt */
339 { 247 {
340 logf("int_write: cf(0x%x), %ld", ep_num, current_tick); 248 setup_received();
341 /* bit cleared by read */
342 usb_drv_stall(ep_num, false, true);
343 } 249 }
344 250 else if (intsrc & IN0_INTR) /* ep0 in interrupt */
345 if (txstat & TXERR)
346 { 251 {
347 panicf("error condition ep%d, %ld", ep_num, current_tick); 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 }
348 } 275 }
276 else if (intsrc & OUT0_INTR) /* ep0 out interrupt */
277 {
278 rxstat = RX0STAT;
349 279
350 if (txstat & TXACK) /* check TxACK flag */ 280 /* TODO handle errors */
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 */
351 { 293 {
352 if (endp->cnt > 0) 294 usb_drv_init();
295 }
296 else if (intsrc & RESUME_INTR) /* usb resume */
297 {
298 TX0CON |= TXCLR; /* TxClr */
299 TX0CON &= ~TXCLR;
300 RX0CON |= RXCLR; /* RxClr */
301 RX0CON &= ~RXCLR;
302 }
303 else if (intsrc & SUSP_INTR) /* usb suspend */
304 {
305 }
306 else if (intsrc & CONN_INTR) /* usb connect */
307 {
308 }
309 else
310 {
311 /* lets figure out which ep generated irq */
312 tmp = intsrc >> 7;
313 for (ep_num=1; ep_num < 15; ep_num++)
353 { 314 {
354 logf("int_write: ack(0x%x), %ld", ep_num, current_tick); 315 tmp >>= ep_num;
355 /* we still have data to send (or ZLP) */ 316 if (tmp & 0x01)
356 int_write(ep_num); 317 break;
357 } 318 }
358 else 319
320 if (intsrc & ((1<<8)|(1<<11)|(1<<14)|(1<<17)|(1<<20)))
359 { 321 {
360 logf("udc_intr: usb_core_transfer_complete(0x%x, USB_DIR_IN, 0, 0x%x), %ld", 322 /* bulk out */
361 ep_num, endp->len, current_tick); 323 rxstat = BOUT_RXSTAT(ep_num);
362 324
363 /* final ack received */ 325 /* TODO handle errors */
364 usb_core_transfer_complete(ep_num, /* ep */ 326 if (rxstat & (1<<18)) /* RxACK */
365 USB_DIR_IN, /* dir */
366 0, /* status */
367 endp->len); /* length */
368
369 /* release semaphore for blocking transfer */
370 if (endp->block)
371 { 327 {
372 logf("udc_intr: ep=0x%x, semaphore_release(), %ld", 328 if (endpoints[ep_num].cnt > 0)
373 ep_num, current_tick); 329 blk_read(ep_num);
374 330 else
375 semaphore_release(&endp->complete); 331 usb_core_transfer_complete(ep_num, /* ep */
332 USB_DIR_OUT, /* dir */
333 0, /* status */
334 endpoints[ep_num].len); /* length */
376 } 335 }
377 } 336 }
378 } 337 else if (intsrc & ((1<<9)|(1<<12)|(1<<15)|(1<<18)|(1<<21)))
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))
408 { 338 {
409 set_address = true; 339 /* bulk in */
410 usb_core_notify_set_address(dev_info & 0x7f); 340 txstat = BIN_TXSTAT(ep_num);
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 }
411 } 363 }
412 364 else if (intsrc & ((1<<10)|(1<13)|(1<<16)|(1<<19)|(1<<22)))
413 /* SET CONFIGURATION request */
414 if (set_configuration == false)
415 if (dev_info & DEV_EN)
416 { 365 {
417 set_configuration = true; 366 /* int in */
418 usb_core_notify_set_config(((dev_info >> 7) & 0xf) + 1); 367 txstat = IIN_TXSTAT(ep_num);
368
369 /* TODO handle errors */
370 if (txstat & TXACK) /* check TxACK flag */
371 {
372 if (endpoints[ep_num].cnt >= 0)
373 {
374 /* we still have data to send (or ZLP) */
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 }
419 } 390 }
391 }
420} 392}
421 393
422/* return port speed */ 394/* return port speed FS=0, HS=1 */
423int usb_drv_port_speed(void) 395int usb_drv_port_speed(void)
424{ 396{
425 return ((DEV_INFO & DEV_SPEED) ? USB_FULL_SPEED : USB_HIGH_SPEED); 397 return ((DEV_INFO & DEV_SPEED) == 0) ? 0 : 1;
426} 398}
427 399
428/* Reserve endpoint */ 400/* Reserve endpoint */
@@ -438,7 +410,7 @@ int usb_drv_request_endpoint(int type, int dir)
438 logf("req: %s %s", XFER_DIR_STR(ep_dir), XFER_TYPE_STR(ep_type)); 410 logf("req: %s %s", XFER_DIR_STR(ep_dir), XFER_TYPE_STR(ep_type));
439 411
440 /* Find an available ep/dir pair */ 412 /* Find an available ep/dir pair */
441 for (ep_num = 1; ep_num < USB_NUM_ENDPOINTS; ep_num++) 413 for (ep_num=1;ep_num<USB_NUM_ENDPOINTS;ep_num++)
442 { 414 {
443 struct endpoint_t* endpoint = &endpoints[ep_num]; 415 struct endpoint_t* endpoint = &endpoints[ep_num];
444 416
@@ -448,35 +420,7 @@ int usb_drv_request_endpoint(int type, int dir)
448 { 420 {
449 /* mark endpoint as taken */ 421 /* mark endpoint as taken */
450 endpoint->allocated = true; 422 endpoint->allocated = true;
451 423
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
480 /* enable interrupt from this endpoint */ 424 /* enable interrupt from this endpoint */
481 EN_INT |= (1<<(ep_num+7)); 425 EN_INT |= (1<<(ep_num+7));
482 426
@@ -491,7 +435,10 @@ int usb_drv_request_endpoint(int type, int dir)
491void usb_drv_release_endpoint(int ep) 435void usb_drv_release_endpoint(int ep)
492{ 436{
493 int ep_num = EP_NUM(ep); 437 int ep_num = EP_NUM(ep);
494 logf("rel: ep%d %s", ep_num, XFER_DIR_STR(EP_DIR(ep))); 438 int ep_dir = EP_DIR(ep);
439 (void) ep_dir;
440
441 logf("rel: ep%d %s", ep_num, XFER_DIR_STR(ep_dir));
495 endpoints[ep_num].allocated = false; 442 endpoints[ep_num].allocated = false;
496 443
497 /* disable interrupt from this endpoint */ 444 /* disable interrupt from this endpoint */
@@ -507,20 +454,14 @@ void usb_drv_release_endpoint(int ep)
507void usb_drv_set_address(int address) 454void usb_drv_set_address(int address)
508{ 455{
509 (void)address; 456 (void)address;
510 /* UDC sets this automaticaly */ 457 /* UDC seems to set this automaticaly */
511} 458}
512 459
513static int _usb_drv_send(int endpoint, void *ptr, int length, bool block) 460static int _usb_drv_send(int endpoint, void *ptr, int length, bool block)
514{ 461{
515 struct endpoint_t *ep; 462 struct endpoint_t *ep;
516 int ep_num = EP_NUM(endpoint); 463 int ep_num = EP_NUM(endpoint);
517 464
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
524 if (ep_num == 0) 465 if (ep_num == 0)
525 ep = &ctrlep[DIR_IN]; 466 ep = &ctrlep[DIR_IN];
526 else 467 else
@@ -536,7 +477,7 @@ static int _usb_drv_send(int endpoint, void *ptr, int length, bool block)
536 477
537 switch (ep->type) 478 switch (ep->type)
538 { 479 {
539 case USB_ENDPOINT_XFER_CONTROL: 480 case USB_ENDPOINT_XFER_CONTROL:
540 ctr_write(); 481 ctr_write();
541 break; 482 break;
542 483
@@ -574,40 +515,30 @@ int usb_drv_recv(int endpoint, void* ptr, int length)
574 struct endpoint_t *ep; 515 struct endpoint_t *ep;
575 int ep_num = EP_NUM(endpoint); 516 int ep_num = EP_NUM(endpoint);
576 517
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
583 if (ep_num == 0) 518 if (ep_num == 0)
584 { 519 {
585 ep = &ctrlep[DIR_OUT]; 520 ep = &ctrlep[DIR_OUT];
586 ep->buf = ptr; 521
587 ep->len = ep->cnt = length; 522 ctr_read();
588
589 /* clear NAK bit */
590 RX0CON &= ~RXNAK;
591 RX0DMAOUTLMADDR = (uint32_t)ptr; /* buffer address */
592 RX0DMACTLO = DMA_START; /* start DMA */
593 } 523 }
594 else 524 else
595 { 525 {
596 ep = &endpoints[ep_num]; 526 ep = &endpoints[ep_num];
597 ep->buf = ptr; 527
598 ep->len = ep->cnt = length;
599
600 /* clear NAK bit */ 528 /* clear NAK bit */
601 BOUT_RXCON(ep_num) &= ~RXNAK; 529 BOUT_RXCON(ep_num) &= ~RXNAK;
602 BOUT_DMAOUTLMADDR(ep_num) = (uint32_t)ptr; 530 BOUT_DMAOUTLMADDR(ep_num) = (uint32_t)ptr;
603 BOUT_DMAOUTCTL(ep_num) = DMA_START; 531 BOUT_DMAOUTCTL(ep_num) = DMA_START;
604 } 532 }
533
534 ep->buf = ptr;
535 ep->len = ep->cnt = length;
605 536
606 return 0; 537 return 0;
607} 538}
608 539
609/* Kill all transfers. Usually you need to set a bit for each endpoint 540/* Kill all transfers. Usually you need to set a bit for each endpoint
610 * and flush fifos. You should also call the completion handler with 541 * and flush fifos. You should also call the completion handler with
611 * error status for everything 542 * error status for everything
612 */ 543 */
613void usb_drv_cancel_all_transfers(void) 544void usb_drv_cancel_all_transfers(void)
@@ -661,8 +592,6 @@ bool usb_drv_stalled(int endpoint, bool in)
661void usb_drv_stall(int endpoint, bool stall, bool in) 592void usb_drv_stall(int endpoint, bool stall, bool in)
662{ 593{
663 int ep_num = EP_NUM(endpoint); 594 int ep_num = EP_NUM(endpoint);
664 logf("usb_drv: %sstall EP%d %s",
665 stall ? "": "un", ep_num, in ? "IN" : "OUT");
666 595
667 switch (endpoints[ep_num].type) 596 switch (endpoints[ep_num].type)
668 { 597 {
@@ -716,23 +645,87 @@ void usb_drv_stall(int endpoint, bool stall, bool in)
716void usb_drv_init(void) 645void usb_drv_init(void)
717{ 646{
718 int ep_num; 647 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 */
719 693
720 /* init semaphore of ep0 */ 694 /* init semaphore of ep0 */
721 semaphore_init(&ctrlep[DIR_OUT].complete, 1, 0); 695 semaphore_init(&ctrlep[DIR_OUT].complete, 1, 0);
722 semaphore_init(&ctrlep[DIR_IN].complete, 1, 0); 696 semaphore_init(&ctrlep[DIR_IN].complete, 1, 0);
723 697
724 /* init semaphores for other endpoints */
725 for (ep_num = 1; ep_num < USB_NUM_ENDPOINTS; ep_num++) 698 for (ep_num = 1; ep_num < USB_NUM_ENDPOINTS; ep_num++)
699 {
726 semaphore_init(&endpoints[ep_num].complete, 1, 0); 700 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 }
727} 715}
728 716
729/* turn off usb core */ 717/* turn off usb core */
730void usb_drv_exit(void) 718void usb_drv_exit(void)
731{ 719{
732 /* udc module reset */ 720 DEV_CTL = DEV_SELF_PWR;
733 SCU_RSTCFG |= (1<<1); 721
734 udelay(10); 722 /* disable USB interrupts in interrupt controller */
735 SCU_RSTCFG &= ~(1<<1); 723 INTC_IMR &= ~IRQ_ARM_UDC;
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 */
736} 729}
737 730
738int usb_detect(void) 731int usb_detect(void)
@@ -743,140 +736,3 @@ int usb_detect(void)
743 return USB_EXTRACTED; 736 return USB_EXTRACTED;
744} 737}
745 738
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}