From 126ca9427417df12b492e938418ee7b5f096a757 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 19 Apr 2015 11:33:21 +0200 Subject: usb: Remove unused variable in usb_setup_descriptor() The compiler did not catch this as it was marked __maybe_unused. Signed-off-by: Hans de Goede diff --git a/common/usb.c b/common/usb.c index 6283f39..7ff8ac5 100644 --- a/common/usb.c +++ b/common/usb.c @@ -959,8 +959,6 @@ static int get_descriptor_len(struct usb_device *dev, int len, int expect_len) static int usb_setup_descriptor(struct usb_device *dev, bool do_read) { - __maybe_unused struct usb_device_descriptor *desc; - /* * This is a Windows scheme of initialization sequence, with double * reset of the device (Linux uses the same sequence) -- cgit v0.10.2 From 6a132416359e36ed77b1319674d7ccb9c1a82694 Mon Sep 17 00:00:00 2001 From: Siva Durga Prasad Paladugu Date: Wed, 29 Apr 2015 10:42:10 +0530 Subject: ci_udc: Update the ci_udc driver to support bulk transfers Update the ci_udc driver to support bulk transfer and also added capability of having multiple dtds if requested data is more than 16K. These changes are tested for both the DFU and lthor. Signed-off-by: Siva Durga Prasad Paladugu diff --git a/drivers/usb/gadget/ci_udc.c b/drivers/usb/gadget/ci_udc.c index 22d288c..aadff42 100644 --- a/drivers/usb/gadget/ci_udc.c +++ b/drivers/usb/gadget/ci_udc.c @@ -50,6 +50,8 @@ /* For each endpoint, we need 2 QTDs, one for each of IN and OUT */ #define ILIST_SZ (NUM_ENDPOINTS * 2 * ILIST_ENT_SZ) +#define EP_MAX_LENGTH_TRANSFER 0x4000 + #ifndef DEBUG #define DBG(x...) do {} while (0) #else @@ -102,13 +104,28 @@ static struct usb_ep_ops ci_ep_ops = { }; /* Init values for USB endpoints. */ -static const struct usb_ep ci_ep_init[2] = { +static const struct usb_ep ci_ep_init[5] = { [0] = { /* EP 0 */ .maxpacket = 64, .name = "ep0", .ops = &ci_ep_ops, }, - [1] = { /* EP 1..n */ + [1] = { + .maxpacket = 512, + .name = "ep1in-bulk", + .ops = &ci_ep_ops, + }, + [2] = { + .maxpacket = 512, + .name = "ep2out-bulk", + .ops = &ci_ep_ops, + }, + [3] = { + .maxpacket = 512, + .name = "ep3in-int", + .ops = &ci_ep_ops, + }, + [4] = { .maxpacket = 512, .name = "ep-", .ops = &ci_ep_ops, @@ -197,6 +214,19 @@ static void ci_flush_qtd(int ep_num) } /** + * ci_flush_td - flush cache over queue item + * @td: td pointer + * + * This function flushes cache for particular transfer descriptor. + */ +static void ci_flush_td(struct ept_queue_item *td) +{ + const uint32_t start = (uint32_t)td; + const uint32_t end = (uint32_t) td + ILIST_ENT_SZ; + flush_dcache_range(start, end); +} + +/** * ci_invalidate_qtd - invalidate cache over queue item * @ep_num: Endpoint number * @@ -211,6 +241,19 @@ static void ci_invalidate_qtd(int ep_num) invalidate_dcache_range(start, end); } +/** + * ci_invalidate_td - invalidate cache over queue item + * @td: td pointer + * + * This function invalidates cache for particular transfer descriptor. + */ +static void ci_invalidate_td(struct ept_queue_item *td) +{ + const uint32_t start = (uint32_t)td; + const uint32_t end = start + ILIST_ENT_SZ; + invalidate_dcache_range(start, end); +} + static struct usb_request * ci_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags) { @@ -376,6 +419,9 @@ static void ci_ep_submit_next_request(struct ci_ep *ci_ep) struct ept_queue_head *head; int bit, num, len, in; struct ci_req *ci_req; + u8 *buf; + uint32_t length, actlen; + struct ept_queue_item *dtd, *qtd; ci_ep->req_primed = true; @@ -387,16 +433,41 @@ static void ci_ep_submit_next_request(struct ci_ep *ci_ep) ci_req = list_first_entry(&ci_ep->queue, struct ci_req, queue); len = ci_req->req.length; - item->info = INFO_BYTES(len) | INFO_ACTIVE; - item->page0 = (unsigned long)ci_req->hw_buf; - item->page1 = ((unsigned long)ci_req->hw_buf & 0xfffff000) + 0x1000; - item->page2 = ((unsigned long)ci_req->hw_buf & 0xfffff000) + 0x2000; - item->page3 = ((unsigned long)ci_req->hw_buf & 0xfffff000) + 0x3000; - item->page4 = ((unsigned long)ci_req->hw_buf & 0xfffff000) + 0x4000; - head->next = (unsigned long)item; head->info = 0; + ci_req->dtd_count = 0; + buf = ci_req->hw_buf; + actlen = 0; + dtd = item; + + do { + length = min(ci_req->req.length - actlen, + (unsigned)EP_MAX_LENGTH_TRANSFER); + + dtd->info = INFO_BYTES(length) | INFO_ACTIVE; + dtd->page0 = (unsigned long)buf; + dtd->page1 = ((unsigned long)buf & 0xfffff000) + 0x1000; + dtd->page2 = ((unsigned long)buf & 0xfffff000) + 0x2000; + dtd->page3 = ((unsigned long)buf & 0xfffff000) + 0x3000; + dtd->page4 = ((unsigned long)buf & 0xfffff000) + 0x4000; + + len -= length; + actlen += length; + buf += length; + + if (len) { + qtd = (struct ept_queue_item *) + memalign(ILIST_ALIGN, ILIST_ENT_SZ); + dtd->next = (uint32_t)qtd; + dtd = qtd; + memset(dtd, 0, ILIST_ENT_SZ); + } + + ci_req->dtd_count++; + } while (len); + + item = dtd; /* * When sending the data for an IN transaction, the attached host * knows that all data for the IN is sent when one of the following @@ -432,6 +503,12 @@ static void ci_ep_submit_next_request(struct ci_ep *ci_ep) ci_flush_qtd(num); + item = (struct ept_queue_item *)head->next; + while (item->next != TERMINATE) { + ci_flush_td((struct ept_queue_item *)item->next); + item = (struct ept_queue_item *)item->next; + } + DBG("ept%d %s queue len %x, req %p, buffer %p\n", num, in ? "in" : "out", len, ci_req, ci_req->hw_buf); ci_flush_qh(num); @@ -497,21 +574,31 @@ static void flip_ep0_direction(void) static void handle_ep_complete(struct ci_ep *ci_ep) { - struct ept_queue_item *item; - int num, in, len; + struct ept_queue_item *item, *next_td; + int num, in, len, j; struct ci_req *ci_req; num = ci_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; in = (ci_ep->desc->bEndpointAddress & USB_DIR_IN) != 0; item = ci_get_qtd(num, in); ci_invalidate_qtd(num); + ci_req = list_first_entry(&ci_ep->queue, struct ci_req, queue); - len = (item->info >> 16) & 0x7fff; - if (item->info & 0xff) - printf("EP%d/%s FAIL info=%x pg0=%x\n", - num, in ? "in" : "out", item->info, item->page0); + next_td = item; + len = 0; + for (j = 0; j < ci_req->dtd_count; j++) { + ci_invalidate_td(next_td); + item = next_td; + len += (item->info >> 16) & 0x7fff; + if (item->info & 0xff) + printf("EP%d/%s FAIL info=%x pg0=%x\n", + num, in ? "in" : "out", item->info, item->page0); + if (j != ci_req->dtd_count - 1) + next_td = (struct ept_queue_item *)item->next; + if (j != 0) + free(item); + } - ci_req = list_first_entry(&ci_ep->queue, struct ci_req, queue); list_del_init(&ci_req->queue); ci_ep->req_primed = false; @@ -852,9 +939,19 @@ static int ci_udc_probe(void) controller.gadget.ep0 = &controller.ep[0].ep; INIT_LIST_HEAD(&controller.gadget.ep0->ep_list); - /* Init EP 1..n */ - for (i = 1; i < NUM_ENDPOINTS; i++) { - memcpy(&controller.ep[i].ep, &ci_ep_init[1], + /* Init EP 1..3 */ + for (i = 1; i < 4; i++) { + memcpy(&controller.ep[i].ep, &ci_ep_init[i], + sizeof(*ci_ep_init)); + INIT_LIST_HEAD(&controller.ep[i].queue); + controller.ep[i].req_primed = false; + list_add_tail(&controller.ep[i].ep.ep_list, + &controller.gadget.ep_list); + } + + /* Init EP 4..n */ + for (i = 4; i < NUM_ENDPOINTS; i++) { + memcpy(&controller.ep[i].ep, &ci_ep_init[4], sizeof(*ci_ep_init)); INIT_LIST_HEAD(&controller.ep[i].queue); controller.ep[i].req_primed = false; diff --git a/drivers/usb/gadget/ci_udc.h b/drivers/usb/gadget/ci_udc.h index 346164a..95cc079 100644 --- a/drivers/usb/gadget/ci_udc.h +++ b/drivers/usb/gadget/ci_udc.h @@ -86,6 +86,7 @@ struct ci_req { /* Buffer for the current transfer. Either req.buf/len or b_buf/len */ uint8_t *hw_buf; uint32_t hw_len; + uint32_t dtd_count; }; struct ci_ep { -- cgit v0.10.2 From 5cfd6c002aa962d102953936a77cc170bb6e5265 Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Tue, 12 May 2015 14:38:27 +0100 Subject: usb: dwc2: Add support for v3 snpsid value This has been tested to the extent that I can enumerate a asix usb networking adapter and boot a kernel over usb on the 96boards hikey u-boot port I'm currently doing. Signed-off-by: Peter Griffin diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c index 2ac0017..eee60a2 100644 --- a/drivers/usb/host/dwc2.c +++ b/drivers/usb/host/dwc2.c @@ -932,7 +932,8 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller) snpsid = readl(®s->gsnpsid); printf("Core Release: %x.%03x\n", snpsid >> 12 & 0xf, snpsid & 0xfff); - if ((snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_2xx) { + if ((snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_2xx && + (snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_3xx) { printf("SNPSID invalid (not DWC2 OTG device): %08x\n", snpsid); return -ENODEV; } diff --git a/drivers/usb/host/dwc2.h b/drivers/usb/host/dwc2.h index 45408c6..f69372e 100644 --- a/drivers/usb/host/dwc2.h +++ b/drivers/usb/host/dwc2.h @@ -732,6 +732,7 @@ struct dwc2_core_regs { #define DWC2_PCGCCTL_DEEP_SLEEP (1 << 7) #define DWC2_PCGCCTL_DEEP_SLEEP_OFFSET 7 #define DWC2_SNPSID_DEVID_VER_2xx (0x4f542 << 12) +#define DWC2_SNPSID_DEVID_VER_3xx (0x4f543 << 12) #define DWC2_SNPSID_DEVID_MASK (0xfffff << 12) #define DWC2_SNPSID_DEVID_OFFSET 12 -- cgit v0.10.2 From 8454c84af5401f8c3bcd0ed2625043270d0ef6aa Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 19 May 2015 22:51:03 +0200 Subject: usb: kbd: Fix key repeat not always working The usb-kbd key repeat code assumes that reports get repeated every 40 ms, this is never true when using CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP, and does not always works for CONFIG_SYS_USB_EVENT_POLL and CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE since not all usb keyboards honor the usb_set_idle() command. For CONFIG_SYS_USB_EVENT_POLL we must use usb_set_idle() since we do a blocking wait for the hid report, so if we do not tell the keyboard to send a hid report every 40ms even if nothing changes then we will block u-boot for 1s (the default u-boot usb interrupt packet timeout). Note that in this case on keyboards which do not support usb_set_idle() we loose and we actually get 1s latencies on other u-boot activities. For the other poll-methods this commit stops using usb_set_idle() and instead repeats the last received hid-report every 40 ms as long as no new hid-report is received. This fixes key-repeat not working at all with CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP and fixes it not working with keyboards which do not implement usb_set_idle() when using CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE. Signed-off-by: Hans de Goede diff --git a/common/usb_kbd.c b/common/usb_kbd.c index 24a1a56..49bfc09 100644 --- a/common/usb_kbd.c +++ b/common/usb_kbd.c @@ -31,7 +31,7 @@ int overwrite_console(void) #endif /* Keyboard sampling rate */ -#define REPEAT_RATE (40 / 4) /* 40msec -> 25cps */ +#define REPEAT_RATE 40 /* 40msec -> 25cps */ #define REPEAT_DELAY 10 /* 10 x REPEAT_RATE = 400msec */ #define NUM_LOCK 0x53 @@ -103,6 +103,7 @@ struct usb_kbd_pdata { unsigned long intpipe; int intpktsize; int intinterval; + unsigned long last_report; struct int_queue *intq; uint32_t repeat_delay; @@ -310,7 +311,7 @@ static int usb_kbd_irq(struct usb_device *dev) /* Interrupt polling */ static inline void usb_kbd_poll_for_event(struct usb_device *dev) { -#if defined(CONFIG_SYS_USB_EVENT_POLL) +#if defined(CONFIG_SYS_USB_EVENT_POLL) struct usb_kbd_pdata *data = dev->privptr; /* Submit a interrupt transfer request */ @@ -318,15 +319,17 @@ static inline void usb_kbd_poll_for_event(struct usb_device *dev) data->intinterval); usb_kbd_irq_worker(dev); -#elif defined(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP) +#elif defined(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP) || \ + defined(CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE) +#if defined(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP) struct usb_interface *iface; struct usb_kbd_pdata *data = dev->privptr; iface = &dev->config.if_desc[0]; usb_get_report(dev, iface->desc.bInterfaceNumber, 1, 0, data->new, USB_KBD_BOOT_REPORT_SIZE); - if (memcmp(data->old, data->new, USB_KBD_BOOT_REPORT_SIZE)) + if (memcmp(data->old, data->new, USB_KBD_BOOT_REPORT_SIZE)) { usb_kbd_irq_worker(dev); -#elif defined(CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE) +#else struct usb_kbd_pdata *data = dev->privptr; if (poll_int_queue(dev, data->intq)) { usb_kbd_irq_worker(dev); @@ -335,6 +338,13 @@ static inline void usb_kbd_poll_for_event(struct usb_device *dev) data->intq = create_int_queue(dev, data->intpipe, 1, USB_KBD_BOOT_REPORT_SIZE, data->new, data->intinterval); +#endif + data->last_report = get_timer(0); + /* Repeat last usb hid report every REPEAT_RATE ms for keyrepeat */ + } else if (data->last_report != -1 && + get_timer(data->last_report) > REPEAT_RATE) { + usb_kbd_irq_worker(dev); + data->last_report = get_timer(0); } #endif } @@ -445,12 +455,16 @@ static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum) data->intpktsize = min(usb_maxpacket(dev, data->intpipe), USB_KBD_BOOT_REPORT_SIZE); data->intinterval = ep->bInterval; + data->last_report = -1; /* We found a USB Keyboard, install it. */ usb_set_protocol(dev, iface->desc.bInterfaceNumber, 0); +#if !defined(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP) && \ + !defined(CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE) debug("USB KBD: found set idle...\n"); - usb_set_idle(dev, iface->desc.bInterfaceNumber, REPEAT_RATE, 0); + usb_set_idle(dev, iface->desc.bInterfaceNumber, REPEAT_RATE / 4, 0); +#endif debug("USB KBD: enable interrupt pipe...\n"); #ifdef CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE -- cgit v0.10.2