blob: 6a3e2aee088d7b88b8e552b7796e1636483d7a7d [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2 * Copyright (c) 2015 Brian Swetland
3 * Copyright (c) 2008 Google, Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files
7 * (the "Software"), to deal in the Software without restriction,
8 * including without limitation the rights to use, copy, modify, merge,
9 * publish, distribute, sublicense, and/or sell copies of the Software,
10 * and to permit persons to whom the Software is furnished to do so,
11 * subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25#include <string.h>
26#include <stdlib.h>
27#include <printf.h>
28#include <assert.h>
29#include <debug.h>
30#include <reg.h>
31#include <arch/arm/cm.h>
32#include <kernel/thread.h>
33#include <kernel/spinlock.h>
34
35#include <platform/lpc43xx-usb.h>
36static_assert(sizeof(usb_dqh_t) == 64);
37static_assert(sizeof(usb_dtd_t) == 32);
38
39#include <dev/udc.h>
40
41#include "udc-common.h"
42
43#define F_LL_INIT 1
44#define F_UDC_INIT 2
45
46// NOTE: I cheat a bit with the locking because this is a UP Cortex-M
47// NOTE: device. I use spinlocks for code that might be called from
48// NOTE: userspace or irq context, but for the irq-only code I don't
49// NOTE: bother with locking because it's impossible for it to execute
50// NOTE: while the lock is held from userspace.
51
52typedef struct {
53 u32 base;
54 spin_lock_t lock;
55
56 usb_dqh_t *qh;
57 usb_dtd_t *dtd_freelist;
58
59 udc_endpoint_t *ep0in;
60 udc_endpoint_t *ep0out;
61 udc_request_t *ep0req;
62 u8 txd[8];
63 u8 rxd[8];
64
65 udc_endpoint_t *ept_list;
66 uint8_t online;
67 uint8_t highspeed;
68 uint8_t config_value;
69 uint8_t flags;
70
71 udc_device_t *device;
72 udc_gadget_t *gadget;
73
74 uint32_t ept_alloc_table;
75} usb_t;
76
77static usb_t USB;
78
79typedef struct usb_request {
80 udc_request_t req;
81 struct usb_request *next;
82 usb_dtd_t *dtd;
83} usb_request_t;
84
85struct udc_endpoint {
86 udc_endpoint_t *next;
87 usb_dqh_t *head;
88 usb_request_t *req;
89 usb_request_t *last;
90 usb_t *usb;
91 uint32_t bit;
92 uint16_t maxpkt;
93 uint8_t num;
94 uint8_t in;
95};
96
97// ---- endpoint management
98
99#if 1
100#define DBG(x...) do {} while(0)
101#else
102#define DBG(x...) dprintf(INFO, x)
103#endif
104
105static udc_endpoint_t *_udc_endpoint_alloc(usb_t *usb,
106 unsigned num, unsigned in, unsigned max_pkt)
107{
108 udc_endpoint_t *ept;
109 unsigned cfg;
110
111 ept = malloc(sizeof(*ept));
112 ept->maxpkt = max_pkt;
113 ept->num = num;
114 ept->in = !!in;
115 ept->req = 0;
116 ept->last = 0;
117 ept->usb = usb;
118
119 cfg = DQH_CFG_MAXPKT(max_pkt) | DQH_CFG_ZLT;
120
121 if(ept->in) {
122 ept->bit = EPT_TX(ept->num);
123 } else {
124 ept->bit = EPT_RX(ept->num);
125 if(num == 0) {
126 cfg |= DQH_CFG_IOS;
127 }
128 }
129
130 ept->head = usb->qh + (num * 2) + (ept->in);
131 ept->head->config = cfg;
132 ept->next = usb->ept_list;
133 usb->ept_list = ept;
134
135 DBG("ept%d %s @%p/%p max=%d bit=%x\n",
136 num, in ? "in":"out", ept, ept->head, max_pkt, ept->bit);
137
138 return ept;
139}
140
141udc_endpoint_t *udc_endpoint_alloc(unsigned type, unsigned maxpkt)
142{
143 udc_endpoint_t *ept;
144 unsigned n;
145 unsigned in = !!(type & 0x80);
146
147 if (!(USB.flags & F_UDC_INIT)) {
148 panic("udc_init() must be called before udc_endpoint_alloc()\n");
149 }
150
151 for (n = 1; n < 6; n++) {
152 unsigned bit = in ? EPT_TX(n) : EPT_RX(n);
153 if (USB.ept_alloc_table & bit) {
154 continue;
155 }
156 if ((ept = _udc_endpoint_alloc(&USB, n, in, maxpkt))) {
157 USB.ept_alloc_table |= bit;
158 }
159 return ept;
160 }
161 return 0;
162}
163
164void udc_endpoint_free(struct udc_endpoint *ept)
165{
166 // todo
167}
168
169static void handle_ept_complete(struct udc_endpoint *ept);
170
171static void endpoint_flush(usb_t *usb, udc_endpoint_t *ept) {
172 if (ept->req) {
173 // flush outstanding transfers
174 writel(ept->bit, usb->base + USB_ENDPTFLUSH);
175 while (readl(usb->base + USB_ENDPTFLUSH)) ;
176 while (ept->req) {
177 handle_ept_complete(ept);
178 }
179 }
180}
181
182static void endpoint_reset(usb_t *usb, udc_endpoint_t *ept) {
183 unsigned n = readl(usb->base + USB_ENDPTCTRL(ept->num));
184 n |= ept->in ? EPCTRL_TXR : EPCTRL_RXR;
185 writel(n, usb->base + USB_ENDPTCTRL(ept->num));
186}
187
188static void endpoint_enable(usb_t *usb, udc_endpoint_t *ept, unsigned yes)
189{
190 unsigned n = readl(usb->base + USB_ENDPTCTRL(ept->num));
191
192 if(yes) {
193 if(ept->in) {
194 n |= (EPCTRL_TXE | EPCTRL_TXR | EPCTRL_TX_BULK);
195 } else {
196 n |= (EPCTRL_RXE | EPCTRL_RXR | EPCTRL_RX_BULK);
197 }
198
199 if(ept->num != 0) {
200 // todo: support non-max-sized packet sizes
201 if(usb->highspeed) {
202 ept->head->config = DQH_CFG_MAXPKT(512) | DQH_CFG_ZLT;
203 } else {
204 ept->head->config = DQH_CFG_MAXPKT(64) | DQH_CFG_ZLT;
205 }
206 }
207 }
208 writel(n, usb->base + USB_ENDPTCTRL(ept->num));
209}
210
211// ---- request management
212
213udc_request_t *udc_request_alloc(void)
214{
215 spin_lock_saved_state_t state;
216 usb_request_t *req;
217 if ((req = malloc(sizeof(*req))) == NULL) {
218 return NULL;
219 }
220
221 spin_lock_irqsave(&USB.lock, state);
222 if (USB.dtd_freelist == NULL) {
223 spin_unlock_irqrestore(&USB.lock, state);
224 free(req);
225 return NULL;
226 } else {
227 req->dtd = USB.dtd_freelist;
228 USB.dtd_freelist = req->dtd->next;
229 spin_unlock_irqrestore(&USB.lock, state);
230
231 req->req.buffer = 0;
232 req->req.length = 0;
233 return &req->req;
234 }
235}
236
237void udc_request_free(struct udc_request *req)
238{
239 // todo: check if active?
240 free(req);
241}
242
243int udc_request_queue(udc_endpoint_t *ept, struct udc_request *_req)
244{
245 spin_lock_saved_state_t state;
246 usb_request_t *req = (usb_request_t *) _req;
247 usb_dtd_t *dtd = req->dtd;
248 unsigned phys = (unsigned) req->req.buffer;
249 int ret = 0;
250
251 dtd->next_dtd = 1; // terminate bit
252 dtd->config = DTD_LEN(req->req.length) | DTD_IOC | DTD_ACTIVE;
253 dtd->bptr0 = phys;
254 phys &= 0xfffff000;
255 dtd->bptr1 = phys + 0x1000;
256 dtd->bptr2 = phys + 0x2000;
257 dtd->bptr3 = phys + 0x3000;
258 dtd->bptr4 = phys + 0x4000;
259
260 req->next = 0;
261 spin_lock_irqsave(&ept->usb->lock, state);
262 if (!USB.online && ept->num) {
263 ret = -1;
264 } else if (ept->req) {
265 // already a transfer in flight, add us to the list
266 // we'll get queue'd by the irq handler when it's our turn
267 ept->last->next = req;
268 } else {
269 ept->head->next_dtd = (unsigned) dtd;
270 ept->head->dtd_config = 0;
271 DSB;
272 writel(ept->bit, ept->usb->base + USB_ENDPTPRIME);
273 ept->req = req;
274 }
275 ept->last = req;
276 spin_unlock_irqrestore(&ept->usb->lock, state);
277
278 DBG("ept%d %s queue req=%p\n", ept->num, ept->in ? "in" : "out", req);
279 return ret;
280}
281
282static void handle_ept_complete(struct udc_endpoint *ept)
283{
284 usb_request_t *req;
285 usb_dtd_t *dtd;
286 unsigned actual;
287 int status;
288
289 DBG("ept%d %s complete req=%p\n",
290 ept->num, ept->in ? "in" : "out", ept->req);
291
292 if ((req = ept->req)) {
293 if (req->next) {
294 // queue next req to hw
295 ept->head->next_dtd = (unsigned) req->next->dtd;
296 ept->head->dtd_config = 0;
297 DSB;
298 writel(ept->bit, ept->usb->base + USB_ENDPTPRIME);
299 ept->req = req->next;
300 } else {
301 ept->req = 0;
302 ept->last = 0;
303 }
304 dtd = req->dtd;
305 if (dtd->config & 0xff) {
306 actual = 0;
307 status = -1;
308 dprintf(INFO, "EP%d/%s FAIL nfo=%x pg0=%x\n",
309 ept->num, ept->in ? "in" : "out", dtd->config, dtd->bptr0);
310 } else {
311 actual = req->req.length - ((dtd->config >> 16) & 0x7fff);
312 status = 0;
313 }
314 if(req->req.complete) {
315 req->req.complete(&req->req, actual, status);
316 }
317 }
318}
319
320static void setup_ack(usb_t *usb)
321{
322 usb->ep0req->complete = 0;
323 usb->ep0req->length = 0;
324 udc_request_queue(usb->ep0in, usb->ep0req);
325}
326
327static void ep0in_complete(struct udc_request *req, unsigned actual, int status)
328{
329 usb_t *usb = (usb_t*) req->context;
330 DBG("ep0in_complete %p %d %d\n", req, actual, status);
331 if(status == 0) {
332 req->length = 0;
333 req->complete = 0;
334 udc_request_queue(usb->ep0out, req);
335 }
336}
337
338static void setup_tx(usb_t *usb, void *buf, unsigned len)
339{
340 DBG("setup_tx %p %d\n", buf, len);
341 usb->ep0req->buffer = buf;
342 usb->ep0req->complete = ep0in_complete;
343 usb->ep0req->length = len;
344 udc_request_queue(usb->ep0in, usb->ep0req);
345}
346
347static void notify_gadgets(udc_gadget_t *gadget, unsigned event) {
348 while (gadget) {
349 if (gadget->notify) {
350 gadget->notify(gadget, event);
351 }
352 gadget = gadget->next;
353 }
354}
355
356#define SETUP(type,request) (((type) << 8) | (request))
357
358static void handle_setup(usb_t *usb)
359{
360 union setup_packet s;
361
362 // setup procedure, per databook
363 // a. clear setup status by writing and waiting for 0 (1-2uS)
364 writel(1, usb->base + USB_ENDPTSETUPSTAT);
365 while (readl(usb->base + USB_ENDPTSETUPSTAT) & 1) ;
366 do {
367 // b. write 1 to tripwire
368 writel(CMD_RUN | CMD_SUTW, usb->base + USB_CMD);
369 // c. extract setup data
370 s.w0 = usb->qh[0].setup0;
371 s.w1 = usb->qh[0].setup1;
372 // d. if tripwire clear, retry
373 } while ((readl(usb->base + USB_CMD) & CMD_SUTW) == 0);
374 // e. clear tripwire
375 writel(CMD_RUN, usb->base + USB_CMD);
376 // flush any pending io from previous setup transactions
377 usb->ep0in->req = 0;
378 usb->ep0out->req = 0;
379 // f. process packet
380 // g. ensure setup status is 0
381
382 DBG("setup 0x%02x 0x%02x %d %d %d\n",
383 s.type, s.request, s.value, s.index, s.length);
384
385 switch (SETUP(s.type,s.request)) {
386 case SETUP(DEVICE_READ, GET_STATUS): {
387 static unsigned zero = 0;
388 if (s.length == 2) {
389 setup_tx(usb, &zero, 2);
390 return;
391 }
392 break;
393 }
394 case SETUP(DEVICE_READ, GET_DESCRIPTOR): {
395 struct udc_descriptor *desc = udc_descriptor_find(s.value);
396 if (desc) {
397 unsigned len = desc->len;
398 if (len > s.length) len = s.length;
399 setup_tx(usb, desc->data, len);
400 return;
401 }
402 break;
403 }
404 case SETUP(DEVICE_READ, GET_CONFIGURATION):
405 if ((s.value == 0) && (s.index == 0) && (s.length == 1)) {
406 setup_tx(usb, &usb->config_value, 1);
407 return;
408 }
409 break;
410 case SETUP(DEVICE_WRITE, SET_CONFIGURATION):
411 if (s.value == 1) {
412 struct udc_endpoint *ept;
413 /* enable endpoints */
414 for (ept = usb->ept_list; ept; ept = ept->next){
415 if (ept->num != 0) {
416 endpoint_enable(usb, ept, 1);
417 }
418 }
419 usb->config_value = 1;
420 notify_gadgets(usb->gadget, UDC_EVENT_ONLINE);
421 } else {
422 writel(0, usb->base + USB_ENDPTCTRL(1));
423 usb->config_value = 0;
424 notify_gadgets(usb->gadget, UDC_EVENT_OFFLINE);
425 }
426 setup_ack(usb);
427 usb->online = s.value ? 1 : 0;
428 return;
429 case SETUP(DEVICE_WRITE, SET_ADDRESS):
430 // write address delayed (will take effect after the next IN txn)
431 writel(((s.value & 0x7F) << 25) | (1 << 24), usb->base + USB_DEVICEADDR);
432 setup_ack(usb);
433 return;
434 case SETUP(INTERFACE_WRITE, SET_INTERFACE):
435 goto stall;
436 case SETUP(ENDPOINT_WRITE, CLEAR_FEATURE): {
437 udc_endpoint_t *ept;
438 unsigned num = s.index & 15;
439 unsigned in = !!(s.index & 0x80);
440
441 if ((s.value != 0) || (s.length != 0)) {
442 break;
443 }
444 DBG("clr feat %d %d\n", num, in);
445 for (ept = usb->ept_list; ept; ept = ept->next) {
446 if ((ept->num == num) && (ept->in == in)) {
447 endpoint_flush(usb, ept);
448 // todo: if callback requeues this could be ugly...
449 endpoint_reset(usb, ept);
450 setup_ack(usb);
451 return;
452 }
453 }
454 break;
455 }
456 }
457
458 dprintf(INFO, "udc: stall %02x %02x %04x %04x %04x\n",
459 s.type, s.request, s.value, s.index, s.length);
460
461stall:
462 writel(EPCTRL_RXS | EPCTRL_TXS, usb->base + USB_ENDPTCTRL(0));
463}
464
465int lpc43xx_usb_init(u32 dmabase, size_t dmasize) {
466 usb_t *usb = &USB;
467 printf("usb_init()\n");
468 if ((dmabase & 0x7FF) || (dmasize < 1024)) {
469 return -1;
470 }
471 usb->qh = (void*) dmabase;
472 usb->dtd_freelist = NULL;
473 memset(usb->qh, 0, dmasize);
474 usb->base = USB0_BASE;
475 dmabase += 768;
476 dmasize -= 768;
477 while (dmasize > sizeof(usb_dtd_t)) {
478 usb_dtd_t *dtd = (void*) dmabase;
479 dtd->next = usb->dtd_freelist;
480 usb->dtd_freelist = dtd;
481 dmabase += sizeof(usb_dtd_t);
482 dmasize -= sizeof(usb_dtd_t);
483 }
484 writel(CMD_RST, usb->base + USB_CMD);
485 while (readl(usb->base + USB_CMD) & CMD_RST) ;
486 printf("usb_init(): reset ok\n");
487 thread_sleep(250);
488
489 // enable USB0 PHY via CREG0
490 writel(readl(0x40043004) & (~0x20), 0x40043004);
491
492 writel(MODE_DEVICE | MODE_SLOM, usb->base + USB_MODE);
493
494 // enable termination in OTG control (required for device mode)
495 writel(OTG_OT, usb->base + USB_OTGSC);
496
497 writel((u32) usb->qh, usb->base + USB_ENDPOINTLISTADDR);
498 usb->flags |= F_LL_INIT;
499 return 0;
500}
501
502static void usb_enable(usb_t *usb, int yes)
503{
504 if (yes) {
505 writel(INTR_UE | INTR_UEE | INTR_PCE | INTR_SEE | INTR_URE,
506 usb->base + USB_INTR);
507
508 writel(CMD_RUN, usb->base + USB_CMD);
509 NVIC_EnableIRQ(USB0_IRQn);
510 } else {
511 NVIC_DisableIRQ(USB0_IRQn);
512 writel(CMD_STOP, usb->base + USB_CMD);
513 }
514}
515
516
517void lpc43xx_USB0_IRQ(void)
518{
519 udc_endpoint_t *ept;
520 usb_t *usb = &USB;
521 int ret = 0;
522 unsigned n;
523
524 arm_cm_irq_entry();
525
526 n = readl(usb->base + USB_STS);
527 writel(n, usb->base + USB_STS);
528
529 if (n & STS_URI) {
530 // reset procedure, per databook
531 // 1. clear setup token semaphores
532 writel(readl(usb->base + USB_ENDPTSETUPSTAT),
533 usb->base + USB_ENDPTSETUPSTAT);
534 // 2. clear completion status bits
535 writel(readl(usb->base + USB_ENDPTCOMPLETE),
536 usb->base + USB_ENDPTCOMPLETE);
537 // 3. cancel primed transfers
538 while (readl(usb->base + USB_ENDPTPRIME)) ;
539 writel(0xFFFFFFFF, usb->base + USB_ENDPTFLUSH);
540 // 4. ensure we finished while reset still active
541 if (!(readl(usb->base + USB_PORTSC1) & PORTSC1_RC)) {
542 printf("usb: failed to reset in time\n");
543 }
544 // 5. free active DTDs
545 usb->online = 0;
546 usb->config_value = 0;
547 notify_gadgets(usb->gadget, UDC_EVENT_OFFLINE);
548 for (ept = usb->ept_list; ept; ept = ept->next) {
549 if (ept->req) {
550 ept->req->dtd->config = DTD_HALTED;
551 handle_ept_complete(ept);
552 }
553 }
554 }
555 if (n & STS_PCI) {
556 unsigned x = readl(usb->base + USB_PORTSC1);
557 usb->highspeed = (x & PORTSC1_HSP) ? 1 : 0;
558 }
559 if (n & (STS_UI | STS_UEI)) {
560 if(readl(usb->base + USB_ENDPTSETUPSTAT) & 1) {
561 handle_setup(usb);
562 }
563 n = readl(usb->base + USB_ENDPTCOMPLETE);
564 writel(n, usb->base + USB_ENDPTCOMPLETE);
565
566 for (ept = usb->ept_list; ept; ept = ept->next) {
567 if (n & ept->bit) {
568 handle_ept_complete(ept);
569 ret = INT_RESCHEDULE;
570 }
571 }
572 }
573 if (n & STS_SEI) {
574 panic("<SEI>");
575 }
576 arm_cm_irq_exit(ret);
577}
578
579// ---- UDC API
580
581int udc_init(struct udc_device *dev)
582{
583 USB.device = dev;
584 USB.ep0out = _udc_endpoint_alloc(&USB, 0, 0, 64);
585 USB.ep0in = _udc_endpoint_alloc(&USB, 0, 1, 64);
586 USB.ep0req = udc_request_alloc();
587 USB.ep0req->context = &USB;
588 USB.flags |= F_UDC_INIT;
589 return 0;
590}
591
592int udc_register_gadget(udc_gadget_t *gadget)
593{
594 if (USB.gadget) {
595 udc_gadget_t *last = USB.gadget;
596 while (last->next) {
597 last = last->next;
598 }
599 last->next = gadget;
600 } else {
601 USB.gadget = gadget;
602 }
603 gadget->next = NULL;
604 return 0;
605}
606
607void udc_ept_desc_fill(udc_endpoint_t *ept, unsigned char *data)
608{
609 data[0] = 7;
610 data[1] = TYPE_ENDPOINT;
611 data[2] = ept->num | (ept->in ? 0x80 : 0x00);
612 data[3] = 0x02; // bulk -- the only kind we support
613 data[4] = ept->maxpkt;
614 data[5] = ept->maxpkt >> 8;
615 data[6] = ept->in ? 0x00 : 0x01;
616}
617
618int udc_start(void)
619{
620 usb_t *usb = &USB;
621
622 dprintf(INFO, "udc_start()\n");
623 if (!(usb->flags & F_LL_INIT)) {
624 panic("udc cannot start before hw init\n");
625 }
626 if (!usb->device) {
627 panic("udc cannot start before init\n");
628 }
629 if (!usb->gadget) {
630 panic("udc has no gadget registered\n");
631 }
632 udc_create_descriptors(usb->device, usb->gadget);
633
634 usb_enable(usb, 1);
635 return 0;
636}
637
638int udc_stop(void)
639{
640 usb_enable(&USB, 0);
641 thread_sleep(10);
642 return 0;
643}
644