From patchwork Fri Sep 5 06:46:06 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Siva Durga Prasad Paladugu X-Patchwork-Id: 386159 X-Patchwork-Delegate: l.majewski@samsung.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id B7AF51400B9 for ; Fri, 5 Sep 2014 17:01:35 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 9C415A7717; Fri, 5 Sep 2014 09:01:33 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id D-UaN9FKbYkd; Fri, 5 Sep 2014 09:01:33 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 00752A73F3; Fri, 5 Sep 2014 09:01:31 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id F33EFA73F3 for ; Fri, 5 Sep 2014 09:01:24 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 7m3KS3dM-wTa for ; Fri, 5 Sep 2014 09:01:21 +0200 (CEST) X-Greylist: delayed 895 seconds by postgrey-1.27 at theia; Fri, 05 Sep 2014 09:01:16 CEST X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from na01-bn1-obe.outbound.protection.outlook.com (mail-bn1blp0182.outbound.protection.outlook.com [207.46.163.182]) by theia.denx.de (Postfix) with ESMTPS id 0FD7EA73EF for ; Fri, 5 Sep 2014 09:01:16 +0200 (CEST) Received: from BY2FFO11FD007.protection.gbl (10.1.14.34) by BY2FFO11HUB044.protection.gbl (10.1.15.225) with Microsoft SMTP Server (TLS) id 15.0.1010.11; Fri, 5 Sep 2014 06:46:18 +0000 Received: from xsj-pvapsmtpgw01 (149.199.60.83) by BY2FFO11FD007.mail.protection.outlook.com (10.1.14.128) with Microsoft SMTP Server (TLS) id 15.0.1010.11 via Frontend Transport; Fri, 5 Sep 2014 06:46:17 +0000 Received: from unknown-38-66.xilinx.com ([149.199.38.66] helo=xsj-smtp1) by xsj-pvapsmtpgw01 with esmtp (Exim 4.63) (envelope-from ) id 1XPnDU-0000wV-5Y for u-boot@lists.denx.de; Thu, 04 Sep 2014 23:41:52 -0700 From: Siva Durga Prasad Paladugu To: Date: Fri, 5 Sep 2014 12:16:06 +0530 X-Mailer: git-send-email 1.7.4 X-RCIS-Action: ALLOW X-TM-AS-Product-Ver: IMSS-7.1.0.1224-7.5.0.1018-20918.005 X-TM-AS-Result: No--10.868-5.0-31-1 X-imss-scan-details: No--10.868-5.0-31-1 Message-ID: X-EOPAttributedMessage: 0 X-Forefront-Antispam-Report: CIP:149.199.60.83; CTRY:US; IPV:NLI; EFV:NLI; SFV:NSPM; SFS:(6009001)(438002)(199003)(189002)(79102001)(64706001)(46102001)(77982001)(20776003)(47776003)(1496007)(77096002)(95666004)(76482001)(48376002)(107046002)(110136001)(106466001)(104016003)(74316001)(2351001)(229853001)(85306004)(50466002)(53416004)(102836001)(90102001)(104166001)(551934003)(80022001)(99396002)(74502001)(217423001)(31966008)(74662001)(21056001)(81542001)(70736001)(50226001)(88136002)(86362001)(4396001)(87936001)(93916002)(92726001)(31696002)(62966002)(83072002)(87286001)(89996001)(85852003)(50986999)(92566001)(19580405001)(44976005)(19580395003)(83322001)(6806004)(81342001)(77156001)(107986001)(23106004); DIR:OUT; SFP:; SCL:1; SRVR:BY2FFO11HUB044; H:xsj-pvapsmtpgw01; FPR:; MLV:sfv; PTR:unknown-60-83.xilinx.com; A:1; MX:1; LANG:en; MIME-Version: 1.0 X-Microsoft-Antispam: BCL:0;PCL:0;RULEID:;UriScan:; X-Forefront-PRVS: 0325F6C77B Received-SPF: Pass (protection.outlook.com: domain of xilinx.com designates 149.199.60.83 as permitted sender) receiver=protection.outlook.com; client-ip=149.199.60.83; helo=xsj-pvapsmtpgw01; Authentication-Results: spf=pass (sender IP is 149.199.60.83) smtp.mailfrom=siva.durga.paladugu@xilinx.com; X-OriginatorOrg: xilinx.com Cc: michals@xilinx.com, Siva Durga Prasad Paladugu Subject: [U-Boot] [UBOOT PATCH] ci_udc: Update the ci_udc driver to support bulk transfers X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de Update the ci_udc driver to support bulk transfer and also added capability of having multiple dtds if requested data is more thank 16K. These changes are tested for both the DFU and lthor. Signed-off-by: Siva Durga Prasad Paladugu Tested-by: Michal Simek --- drivers/usb/gadget/ci_udc.c | 135 +++++++++++++++++++++++++++++++++++++------ drivers/usb/gadget/ci_udc.h | 1 + 2 files changed, 117 insertions(+), 19 deletions(-) diff --git a/drivers/usb/gadget/ci_udc.c b/drivers/usb/gadget/ci_udc.c index 2572b34..d1d19dc 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 = (uint32_t)ci_req->hw_buf; - item->page1 = ((uint32_t)ci_req->hw_buf & 0xfffff000) + 0x1000; - item->page2 = ((uint32_t)ci_req->hw_buf & 0xfffff000) + 0x2000; - item->page3 = ((uint32_t)ci_req->hw_buf & 0xfffff000) + 0x3000; - item->page4 = ((uint32_t)ci_req->hw_buf & 0xfffff000) + 0x4000; - head->next = (unsigned) 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 = (uint32_t)buf; + dtd->page1 = ((uint32_t)buf & 0xfffff000) + 0x1000; + dtd->page2 = ((uint32_t)buf & 0xfffff000) + 0x2000; + dtd->page3 = ((uint32_t)buf & 0xfffff000) + 0x3000; + dtd->page4 = ((uint32_t)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; @@ -847,9 +934,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 {