blob: c9ae3b29c88df541270ec76784c1fdda133ae7b6 [file] [log] [blame]
Brian Swetland3e7e21a2009-01-19 19:41:24 -08001/*
2 * Copyright (c) 2008, Google Inc.
3 * All rights reserved.
4 *
vijay kumar9c9f1cf2014-01-15 16:05:28 +05305 * Copyright (c) 2009-2014, The Linux Foundation. All rights reserved.
Shashank Mittal23b8f422010-04-16 19:27:21 -07006 *
Brian Swetland3e7e21a2009-01-19 19:41:24 -08007 * Redistribution and use in source and binary forms, with or without
Deepa Dinamani0bf2f442012-10-19 11:41:06 -07008 * modification, are permitted provided that the following conditions are
9 * met:
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials provided
15 * with the distribution.
16 * * Neither the name of The Linux Foundation nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
Brian Swetland3e7e21a2009-01-19 19:41:24 -080019 *
Deepa Dinamani0bf2f442012-10-19 11:41:06 -070020 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
21 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
30 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Brian Swetland3e7e21a2009-01-19 19:41:24 -080031 */
32
33#include <string.h>
34#include <stdlib.h>
35#include <debug.h>
Deepa Dinamani0bf2f442012-10-19 11:41:06 -070036#include <platform.h>
Brian Swetland3e7e21a2009-01-19 19:41:24 -080037#include <platform/iomap.h>
38#include <platform/irqs.h>
39#include <platform/interrupts.h>
Greg Griscod2471ef2011-07-14 13:00:42 -070040#include <platform/timer.h>
Brian Swetland3e7e21a2009-01-19 19:41:24 -080041#include <kernel/thread.h>
42#include <reg.h>
Brian Swetland3e7e21a2009-01-19 19:41:24 -080043#include <dev/udc.h>
Brian Swetland3e7e21a2009-01-19 19:41:24 -080044#include "hsusb.h"
45
Hanumant Singh5322c742012-12-12 15:40:09 -080046#define MAX_TD_XFER_SIZE (16 * 1024)
47
48
Brian Swetland3e7e21a2009-01-19 19:41:24 -080049/* common code - factor out into a shared file */
50
51struct udc_descriptor {
52 struct udc_descriptor *next;
Ajay Dudanib01e5062011-12-03 23:23:42 -080053 unsigned short tag; /* ((TYPE << 8) | NUM) */
54 unsigned short len; /* total length */
Brian Swetland3e7e21a2009-01-19 19:41:24 -080055 unsigned char data[0];
56};
57
Ajay Dudanib01e5062011-12-03 23:23:42 -080058struct udc_descriptor *udc_descriptor_alloc(unsigned type, unsigned num,
59 unsigned len)
Brian Swetland3e7e21a2009-01-19 19:41:24 -080060{
61 struct udc_descriptor *desc;
62 if ((len > 255) || (len < 2) || (num > 255) || (type > 255))
63 return 0;
64
Ajay Dudanib01e5062011-12-03 23:23:42 -080065 if (!(desc = malloc(sizeof(struct udc_descriptor) + len)))
Brian Swetland3e7e21a2009-01-19 19:41:24 -080066 return 0;
67
68 desc->next = 0;
69 desc->tag = (type << 8) | num;
70 desc->len = len;
71 desc->data[0] = len;
72 desc->data[1] = type;
73
74 return desc;
75}
76
77static struct udc_descriptor *desc_list = 0;
78static unsigned next_string_id = 1;
79
80void udc_descriptor_register(struct udc_descriptor *desc)
81{
82 desc->next = desc_list;
83 desc_list = desc;
84}
85
86unsigned udc_string_desc_alloc(const char *str)
87{
88 unsigned len;
89 struct udc_descriptor *desc;
90 unsigned char *data;
91
92 if (next_string_id > 255)
93 return 0;
94
95 if (!str)
96 return 0;
97
98 len = strlen(str);
99 desc = udc_descriptor_alloc(TYPE_STRING, next_string_id, len * 2 + 2);
100 if (!desc)
101 return 0;
102 next_string_id++;
103
104 /* expand ascii string to utf16 */
105 data = desc->data + 2;
106 while (len-- > 0) {
107 *data++ = *str++;
108 *data++ = 0;
109 }
110
111 udc_descriptor_register(desc);
112 return desc->tag & 0xff;
113}
114
115/* end of common code */
116
Ajay Dudani7d605522010-10-01 19:52:37 -0700117__WEAK void hsusb_clock_init(void)
118{
Greg Griscod6250552011-06-29 14:40:23 -0700119 return;
Ajay Dudani7d605522010-10-01 19:52:37 -0700120}
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800121
122#if 1
123#define DBG(x...) do {} while(0)
124#else
Amol Jadida118b92012-07-06 19:53:18 -0700125#define DBG(x...) dprintf(ALWAYS, x)
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800126#endif
127
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800128#define usb_status(a,b)
129
130struct usb_request {
131 struct udc_request req;
132 struct ept_queue_item *item;
133};
Amol Jadi4421e652011-06-16 15:00:48 -0700134
Ajay Dudanib01e5062011-12-03 23:23:42 -0800135struct udc_endpoint {
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800136 struct udc_endpoint *next;
137 unsigned bit;
138 struct ept_queue_head *head;
139 struct usb_request *req;
140 unsigned char num;
141 unsigned char in;
142 unsigned short maxpkt;
143};
144
145struct udc_endpoint *ept_list = 0;
146struct ept_queue_head *epts = 0;
147
148static int usb_online = 0;
149static int usb_highspeed = 0;
150
151static struct udc_device *the_device;
152static struct udc_gadget *the_gadget;
Shashank Mittal2523e0b2011-10-14 17:32:46 -0700153static unsigned test_mode = 0;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800154
Ajay Dudanib01e5062011-12-03 23:23:42 -0800155struct udc_endpoint *_udc_endpoint_alloc(unsigned num, unsigned in,
156 unsigned max_pkt)
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800157{
158 struct udc_endpoint *ept;
159 unsigned cfg;
160
Hanumant Singh9d519092012-12-06 21:59:52 -0800161 ept = memalign(CACHE_LINE, ROUNDUP(sizeof(*ept), CACHE_LINE));
Amol Jadi4421e652011-06-16 15:00:48 -0700162
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800163 ept->maxpkt = max_pkt;
164 ept->num = num;
165 ept->in = !!in;
166 ept->req = 0;
167
168 cfg = CONFIG_MAX_PKT(max_pkt) | CONFIG_ZLT;
169
Ajay Dudanib01e5062011-12-03 23:23:42 -0800170 if (ept->in) {
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800171 ept->bit = EPT_TX(ept->num);
172 } else {
173 ept->bit = EPT_RX(ept->num);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800174 if (num == 0)
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800175 cfg |= CONFIG_IOS;
176 }
177
178 ept->head = epts + (num * 2) + (ept->in);
179 ept->head->config = cfg;
180
181 ept->next = ept_list;
182 ept_list = ept;
Amol Jadi4421e652011-06-16 15:00:48 -0700183
184 DBG("ept%d %s @%p/%p max=%d bit=%x\n",
Ajay Dudanib01e5062011-12-03 23:23:42 -0800185 num, in ? "in" : "out", ept, ept->head, max_pkt, ept->bit);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800186
187 return ept;
188}
189
190static unsigned ept_alloc_table = EPT_TX(0) | EPT_RX(0);
191
192struct udc_endpoint *udc_endpoint_alloc(unsigned type, unsigned maxpkt)
193{
194 struct udc_endpoint *ept;
195 unsigned n;
196 unsigned in;
197
198 if (type == UDC_TYPE_BULK_IN) {
199 in = 1;
200 } else if (type == UDC_TYPE_BULK_OUT) {
201 in = 0;
202 } else {
203 return 0;
204 }
205
206 for (n = 1; n < 16; n++) {
207 unsigned bit = in ? EPT_TX(n) : EPT_RX(n);
208 if (ept_alloc_table & bit)
209 continue;
210 ept = _udc_endpoint_alloc(n, in, maxpkt);
211 if (ept)
212 ept_alloc_table |= bit;
213 return ept;
214 }
215 return 0;
216}
217
218void udc_endpoint_free(struct udc_endpoint *ept)
219{
220 /* todo */
221}
222
223static void endpoint_enable(struct udc_endpoint *ept, unsigned yes)
224{
225 unsigned n = readl(USB_ENDPTCTRL(ept->num));
226
Ajay Dudanib01e5062011-12-03 23:23:42 -0800227 if (yes) {
228 if (ept->in) {
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800229 n |= (CTRL_TXE | CTRL_TXR | CTRL_TXT_BULK);
230 } else {
231 n |= (CTRL_RXE | CTRL_RXR | CTRL_RXT_BULK);
232 }
233
Ajay Dudanib01e5062011-12-03 23:23:42 -0800234 if (ept->num != 0) {
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800235 /* XXX should be more dynamic... */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800236 if (usb_highspeed) {
237 ept->head->config =
238 CONFIG_MAX_PKT(512) | CONFIG_ZLT;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800239 } else {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800240 ept->head->config =
241 CONFIG_MAX_PKT(64) | CONFIG_ZLT;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800242 }
243 }
244 }
245 writel(n, USB_ENDPTCTRL(ept->num));
246}
247
248struct udc_request *udc_request_alloc(void)
249{
250 struct usb_request *req;
Hanumant Singh9d519092012-12-06 21:59:52 -0800251 req = memalign(CACHE_LINE, ROUNDUP(sizeof(*req), CACHE_LINE));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800252 req->req.buf = 0;
253 req->req.length = 0;
Hanumant Singh9d519092012-12-06 21:59:52 -0800254 req->item = memalign(CACHE_LINE, ROUNDUP(sizeof(struct ept_queue_item),
255 CACHE_LINE));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800256 return &req->req;
257}
258
259void udc_request_free(struct udc_request *req)
260{
261 free(req);
262}
263
Hanumant Singh5322c742012-12-12 15:40:09 -0800264/*
265 * Assumes that TDs allocated already are not freed.
266 * But it can handle case where TDs are freed as well.
267 */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800268int udc_request_queue(struct udc_endpoint *ept, struct udc_request *_req)
269{
Hanumant Singh5322c742012-12-12 15:40:09 -0800270 unsigned xfer = 0;
271 struct ept_queue_item *item, *curr_item;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800272 struct usb_request *req = (struct usb_request *)_req;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800273 unsigned phys = (unsigned)req->req.buf;
Hanumant Singh5322c742012-12-12 15:40:09 -0800274 unsigned len = req->req.length;
275 unsigned int count = 0;
Amol Jadi4421e652011-06-16 15:00:48 -0700276
Hanumant Singh5322c742012-12-12 15:40:09 -0800277 curr_item = NULL;
278 xfer = (len > MAX_TD_XFER_SIZE) ? MAX_TD_XFER_SIZE : len;
279 /*
280 * First TD allocated during request allocation
281 */
282 item = req->item;
283 item->info = INFO_BYTES(xfer) | INFO_ACTIVE;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800284 item->page0 = phys;
285 item->page1 = (phys & 0xfffff000) + 0x1000;
Shashank Mittal1cc65b02011-12-20 15:30:17 -0800286 item->page2 = (phys & 0xfffff000) + 0x2000;
287 item->page3 = (phys & 0xfffff000) + 0x3000;
288 item->page4 = (phys & 0xfffff000) + 0x4000;
Hanumant Singh5322c742012-12-12 15:40:09 -0800289 phys += xfer;
290 curr_item = item;
291 len -= xfer;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800292
Hanumant Singh5322c742012-12-12 15:40:09 -0800293 /*
294 * If transfer length is more then
295 * accomodate by 1 TD
296 * we add more transfer descriptors
297 */
298 while (len > 0) {
299 xfer = (len > MAX_TD_XFER_SIZE) ? MAX_TD_XFER_SIZE : len;
300 if (curr_item->next == TERMINATE) {
301 /*
302 * Allocate new TD only if chain doesnot
303 * exist already
304 */
305 item = memalign(CACHE_LINE,
306 ROUNDUP(sizeof(struct ept_queue_item), CACHE_LINE));
307 if (!item) {
308 dprintf(ALWAYS, "allocate USB item fail ept%d"
309 "%s queue\n",
310 "td count = %d\n",
311 ept->num,
312 ept->in ? "in" : "out",
313 count);
314 return -1;
315 } else {
316 count ++;
317 curr_item->next = PA(item);
318 item->next = TERMINATE;
319 }
320 } else
321 /* Since next TD in chain already exists */
322 item = VA(curr_item->next);
323
324 /* Update TD with transfer information */
325 item->info = INFO_BYTES(xfer) | INFO_ACTIVE;
326 item->page0 = phys;
327 item->page1 = (phys & 0xfffff000) + 0x1000;
328 item->page2 = (phys & 0xfffff000) + 0x2000;
329 item->page3 = (phys & 0xfffff000) + 0x3000;
330 item->page4 = (phys & 0xfffff000) + 0x4000;
331
332 curr_item = item;
333 len -= xfer;
334 phys += xfer;
335 }
336
337 /* Terminate and set interrupt for last TD */
338 curr_item->next = TERMINATE;
339 curr_item->info |= INFO_IOC;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800340 enter_critical_section();
Hanumant Singh5322c742012-12-12 15:40:09 -0800341 ept->head->next = PA(req->item);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800342 ept->head->info = 0;
343 ept->req = req;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800344 arch_clean_invalidate_cache_range((addr_t) ept,
345 sizeof(struct udc_endpoint));
346 arch_clean_invalidate_cache_range((addr_t) ept->head,
347 sizeof(struct ept_queue_head));
348 arch_clean_invalidate_cache_range((addr_t) ept->req,
349 sizeof(struct usb_request));
Deepa Dinamani0bf2f442012-10-19 11:41:06 -0700350 arch_clean_invalidate_cache_range((addr_t) VA(req->req.buf),
Ajay Dudanib01e5062011-12-03 23:23:42 -0800351 req->req.length);
Hanumant Singh5322c742012-12-12 15:40:09 -0800352
353 item = req->item;
354 /* Write all TD's to memory from cache */
355 while (item != NULL) {
356 curr_item = item;
357 if (curr_item->next == TERMINATE)
358 item = NULL;
359 else
360 item = curr_item->next;
361 arch_clean_invalidate_cache_range((addr_t) curr_item,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800362 sizeof(struct ept_queue_item));
Hanumant Singh5322c742012-12-12 15:40:09 -0800363 }
Amol Jadi4421e652011-06-16 15:00:48 -0700364
Ajay Dudanib01e5062011-12-03 23:23:42 -0800365 DBG("ept%d %s queue req=%p\n", ept->num, ept->in ? "in" : "out", req);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800366 writel(ept->bit, USB_ENDPTPRIME);
367 exit_critical_section();
368 return 0;
369}
370
371static void handle_ept_complete(struct udc_endpoint *ept)
372{
373 struct ept_queue_item *item;
Hanumant Singh5322c742012-12-12 15:40:09 -0800374 unsigned actual, total_len;
375 int status, len;
Sundarajan Srinivasanafc69282013-11-19 14:07:03 -0800376 struct usb_request *req=NULL;
Hanumant Singh5322c742012-12-12 15:40:09 -0800377 void *buf;
Amol Jadi4421e652011-06-16 15:00:48 -0700378
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800379 DBG("ept%d %s complete req=%p\n",
Ajay Dudanib01e5062011-12-03 23:23:42 -0800380 ept->num, ept->in ? "in" : "out", ept->req);
Amol Jadi4421e652011-06-16 15:00:48 -0700381
Hanumant Singh5322c742012-12-12 15:40:09 -0800382 arch_invalidate_cache_range((addr_t) ept,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800383 sizeof(struct udc_endpoint));
Sundarajan Srinivasanafc69282013-11-19 14:07:03 -0800384
385 if(ept->req)
386 {
387 req = VA(ept->req);
388 arch_invalidate_cache_range((addr_t) ept->req,
389 sizeof(struct usb_request));
390 }
Amol Jadi4421e652011-06-16 15:00:48 -0700391
Ajay Dudanib01e5062011-12-03 23:23:42 -0800392 if (req) {
Hanumant Singh5322c742012-12-12 15:40:09 -0800393 item = VA(req->item);
394 /* total transfer length for transacation */
395 total_len = req->req.length;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800396 ept->req = 0;
Hanumant Singh5322c742012-12-12 15:40:09 -0800397 actual = 0;
398 while(1) {
Amol Jadi4421e652011-06-16 15:00:48 -0700399
Hanumant Singh5322c742012-12-12 15:40:09 -0800400 do {
401 /*
402 * Must clean/invalidate cached item
403 * data before checking the status
404 * every time.
405 */
406 arch_invalidate_cache_range((addr_t)(item),
407 sizeof(
408 struct ept_queue_item));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800409
Hanumant Singh5322c742012-12-12 15:40:09 -0800410 } while(readl(&item->info) & INFO_ACTIVE);
411
412 if ((item->info) & 0xff) {
413 /* error */
414 status = -1;
415 dprintf(INFO, "EP%d/%s FAIL nfo=%x pg0=%x\n",
416 ept->num, ept->in ? "in" : "out",
417 item->info,
418 item->page0);
419 goto out;
420 }
421
422 /* Check if we are processing last TD */
423 if (item->next == TERMINATE) {
424 /*
425 * Record the data transferred for the last TD
426 */
427 actual += total_len - (item->info >> 16)
428 & 0x7FFF;
429 total_len = 0;
430 break;
431 } else {
432 /*
433 * Since we are not in last TD
434 * the total assumed transfer ascribed to this
435 * TD woulb the max possible TD transfer size
436 * (16K)
437 */
438 actual += MAX_TD_XFER_SIZE - (item->info >> 16) & 0x7FFF;
439 total_len -= MAX_TD_XFER_SIZE - (item->info >> 16) & 0x7FFF;
440 /*Move to next item in chain*/
441 item = VA(item->next);
442 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800443 }
Hanumant Singh5322c742012-12-12 15:40:09 -0800444 status = 0;
445out:
Ajay Dudanib01e5062011-12-03 23:23:42 -0800446 if (req->req.complete)
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800447 req->req.complete(&req->req, actual, status);
448 }
449}
450
451static const char *reqname(unsigned r)
452{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800453 switch (r) {
454 case GET_STATUS:
455 return "GET_STATUS";
456 case CLEAR_FEATURE:
457 return "CLEAR_FEATURE";
458 case SET_FEATURE:
459 return "SET_FEATURE";
460 case SET_ADDRESS:
461 return "SET_ADDRESS";
462 case GET_DESCRIPTOR:
463 return "GET_DESCRIPTOR";
464 case SET_DESCRIPTOR:
465 return "SET_DESCRIPTOR";
466 case GET_CONFIGURATION:
467 return "GET_CONFIGURATION";
468 case SET_CONFIGURATION:
469 return "SET_CONFIGURATION";
470 case GET_INTERFACE:
471 return "GET_INTERFACE";
472 case SET_INTERFACE:
473 return "SET_INTERFACE";
474 default:
475 return "*UNKNOWN*";
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800476 }
477}
478
479static struct udc_endpoint *ep0in, *ep0out;
480static struct udc_request *ep0req;
481
Ajay Dudanib01e5062011-12-03 23:23:42 -0800482static void
vijay kumar9c9f1cf2014-01-15 16:05:28 +0530483ep0_setup_ack_complete()
Shashank Mittal2523e0b2011-10-14 17:32:46 -0700484{
485 uint32_t mode;
486
Ajay Dudanib01e5062011-12-03 23:23:42 -0800487 if (!test_mode)
Shashank Mittal2523e0b2011-10-14 17:32:46 -0700488 return;
489
Ajay Dudanib01e5062011-12-03 23:23:42 -0800490 switch (test_mode) {
491 case TEST_PACKET:
492 dprintf(INFO, "Entering test mode for TST_PKT\n");
493 mode = readl(USB_PORTSC) & (~PORTSC_PTC);
494 writel(mode | PORTSC_PTC_TST_PKT, USB_PORTSC);
495 break;
Shashank Mittal2523e0b2011-10-14 17:32:46 -0700496
Ajay Dudanib01e5062011-12-03 23:23:42 -0800497 case TEST_SE0_NAK:
498 dprintf(INFO, "Entering test mode for SE0-NAK\n");
499 mode = readl(USB_PORTSC) & (~PORTSC_PTC);
500 writel(mode | PORTSC_PTC_SE0_NAK, USB_PORTSC);
501 break;
Shashank Mittal2523e0b2011-10-14 17:32:46 -0700502 }
503
504}
505
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800506static void setup_ack(void)
507{
Shashank Mittal2523e0b2011-10-14 17:32:46 -0700508 ep0req->complete = ep0_setup_ack_complete;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800509 ep0req->length = 0;
510 udc_request_queue(ep0in, ep0req);
511}
512
513static void ep0in_complete(struct udc_request *req, unsigned actual, int status)
514{
515 DBG("ep0in_complete %p %d %d\n", req, actual, status);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800516 if (status == 0) {
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800517 req->length = 0;
518 req->complete = 0;
519 udc_request_queue(ep0out, req);
520 }
521}
522
523static void setup_tx(void *buf, unsigned len)
524{
525 DBG("setup_tx %p %d\n", buf, len);
526 memcpy(ep0req->buf, buf, len);
Deepa Dinamani0bf2f442012-10-19 11:41:06 -0700527 ep0req->buf = PA((addr_t)ep0req->buf);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800528 ep0req->complete = ep0in_complete;
529 ep0req->length = len;
530 udc_request_queue(ep0in, ep0req);
531}
532
533static unsigned char usb_config_value = 0;
534
535#define SETUP(type,request) (((type) << 8) | (request))
536
537static void handle_setup(struct udc_endpoint *ept)
538{
539 struct setup_packet s;
Amol Jadi4421e652011-06-16 15:00:48 -0700540
Ajay Dudanib01e5062011-12-03 23:23:42 -0800541 arch_clean_invalidate_cache_range((addr_t) ept->head->setup_data,
542 sizeof(struct ept_queue_head));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800543 memcpy(&s, ept->head->setup_data, sizeof(s));
544 writel(ept->bit, USB_ENDPTSETUPSTAT);
545
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800546 DBG("handle_setup type=0x%02x req=0x%02x val=%d idx=%d len=%d (%s)\n",
Ajay Dudanib01e5062011-12-03 23:23:42 -0800547 s.type, s.request, s.value, s.index, s.length, reqname(s.request));
Amol Jadi4421e652011-06-16 15:00:48 -0700548
Ajay Dudanib01e5062011-12-03 23:23:42 -0800549 switch (SETUP(s.type, s.request)) {
550 case SETUP(DEVICE_READ, GET_STATUS):
551 {
552 unsigned zero = 0;
553 if (s.length == 2) {
554 setup_tx(&zero, 2);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800555 return;
556 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800557 break;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800558 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800559 case SETUP(DEVICE_READ, GET_DESCRIPTOR):
560 {
561 struct udc_descriptor *desc;
562 /* usb_highspeed? */
563 for (desc = desc_list; desc; desc = desc->next) {
564 if (desc->tag == s.value) {
565 unsigned len = desc->len;
566 if (len > s.length)
567 len = s.length;
568 setup_tx(desc->data, len);
569 return;
570 }
571 }
572 break;
573 }
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800574 case SETUP(DEVICE_READ, GET_CONFIGURATION):
575 /* disabling this causes data transaction failures on OSX. Why? */
576 if ((s.value == 0) && (s.index == 0) && (s.length == 1)) {
577 setup_tx(&usb_config_value, 1);
578 return;
579 }
580 break;
581 case SETUP(DEVICE_WRITE, SET_CONFIGURATION):
582 if (s.value == 1) {
583 struct udc_endpoint *ept;
584 /* enable endpoints */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800585 for (ept = ept_list; ept; ept = ept->next) {
Amol Jadi4421e652011-06-16 15:00:48 -0700586 if (ept->num == 0)
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800587 continue;
588 endpoint_enable(ept, s.value);
589 }
590 usb_config_value = 1;
591 the_gadget->notify(the_gadget, UDC_EVENT_ONLINE);
592 } else {
593 writel(0, USB_ENDPTCTRL(1));
594 usb_config_value = 0;
595 the_gadget->notify(the_gadget, UDC_EVENT_OFFLINE);
596 }
597 setup_ack();
598 usb_online = s.value ? 1 : 0;
599 usb_status(s.value ? 1 : 0, usb_highspeed);
600 return;
601 case SETUP(DEVICE_WRITE, SET_ADDRESS):
602 /* write address delayed (will take effect
Ajay Dudanib01e5062011-12-03 23:23:42 -0800603 ** after the next IN txn)
604 */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800605 writel((s.value << 25) | (1 << 24), USB_DEVICEADDR);
606 setup_ack();
607 return;
608 case SETUP(INTERFACE_WRITE, SET_INTERFACE):
609 /* if we ack this everything hangs */
610 /* per spec, STALL is valid if there is not alt func */
611 goto stall;
Subbaraman Narayanamurthyd8b7afc2011-06-30 15:42:41 -0700612 case SETUP(DEVICE_WRITE, SET_FEATURE):
Shashank Mittal2523e0b2011-10-14 17:32:46 -0700613 test_mode = s.index;
Subbaraman Narayanamurthyd8b7afc2011-06-30 15:42:41 -0700614 setup_ack();
Subbaraman Narayanamurthyd8b7afc2011-06-30 15:42:41 -0700615 return;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800616 case SETUP(ENDPOINT_WRITE, CLEAR_FEATURE):
617 {
618 struct udc_endpoint *ept;
619 unsigned num = s.index & 15;
620 unsigned in = !!(s.index & 0x80);
Amol Jadi4421e652011-06-16 15:00:48 -0700621
Ajay Dudanib01e5062011-12-03 23:23:42 -0800622 if ((s.value == 0) && (s.length == 0)) {
623 DBG("clr feat %d %d\n", num, in);
624 for (ept = ept_list; ept; ept = ept->next) {
625 if ((ept->num == num)
626 && (ept->in == in)) {
627 endpoint_enable(ept, 1);
628 setup_ack();
629 return;
630 }
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800631 }
632 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800633 break;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800634 }
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800635 }
636
637 dprintf(INFO, "STALL %s %d %d %d %d %d\n",
638 reqname(s.request),
639 s.type, s.request, s.value, s.index, s.length);
640
Ajay Dudanib01e5062011-12-03 23:23:42 -0800641 stall:
642 writel((1 << 16) | (1 << 0), USB_ENDPTCTRL(ept->num));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800643}
644
645unsigned ulpi_read(unsigned reg)
646{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800647 /* initiate read operation */
648 writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg), USB_ULPI_VIEWPORT);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800649
Ajay Dudanib01e5062011-12-03 23:23:42 -0800650 /* wait for completion */
651 while (readl(USB_ULPI_VIEWPORT) & ULPI_RUN) ;
Amol Jadi4421e652011-06-16 15:00:48 -0700652
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800653 return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
654}
655
656void ulpi_write(unsigned val, unsigned reg)
657{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800658 /* initiate write operation */
Amol Jadi4421e652011-06-16 15:00:48 -0700659 writel(ULPI_RUN | ULPI_WRITE |
Ajay Dudanib01e5062011-12-03 23:23:42 -0800660 ULPI_ADDR(reg) | ULPI_DATA(val), USB_ULPI_VIEWPORT);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800661
Ajay Dudanib01e5062011-12-03 23:23:42 -0800662 /* wait for completion */
663 while (readl(USB_ULPI_VIEWPORT) & ULPI_RUN) ;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800664}
Ajay Dudani5a1e3302009-12-05 13:19:17 -0800665
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800666
Amol Jadi4421e652011-06-16 15:00:48 -0700667int udc_init(struct udc_device *dev)
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800668{
Amol Jadi4421e652011-06-16 15:00:48 -0700669 DBG("udc_init():\n");
670
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800671 hsusb_clock_init();
672
Amol Jadida118b92012-07-06 19:53:18 -0700673 /* RESET */
Channagoud Kadabi50c92b12013-03-29 14:36:44 -0700674 writel(0x00080002, USB_USBCMD);
Amol Jadida118b92012-07-06 19:53:18 -0700675
676 thread_sleep(20);
Subbaraman Narayanamurthyb0111a12011-02-03 14:24:16 -0800677
Deepa Dinamani0687ecd2012-08-10 16:00:26 -0700678 while((readl(USB_USBCMD)&2));
679
680 /* select ULPI phy */
681 writel(0x80000000, USB_PORTSC);
682
Amol Jadi71303ad2013-02-28 20:56:08 -0800683 /* Do any target specific intialization like GPIO settings,
684 * LDO, PHY configuration etc. needed before USB port can be used.
685 */
686 target_usb_init();
687
688 /* USB_OTG_HS_AHB_BURST */
Deepa Dinamani0687ecd2012-08-10 16:00:26 -0700689 writel(0x0, USB_SBUSCFG);
690
691 /* USB_OTG_HS_AHB_MODE: HPROT_MODE */
692 /* Bus access related config. */
693 writel(0x08, USB_AHB_MODE);
694
Deepa Dinamani4f9db032013-03-15 13:17:16 -0700695 epts = memalign(lcm(4096, CACHE_LINE), ROUNDUP(4096, CACHE_LINE));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800696
697 dprintf(INFO, "USB init ept @ %p\n", epts);
698 memset(epts, 0, 32 * sizeof(struct ept_queue_head));
Ajay Dudanib01e5062011-12-03 23:23:42 -0800699 arch_clean_invalidate_cache_range((addr_t) epts,
700 32 * sizeof(struct ept_queue_head));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800701
Deepa Dinamani0bf2f442012-10-19 11:41:06 -0700702 writel((unsigned)PA((addr_t)epts), USB_ENDPOINTLISTADDR);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800703
Ajay Dudanib01e5062011-12-03 23:23:42 -0800704 /* select DEVICE mode */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800705 writel(0x02, USB_USBMODE);
706
707 writel(0xffffffff, USB_ENDPTFLUSH);
708 thread_sleep(20);
709
710 ep0out = _udc_endpoint_alloc(0, 0, 64);
711 ep0in = _udc_endpoint_alloc(0, 1, 64);
712 ep0req = udc_request_alloc();
Deepa Dinamani4f9db032013-03-15 13:17:16 -0700713 ep0req->buf = memalign(CACHE_LINE, ROUNDUP(4096, CACHE_LINE));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800714
715 {
716 /* create and register a language table descriptor */
717 /* language 0x0409 is US English */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800718 struct udc_descriptor *desc =
719 udc_descriptor_alloc(TYPE_STRING, 0, 4);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800720 desc->data[2] = 0x09;
721 desc->data[3] = 0x04;
722 udc_descriptor_register(desc);
723 }
Amol Jadi4421e652011-06-16 15:00:48 -0700724
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800725 the_device = dev;
726 return 0;
727}
728
729enum handler_return udc_interrupt(void *arg)
730{
731 struct udc_endpoint *ept;
732 unsigned ret = INT_NO_RESCHEDULE;
733 unsigned n = readl(USB_USBSTS);
734 writel(n, USB_USBSTS);
Amol Jadi4421e652011-06-16 15:00:48 -0700735
Amol Jadida118b92012-07-06 19:53:18 -0700736 DBG("\nudc_interrupt(): status = 0x%x\n", n);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800737
Amol Jadida118b92012-07-06 19:53:18 -0700738 n &= (STS_SLI | STS_URI | STS_PCI | STS_UI | STS_UEI);
Amol Jadi4421e652011-06-16 15:00:48 -0700739
740 if (n == 0) {
741 DBG("n = 0\n");
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800742 return ret;
Amol Jadi4421e652011-06-16 15:00:48 -0700743 }
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800744
745 if (n & STS_URI) {
Amol Jadi4421e652011-06-16 15:00:48 -0700746 DBG("STS_URI\n");
747
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800748 writel(readl(USB_ENDPTCOMPLETE), USB_ENDPTCOMPLETE);
749 writel(readl(USB_ENDPTSETUPSTAT), USB_ENDPTSETUPSTAT);
750 writel(0xffffffff, USB_ENDPTFLUSH);
751 writel(0, USB_ENDPTCTRL(1));
Amol Jadi4421e652011-06-16 15:00:48 -0700752 dprintf(INFO, "-- reset --\n");
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800753 usb_online = 0;
754 usb_config_value = 0;
755 the_gadget->notify(the_gadget, UDC_EVENT_OFFLINE);
756
757 /* error out any pending reqs */
758 for (ept = ept_list; ept; ept = ept->next) {
759 /* ensure that ept_complete considers
760 * this to be an error state
761 */
762 if (ept->req) {
763 ept->req->item->info = INFO_HALTED;
764 handle_ept_complete(ept);
765 }
766 }
767 usb_status(0, usb_highspeed);
768 }
769 if (n & STS_SLI) {
Ajay Dudani35f686f2011-07-22 13:12:09 -0700770 DBG("-- suspend --\n");
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800771 }
772 if (n & STS_PCI) {
Amol Jadi4421e652011-06-16 15:00:48 -0700773 dprintf(INFO, "-- portchange --\n");
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800774 unsigned spd = (readl(USB_PORTSC) >> 26) & 3;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800775 if (spd == 2) {
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800776 usb_highspeed = 1;
777 } else {
778 usb_highspeed = 0;
779 }
780 }
781 if (n & STS_UEI) {
Amol Jadi4421e652011-06-16 15:00:48 -0700782 DBG("STS_UEI\n");
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800783 dprintf(INFO, "<UEI %x>\n", readl(USB_ENDPTCOMPLETE));
784 }
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800785 if ((n & STS_UI) || (n & STS_UEI)) {
Amol Jadida118b92012-07-06 19:53:18 -0700786
787 if (n & STS_UEI)
788 DBG("ERROR ");
789 if (n & STS_UI)
790 DBG("USB ");
791
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800792 n = readl(USB_ENDPTSETUPSTAT);
793 if (n & EPT_RX(0)) {
794 handle_setup(ep0out);
795 ret = INT_RESCHEDULE;
796 }
797
798 n = readl(USB_ENDPTCOMPLETE);
799 if (n != 0) {
800 writel(n, USB_ENDPTCOMPLETE);
801 }
802
Ajay Dudanib01e5062011-12-03 23:23:42 -0800803 for (ept = ept_list; ept; ept = ept->next) {
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800804 if (n & ept->bit) {
805 handle_ept_complete(ept);
806 ret = INT_RESCHEDULE;
807 }
808 }
809 }
810 return ret;
811}
812
813int udc_register_gadget(struct udc_gadget *gadget)
814{
815 if (the_gadget) {
816 dprintf(CRITICAL, "only one gadget supported\n");
817 return -1;
818 }
819 the_gadget = gadget;
820 return 0;
821}
822
823static void udc_ept_desc_fill(struct udc_endpoint *ept, unsigned char *data)
824{
825 data[0] = 7;
826 data[1] = TYPE_ENDPOINT;
827 data[2] = ept->num | (ept->in ? 0x80 : 0x00);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800828 data[3] = 0x02; /* bulk -- the only kind we support */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800829 data[4] = ept->maxpkt;
830 data[5] = ept->maxpkt >> 8;
831 data[6] = ept->in ? 0x00 : 0x01;
832}
833
834static unsigned udc_ifc_desc_size(struct udc_gadget *g)
835{
836 return 9 + g->ifc_endpoints * 7;
837}
838
839static void udc_ifc_desc_fill(struct udc_gadget *g, unsigned char *data)
840{
841 unsigned n;
842
843 data[0] = 0x09;
844 data[1] = TYPE_INTERFACE;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800845 data[2] = 0x00; /* ifc number */
846 data[3] = 0x00; /* alt number */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800847 data[4] = g->ifc_endpoints;
848 data[5] = g->ifc_class;
849 data[6] = g->ifc_subclass;
850 data[7] = g->ifc_protocol;
851 data[8] = udc_string_desc_alloc(g->ifc_string);
852
853 data += 9;
854 for (n = 0; n < g->ifc_endpoints; n++) {
855 udc_ept_desc_fill(g->ept[n], data);
856 data += 7;
857 }
858}
859
860int udc_start(void)
861{
862 struct udc_descriptor *desc;
863 unsigned char *data;
864 unsigned size;
Amol Jadi71303ad2013-02-28 20:56:08 -0800865 uint32_t val;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800866
Chandan Uddaraju40b227d2010-08-03 19:25:41 -0700867 dprintf(ALWAYS, "udc_start()\n");
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800868
869 if (!the_device) {
870 dprintf(CRITICAL, "udc cannot start before init\n");
871 return -1;
872 }
873 if (!the_gadget) {
874 dprintf(CRITICAL, "udc has no gadget registered\n");
875 return -1;
876 }
877
878 /* create our device descriptor */
879 desc = udc_descriptor_alloc(TYPE_DEVICE, 0, 18);
880 data = desc->data;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800881 data[2] = 0x00; /* usb spec minor rev */
882 data[3] = 0x02; /* usb spec major rev */
883 data[4] = 0x00; /* class */
884 data[5] = 0x00; /* subclass */
885 data[6] = 0x00; /* protocol */
886 data[7] = 0x40; /* max packet size on ept 0 */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800887 memcpy(data + 8, &the_device->vendor_id, sizeof(short));
888 memcpy(data + 10, &the_device->product_id, sizeof(short));
889 memcpy(data + 12, &the_device->version_id, sizeof(short));
890 data[14] = udc_string_desc_alloc(the_device->manufacturer);
891 data[15] = udc_string_desc_alloc(the_device->product);
892 data[16] = udc_string_desc_alloc(the_device->serialno);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800893 data[17] = 1; /* number of configurations */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800894 udc_descriptor_register(desc);
895
896 /* create our configuration descriptor */
897 size = 9 + udc_ifc_desc_size(the_gadget);
898 desc = udc_descriptor_alloc(TYPE_CONFIGURATION, 0, size);
899 data = desc->data;
900 data[0] = 0x09;
901 data[2] = size;
902 data[3] = size >> 8;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800903 data[4] = 0x01; /* number of interfaces */
904 data[5] = 0x01; /* configuration value */
905 data[6] = 0x00; /* configuration string */
906 data[7] = 0x80; /* attributes */
907 data[8] = 0x80; /* max power (250ma) -- todo fix this */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800908 udc_ifc_desc_fill(the_gadget, data + 9);
909 udc_descriptor_register(desc);
910
Ajay Dudanib01e5062011-12-03 23:23:42 -0800911 register_int_handler(INT_USB_HS, udc_interrupt, (void *)0);
Amol Jadica4f4c92011-01-13 20:19:34 -0800912 writel(STS_URI | STS_SLI | STS_UI | STS_PCI, USB_USBINTR);
913 unmask_interrupt(INT_USB_HS);
914
Ajay Dudanib01e5062011-12-03 23:23:42 -0800915 /* go to RUN mode (D+ pullup enable) */
Amol Jadi71303ad2013-02-28 20:56:08 -0800916 val = readl(USB_USBCMD);
917
918 writel(val | 0x00080001, USB_USBCMD);
Amol Jadica4f4c92011-01-13 20:19:34 -0800919
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800920 return 0;
921}
922
923int udc_stop(void)
924{
Deepa Dinamani761cc952013-03-06 11:15:46 -0800925 uint32_t val;
926
927 /* Flush all primed end points. */
928 writel(0xffffffff, USB_ENDPTFLUSH);
929
930 /* Stop controller. */
931 val = readl(USB_USBCMD);
932 writel(val & ~USBCMD_ATTACH, USB_USBCMD);
933
934 /* Mask the interrupts. */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800935 writel(0, USB_USBINTR);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800936 mask_interrupt(INT_USB_HS);
937
Deepa Dinamani761cc952013-03-06 11:15:46 -0800938 /* Perform any target specific clean up. */
Amol Jadida118b92012-07-06 19:53:18 -0700939 target_usb_stop();
940
Deepa Dinamani761cc952013-03-06 11:15:46 -0800941 /* Reset the controller. */
942 writel(USBCMD_RESET, USB_USBCMD);
943 /* Wait until reset completes. */
944 while(readl(USB_USBCMD) & USBCMD_RESET);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800945
946 return 0;
947}