blob: 5c7d61f43b9c39e40c8ca615a7a39d7d165b8944 [file] [log] [blame]
Brian Swetland3e7e21a2009-01-19 19:41:24 -08001/*
2 * Copyright (c) 2008, Google Inc.
3 * All rights reserved.
4 *
Matthew Qinc7447202015-02-03 17:45:17 +08005 * Copyright (c) 2009-2015, 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>
vijay kumar4f4405f2014-08-08 11:49:53 +053044#include <target.h>
Brian Swetland3e7e21a2009-01-19 19:41:24 -080045#include "hsusb.h"
46
Hanumant Singh5322c742012-12-12 15:40:09 -080047#define MAX_TD_XFER_SIZE (16 * 1024)
48
49
Brian Swetland3e7e21a2009-01-19 19:41:24 -080050/* common code - factor out into a shared file */
51
52struct udc_descriptor {
53 struct udc_descriptor *next;
Ajay Dudanib01e5062011-12-03 23:23:42 -080054 unsigned short tag; /* ((TYPE << 8) | NUM) */
55 unsigned short len; /* total length */
Brian Swetland3e7e21a2009-01-19 19:41:24 -080056 unsigned char data[0];
57};
58
Ajay Dudanib01e5062011-12-03 23:23:42 -080059struct udc_descriptor *udc_descriptor_alloc(unsigned type, unsigned num,
60 unsigned len)
Brian Swetland3e7e21a2009-01-19 19:41:24 -080061{
62 struct udc_descriptor *desc;
63 if ((len > 255) || (len < 2) || (num > 255) || (type > 255))
64 return 0;
65
Ajay Dudanib01e5062011-12-03 23:23:42 -080066 if (!(desc = malloc(sizeof(struct udc_descriptor) + len)))
Brian Swetland3e7e21a2009-01-19 19:41:24 -080067 return 0;
68
69 desc->next = 0;
70 desc->tag = (type << 8) | num;
71 desc->len = len;
72 desc->data[0] = len;
73 desc->data[1] = type;
74
75 return desc;
76}
77
78static struct udc_descriptor *desc_list = 0;
79static unsigned next_string_id = 1;
80
81void udc_descriptor_register(struct udc_descriptor *desc)
82{
83 desc->next = desc_list;
84 desc_list = desc;
85}
86
87unsigned udc_string_desc_alloc(const char *str)
88{
89 unsigned len;
90 struct udc_descriptor *desc;
91 unsigned char *data;
92
93 if (next_string_id > 255)
94 return 0;
95
96 if (!str)
97 return 0;
98
99 len = strlen(str);
100 desc = udc_descriptor_alloc(TYPE_STRING, next_string_id, len * 2 + 2);
101 if (!desc)
102 return 0;
103 next_string_id++;
104
105 /* expand ascii string to utf16 */
106 data = desc->data + 2;
107 while (len-- > 0) {
108 *data++ = *str++;
109 *data++ = 0;
110 }
111
112 udc_descriptor_register(desc);
113 return desc->tag & 0xff;
114}
115
116/* end of common code */
117
Ajay Dudani7d605522010-10-01 19:52:37 -0700118__WEAK void hsusb_clock_init(void)
119{
Greg Griscod6250552011-06-29 14:40:23 -0700120 return;
Ajay Dudani7d605522010-10-01 19:52:37 -0700121}
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800122
123#if 1
124#define DBG(x...) do {} while(0)
125#else
Amol Jadida118b92012-07-06 19:53:18 -0700126#define DBG(x...) dprintf(ALWAYS, x)
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800127#endif
128
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800129#define usb_status(a,b)
130
131struct usb_request {
132 struct udc_request req;
133 struct ept_queue_item *item;
134};
Amol Jadi4421e652011-06-16 15:00:48 -0700135
Ajay Dudanib01e5062011-12-03 23:23:42 -0800136struct udc_endpoint {
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800137 struct udc_endpoint *next;
138 unsigned bit;
139 struct ept_queue_head *head;
140 struct usb_request *req;
141 unsigned char num;
142 unsigned char in;
143 unsigned short maxpkt;
144};
145
146struct udc_endpoint *ept_list = 0;
147struct ept_queue_head *epts = 0;
148
149static int usb_online = 0;
150static int usb_highspeed = 0;
151
152static struct udc_device *the_device;
153static struct udc_gadget *the_gadget;
Shashank Mittal2523e0b2011-10-14 17:32:46 -0700154static unsigned test_mode = 0;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800155
Ajay Dudanib01e5062011-12-03 23:23:42 -0800156struct udc_endpoint *_udc_endpoint_alloc(unsigned num, unsigned in,
157 unsigned max_pkt)
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800158{
159 struct udc_endpoint *ept;
160 unsigned cfg;
161
Hanumant Singh9d519092012-12-06 21:59:52 -0800162 ept = memalign(CACHE_LINE, ROUNDUP(sizeof(*ept), CACHE_LINE));
Lijuan Gaodc077222014-07-18 16:43:18 +0800163 ASSERT(ept);
Amol Jadi4421e652011-06-16 15:00:48 -0700164
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800165 ept->maxpkt = max_pkt;
166 ept->num = num;
167 ept->in = !!in;
168 ept->req = 0;
169
170 cfg = CONFIG_MAX_PKT(max_pkt) | CONFIG_ZLT;
171
Ajay Dudanib01e5062011-12-03 23:23:42 -0800172 if (ept->in) {
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800173 ept->bit = EPT_TX(ept->num);
174 } else {
175 ept->bit = EPT_RX(ept->num);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800176 if (num == 0)
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800177 cfg |= CONFIG_IOS;
178 }
179
180 ept->head = epts + (num * 2) + (ept->in);
181 ept->head->config = cfg;
182
183 ept->next = ept_list;
184 ept_list = ept;
Amol Jadi4421e652011-06-16 15:00:48 -0700185
Matthew Qinc7447202015-02-03 17:45:17 +0800186 arch_clean_invalidate_cache_range((addr_t) ept,
187 sizeof(struct udc_endpoint));
188 arch_clean_invalidate_cache_range((addr_t) ept->head,
189 sizeof(struct ept_queue_head));
190
Amol Jadi4421e652011-06-16 15:00:48 -0700191 DBG("ept%d %s @%p/%p max=%d bit=%x\n",
Ajay Dudanib01e5062011-12-03 23:23:42 -0800192 num, in ? "in" : "out", ept, ept->head, max_pkt, ept->bit);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800193
194 return ept;
195}
196
197static unsigned ept_alloc_table = EPT_TX(0) | EPT_RX(0);
198
199struct udc_endpoint *udc_endpoint_alloc(unsigned type, unsigned maxpkt)
200{
201 struct udc_endpoint *ept;
202 unsigned n;
203 unsigned in;
204
205 if (type == UDC_TYPE_BULK_IN) {
206 in = 1;
207 } else if (type == UDC_TYPE_BULK_OUT) {
208 in = 0;
209 } else {
210 return 0;
211 }
212
213 for (n = 1; n < 16; n++) {
214 unsigned bit = in ? EPT_TX(n) : EPT_RX(n);
215 if (ept_alloc_table & bit)
216 continue;
217 ept = _udc_endpoint_alloc(n, in, maxpkt);
218 if (ept)
219 ept_alloc_table |= bit;
220 return ept;
221 }
222 return 0;
223}
224
225void udc_endpoint_free(struct udc_endpoint *ept)
226{
227 /* todo */
228}
229
230static void endpoint_enable(struct udc_endpoint *ept, unsigned yes)
231{
232 unsigned n = readl(USB_ENDPTCTRL(ept->num));
233
Ajay Dudanib01e5062011-12-03 23:23:42 -0800234 if (yes) {
235 if (ept->in) {
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800236 n |= (CTRL_TXE | CTRL_TXR | CTRL_TXT_BULK);
237 } else {
238 n |= (CTRL_RXE | CTRL_RXR | CTRL_RXT_BULK);
239 }
240
Ajay Dudanib01e5062011-12-03 23:23:42 -0800241 if (ept->num != 0) {
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800242 /* XXX should be more dynamic... */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800243 if (usb_highspeed) {
244 ept->head->config =
245 CONFIG_MAX_PKT(512) | CONFIG_ZLT;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800246 } else {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800247 ept->head->config =
248 CONFIG_MAX_PKT(64) | CONFIG_ZLT;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800249 }
250 }
251 }
252 writel(n, USB_ENDPTCTRL(ept->num));
253}
254
255struct udc_request *udc_request_alloc(void)
256{
257 struct usb_request *req;
Hanumant Singh9d519092012-12-06 21:59:52 -0800258 req = memalign(CACHE_LINE, ROUNDUP(sizeof(*req), CACHE_LINE));
Lijuan Gaodc077222014-07-18 16:43:18 +0800259 ASSERT(req);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800260 req->req.buf = 0;
261 req->req.length = 0;
Hanumant Singh9d519092012-12-06 21:59:52 -0800262 req->item = memalign(CACHE_LINE, ROUNDUP(sizeof(struct ept_queue_item),
263 CACHE_LINE));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800264 return &req->req;
265}
266
267void udc_request_free(struct udc_request *req)
268{
269 free(req);
270}
271
Hanumant Singh5322c742012-12-12 15:40:09 -0800272/*
273 * Assumes that TDs allocated already are not freed.
274 * But it can handle case where TDs are freed as well.
275 */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800276int udc_request_queue(struct udc_endpoint *ept, struct udc_request *_req)
277{
Hanumant Singh5322c742012-12-12 15:40:09 -0800278 unsigned xfer = 0;
279 struct ept_queue_item *item, *curr_item;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800280 struct usb_request *req = (struct usb_request *)_req;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800281 unsigned phys = (unsigned)req->req.buf;
Hanumant Singh5322c742012-12-12 15:40:09 -0800282 unsigned len = req->req.length;
283 unsigned int count = 0;
Amol Jadi4421e652011-06-16 15:00:48 -0700284
Hanumant Singh5322c742012-12-12 15:40:09 -0800285 curr_item = NULL;
286 xfer = (len > MAX_TD_XFER_SIZE) ? MAX_TD_XFER_SIZE : len;
287 /*
288 * First TD allocated during request allocation
289 */
290 item = req->item;
291 item->info = INFO_BYTES(xfer) | INFO_ACTIVE;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800292 item->page0 = phys;
293 item->page1 = (phys & 0xfffff000) + 0x1000;
Shashank Mittal1cc65b02011-12-20 15:30:17 -0800294 item->page2 = (phys & 0xfffff000) + 0x2000;
295 item->page3 = (phys & 0xfffff000) + 0x3000;
296 item->page4 = (phys & 0xfffff000) + 0x4000;
Hanumant Singh5322c742012-12-12 15:40:09 -0800297 phys += xfer;
298 curr_item = item;
299 len -= xfer;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800300
Hanumant Singh5322c742012-12-12 15:40:09 -0800301 /*
302 * If transfer length is more then
303 * accomodate by 1 TD
304 * we add more transfer descriptors
305 */
306 while (len > 0) {
307 xfer = (len > MAX_TD_XFER_SIZE) ? MAX_TD_XFER_SIZE : len;
308 if (curr_item->next == TERMINATE) {
309 /*
310 * Allocate new TD only if chain doesnot
311 * exist already
312 */
313 item = memalign(CACHE_LINE,
314 ROUNDUP(sizeof(struct ept_queue_item), CACHE_LINE));
315 if (!item) {
vijay kumar4f4405f2014-08-08 11:49:53 +0530316 dprintf(ALWAYS, "allocate USB item fail ept%d\n %s queue\ntd count = %d\n",
Hanumant Singh5322c742012-12-12 15:40:09 -0800317 ept->num,
318 ept->in ? "in" : "out",
319 count);
320 return -1;
321 } else {
322 count ++;
vijay kumar4f4405f2014-08-08 11:49:53 +0530323 curr_item->next = PA((addr_t)item);
Hanumant Singh5322c742012-12-12 15:40:09 -0800324 item->next = TERMINATE;
325 }
326 } else
327 /* Since next TD in chain already exists */
vijay kumar4f4405f2014-08-08 11:49:53 +0530328 item = (struct ept_queue_item *)VA(curr_item->next);
Hanumant Singh5322c742012-12-12 15:40:09 -0800329
330 /* Update TD with transfer information */
331 item->info = INFO_BYTES(xfer) | INFO_ACTIVE;
332 item->page0 = phys;
333 item->page1 = (phys & 0xfffff000) + 0x1000;
334 item->page2 = (phys & 0xfffff000) + 0x2000;
335 item->page3 = (phys & 0xfffff000) + 0x3000;
336 item->page4 = (phys & 0xfffff000) + 0x4000;
337
338 curr_item = item;
339 len -= xfer;
340 phys += xfer;
341 }
342
343 /* Terminate and set interrupt for last TD */
344 curr_item->next = TERMINATE;
345 curr_item->info |= INFO_IOC;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800346 enter_critical_section();
vijay kumar4f4405f2014-08-08 11:49:53 +0530347 ept->head->next = PA((addr_t)req->item);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800348 ept->head->info = 0;
349 ept->req = req;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800350 arch_clean_invalidate_cache_range((addr_t) ept,
351 sizeof(struct udc_endpoint));
352 arch_clean_invalidate_cache_range((addr_t) ept->head,
353 sizeof(struct ept_queue_head));
354 arch_clean_invalidate_cache_range((addr_t) ept->req,
355 sizeof(struct usb_request));
vijay kumar4f4405f2014-08-08 11:49:53 +0530356 arch_clean_invalidate_cache_range((addr_t) VA((addr_t)req->req.buf),
Ajay Dudanib01e5062011-12-03 23:23:42 -0800357 req->req.length);
Hanumant Singh5322c742012-12-12 15:40:09 -0800358
359 item = req->item;
360 /* Write all TD's to memory from cache */
361 while (item != NULL) {
362 curr_item = item;
363 if (curr_item->next == TERMINATE)
364 item = NULL;
365 else
vijay kumar4f4405f2014-08-08 11:49:53 +0530366 item = (struct ept_queue_item *)curr_item->next;
Hanumant Singh5322c742012-12-12 15:40:09 -0800367 arch_clean_invalidate_cache_range((addr_t) curr_item,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800368 sizeof(struct ept_queue_item));
Hanumant Singh5322c742012-12-12 15:40:09 -0800369 }
Amol Jadi4421e652011-06-16 15:00:48 -0700370
Ajay Dudanib01e5062011-12-03 23:23:42 -0800371 DBG("ept%d %s queue req=%p\n", ept->num, ept->in ? "in" : "out", req);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800372 writel(ept->bit, USB_ENDPTPRIME);
373 exit_critical_section();
374 return 0;
375}
376
377static void handle_ept_complete(struct udc_endpoint *ept)
378{
379 struct ept_queue_item *item;
Hanumant Singh5322c742012-12-12 15:40:09 -0800380 unsigned actual, total_len;
vijay kumar4f4405f2014-08-08 11:49:53 +0530381 int status;
Sundarajan Srinivasanafc69282013-11-19 14:07:03 -0800382 struct usb_request *req=NULL;
Amol Jadi4421e652011-06-16 15:00:48 -0700383
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800384 DBG("ept%d %s complete req=%p\n",
Ajay Dudanib01e5062011-12-03 23:23:42 -0800385 ept->num, ept->in ? "in" : "out", ept->req);
Amol Jadi4421e652011-06-16 15:00:48 -0700386
Hanumant Singh5322c742012-12-12 15:40:09 -0800387 arch_invalidate_cache_range((addr_t) ept,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800388 sizeof(struct udc_endpoint));
Sundarajan Srinivasanafc69282013-11-19 14:07:03 -0800389
390 if(ept->req)
391 {
vijay kumar4f4405f2014-08-08 11:49:53 +0530392 req = (struct usb_request *)VA((addr_t)ept->req);
Sundarajan Srinivasanafc69282013-11-19 14:07:03 -0800393 arch_invalidate_cache_range((addr_t) ept->req,
394 sizeof(struct usb_request));
395 }
Amol Jadi4421e652011-06-16 15:00:48 -0700396
Ajay Dudanib01e5062011-12-03 23:23:42 -0800397 if (req) {
vijay kumar4f4405f2014-08-08 11:49:53 +0530398 item = (struct ept_queue_item *)VA((addr_t)req->item);
Hanumant Singh5322c742012-12-12 15:40:09 -0800399 /* total transfer length for transacation */
400 total_len = req->req.length;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800401 ept->req = 0;
Hanumant Singh5322c742012-12-12 15:40:09 -0800402 actual = 0;
403 while(1) {
Amol Jadi4421e652011-06-16 15:00:48 -0700404
Hanumant Singh5322c742012-12-12 15:40:09 -0800405 do {
406 /*
407 * Must clean/invalidate cached item
408 * data before checking the status
409 * every time.
410 */
411 arch_invalidate_cache_range((addr_t)(item),
412 sizeof(
413 struct ept_queue_item));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800414
Hanumant Singh5322c742012-12-12 15:40:09 -0800415 } while(readl(&item->info) & INFO_ACTIVE);
416
417 if ((item->info) & 0xff) {
418 /* error */
419 status = -1;
420 dprintf(INFO, "EP%d/%s FAIL nfo=%x pg0=%x\n",
421 ept->num, ept->in ? "in" : "out",
422 item->info,
423 item->page0);
424 goto out;
425 }
426
427 /* Check if we are processing last TD */
428 if (item->next == TERMINATE) {
429 /*
430 * Record the data transferred for the last TD
431 */
vijay kumar4f4405f2014-08-08 11:49:53 +0530432 actual += (total_len - (item->info >> 16))
Hanumant Singh5322c742012-12-12 15:40:09 -0800433 & 0x7FFF;
434 total_len = 0;
435 break;
436 } else {
437 /*
438 * Since we are not in last TD
439 * the total assumed transfer ascribed to this
440 * TD woulb the max possible TD transfer size
441 * (16K)
442 */
vijay kumar4f4405f2014-08-08 11:49:53 +0530443 actual += (MAX_TD_XFER_SIZE - (item->info >> 16)) & 0x7FFF;
444 total_len -= (MAX_TD_XFER_SIZE - (item->info >> 16)) & 0x7FFF;
Hanumant Singh5322c742012-12-12 15:40:09 -0800445 /*Move to next item in chain*/
vijay kumar4f4405f2014-08-08 11:49:53 +0530446 item = (struct ept_queue_item *)VA(item->next);
Hanumant Singh5322c742012-12-12 15:40:09 -0800447 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800448 }
Hanumant Singh5322c742012-12-12 15:40:09 -0800449 status = 0;
450out:
Ajay Dudanib01e5062011-12-03 23:23:42 -0800451 if (req->req.complete)
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800452 req->req.complete(&req->req, actual, status);
453 }
454}
455
456static const char *reqname(unsigned r)
457{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800458 switch (r) {
459 case GET_STATUS:
460 return "GET_STATUS";
461 case CLEAR_FEATURE:
462 return "CLEAR_FEATURE";
463 case SET_FEATURE:
464 return "SET_FEATURE";
465 case SET_ADDRESS:
466 return "SET_ADDRESS";
467 case GET_DESCRIPTOR:
468 return "GET_DESCRIPTOR";
469 case SET_DESCRIPTOR:
470 return "SET_DESCRIPTOR";
471 case GET_CONFIGURATION:
472 return "GET_CONFIGURATION";
473 case SET_CONFIGURATION:
474 return "SET_CONFIGURATION";
475 case GET_INTERFACE:
476 return "GET_INTERFACE";
477 case SET_INTERFACE:
478 return "SET_INTERFACE";
479 default:
480 return "*UNKNOWN*";
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800481 }
482}
483
484static struct udc_endpoint *ep0in, *ep0out;
485static struct udc_request *ep0req;
486
Ajay Dudanib01e5062011-12-03 23:23:42 -0800487static void
vijay kumar9c9f1cf2014-01-15 16:05:28 +0530488ep0_setup_ack_complete()
Shashank Mittal2523e0b2011-10-14 17:32:46 -0700489{
490 uint32_t mode;
491
Ajay Dudanib01e5062011-12-03 23:23:42 -0800492 if (!test_mode)
Shashank Mittal2523e0b2011-10-14 17:32:46 -0700493 return;
494
Ajay Dudanib01e5062011-12-03 23:23:42 -0800495 switch (test_mode) {
496 case TEST_PACKET:
497 dprintf(INFO, "Entering test mode for TST_PKT\n");
498 mode = readl(USB_PORTSC) & (~PORTSC_PTC);
499 writel(mode | PORTSC_PTC_TST_PKT, USB_PORTSC);
500 break;
Shashank Mittal2523e0b2011-10-14 17:32:46 -0700501
Ajay Dudanib01e5062011-12-03 23:23:42 -0800502 case TEST_SE0_NAK:
503 dprintf(INFO, "Entering test mode for SE0-NAK\n");
504 mode = readl(USB_PORTSC) & (~PORTSC_PTC);
505 writel(mode | PORTSC_PTC_SE0_NAK, USB_PORTSC);
506 break;
Shashank Mittal2523e0b2011-10-14 17:32:46 -0700507 }
508
509}
510
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800511static void setup_ack(void)
512{
Shashank Mittal2523e0b2011-10-14 17:32:46 -0700513 ep0req->complete = ep0_setup_ack_complete;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800514 ep0req->length = 0;
515 udc_request_queue(ep0in, ep0req);
516}
517
518static void ep0in_complete(struct udc_request *req, unsigned actual, int status)
519{
520 DBG("ep0in_complete %p %d %d\n", req, actual, status);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800521 if (status == 0) {
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800522 req->length = 0;
523 req->complete = 0;
524 udc_request_queue(ep0out, req);
525 }
526}
527
528static void setup_tx(void *buf, unsigned len)
529{
530 DBG("setup_tx %p %d\n", buf, len);
531 memcpy(ep0req->buf, buf, len);
vijay kumar4f4405f2014-08-08 11:49:53 +0530532 ep0req->buf = (void *)PA((addr_t)ep0req->buf);
Matthew Qinc7447202015-02-03 17:45:17 +0800533 arch_clean_invalidate_cache_range((addr_t)ep0req->buf, len);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800534 ep0req->complete = ep0in_complete;
535 ep0req->length = len;
536 udc_request_queue(ep0in, ep0req);
537}
538
539static unsigned char usb_config_value = 0;
540
541#define SETUP(type,request) (((type) << 8) | (request))
542
543static void handle_setup(struct udc_endpoint *ept)
544{
545 struct setup_packet s;
Amol Jadi4421e652011-06-16 15:00:48 -0700546
Ajay Dudanib01e5062011-12-03 23:23:42 -0800547 arch_clean_invalidate_cache_range((addr_t) ept->head->setup_data,
548 sizeof(struct ept_queue_head));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800549 memcpy(&s, ept->head->setup_data, sizeof(s));
Matthew Qinc7447202015-02-03 17:45:17 +0800550 arch_clean_invalidate_cache_range((addr_t)&s, sizeof(s));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800551 writel(ept->bit, USB_ENDPTSETUPSTAT);
552
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800553 DBG("handle_setup type=0x%02x req=0x%02x val=%d idx=%d len=%d (%s)\n",
Ajay Dudanib01e5062011-12-03 23:23:42 -0800554 s.type, s.request, s.value, s.index, s.length, reqname(s.request));
Amol Jadi4421e652011-06-16 15:00:48 -0700555
Ajay Dudanib01e5062011-12-03 23:23:42 -0800556 switch (SETUP(s.type, s.request)) {
557 case SETUP(DEVICE_READ, GET_STATUS):
558 {
559 unsigned zero = 0;
560 if (s.length == 2) {
561 setup_tx(&zero, 2);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800562 return;
563 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800564 break;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800565 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800566 case SETUP(DEVICE_READ, GET_DESCRIPTOR):
567 {
568 struct udc_descriptor *desc;
vijay kumarb8639052015-03-09 17:37:31 +0530569 unsigned char* data = NULL;
570 unsigned n;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800571 /* usb_highspeed? */
572 for (desc = desc_list; desc; desc = desc->next) {
573 if (desc->tag == s.value) {
vijay kumarb8639052015-03-09 17:37:31 +0530574 /*Check for configuration type of descriptor*/
575 if (desc->tag == (TYPE_CONFIGURATION << 8)) {
576 data = desc->data;
577 data+= 9; /* skip config desc */
578 data+= 9; /* skip interface desc */
579 /* taking the max packet size based on the USB host speed connected */
580 for (n = 0; n < 2; n++) {
581 data[4] = usb_highspeed ? 512:64;
582 data[5] = (usb_highspeed ? 512:64)>>8;
583 data += 7;
584 }
585 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800586 unsigned len = desc->len;
587 if (len > s.length)
588 len = s.length;
589 setup_tx(desc->data, len);
590 return;
591 }
592 }
593 break;
594 }
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800595 case SETUP(DEVICE_READ, GET_CONFIGURATION):
596 /* disabling this causes data transaction failures on OSX. Why? */
597 if ((s.value == 0) && (s.index == 0) && (s.length == 1)) {
598 setup_tx(&usb_config_value, 1);
599 return;
600 }
601 break;
602 case SETUP(DEVICE_WRITE, SET_CONFIGURATION):
603 if (s.value == 1) {
604 struct udc_endpoint *ept;
605 /* enable endpoints */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800606 for (ept = ept_list; ept; ept = ept->next) {
Amol Jadi4421e652011-06-16 15:00:48 -0700607 if (ept->num == 0)
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800608 continue;
609 endpoint_enable(ept, s.value);
610 }
611 usb_config_value = 1;
612 the_gadget->notify(the_gadget, UDC_EVENT_ONLINE);
613 } else {
614 writel(0, USB_ENDPTCTRL(1));
615 usb_config_value = 0;
616 the_gadget->notify(the_gadget, UDC_EVENT_OFFLINE);
617 }
618 setup_ack();
619 usb_online = s.value ? 1 : 0;
620 usb_status(s.value ? 1 : 0, usb_highspeed);
621 return;
622 case SETUP(DEVICE_WRITE, SET_ADDRESS):
623 /* write address delayed (will take effect
Ajay Dudanib01e5062011-12-03 23:23:42 -0800624 ** after the next IN txn)
625 */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800626 writel((s.value << 25) | (1 << 24), USB_DEVICEADDR);
627 setup_ack();
628 return;
629 case SETUP(INTERFACE_WRITE, SET_INTERFACE):
630 /* if we ack this everything hangs */
631 /* per spec, STALL is valid if there is not alt func */
632 goto stall;
Subbaraman Narayanamurthyd8b7afc2011-06-30 15:42:41 -0700633 case SETUP(DEVICE_WRITE, SET_FEATURE):
Shashank Mittal2523e0b2011-10-14 17:32:46 -0700634 test_mode = s.index;
Subbaraman Narayanamurthyd8b7afc2011-06-30 15:42:41 -0700635 setup_ack();
Subbaraman Narayanamurthyd8b7afc2011-06-30 15:42:41 -0700636 return;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800637 case SETUP(ENDPOINT_WRITE, CLEAR_FEATURE):
638 {
639 struct udc_endpoint *ept;
640 unsigned num = s.index & 15;
641 unsigned in = !!(s.index & 0x80);
Amol Jadi4421e652011-06-16 15:00:48 -0700642
Ajay Dudanib01e5062011-12-03 23:23:42 -0800643 if ((s.value == 0) && (s.length == 0)) {
644 DBG("clr feat %d %d\n", num, in);
645 for (ept = ept_list; ept; ept = ept->next) {
646 if ((ept->num == num)
647 && (ept->in == in)) {
648 endpoint_enable(ept, 1);
649 setup_ack();
650 return;
651 }
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800652 }
653 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800654 break;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800655 }
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800656 }
657
658 dprintf(INFO, "STALL %s %d %d %d %d %d\n",
659 reqname(s.request),
660 s.type, s.request, s.value, s.index, s.length);
661
Ajay Dudanib01e5062011-12-03 23:23:42 -0800662 stall:
663 writel((1 << 16) | (1 << 0), USB_ENDPTCTRL(ept->num));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800664}
665
666unsigned ulpi_read(unsigned reg)
667{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800668 /* initiate read operation */
669 writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg), USB_ULPI_VIEWPORT);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800670
Ajay Dudanib01e5062011-12-03 23:23:42 -0800671 /* wait for completion */
672 while (readl(USB_ULPI_VIEWPORT) & ULPI_RUN) ;
Amol Jadi4421e652011-06-16 15:00:48 -0700673
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800674 return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
675}
676
677void ulpi_write(unsigned val, unsigned reg)
678{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800679 /* initiate write operation */
Amol Jadi4421e652011-06-16 15:00:48 -0700680 writel(ULPI_RUN | ULPI_WRITE |
Ajay Dudanib01e5062011-12-03 23:23:42 -0800681 ULPI_ADDR(reg) | ULPI_DATA(val), USB_ULPI_VIEWPORT);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800682
Ajay Dudanib01e5062011-12-03 23:23:42 -0800683 /* wait for completion */
684 while (readl(USB_ULPI_VIEWPORT) & ULPI_RUN) ;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800685}
Ajay Dudani5a1e3302009-12-05 13:19:17 -0800686
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800687
Amol Jadi4421e652011-06-16 15:00:48 -0700688int udc_init(struct udc_device *dev)
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800689{
Amol Jadi4421e652011-06-16 15:00:48 -0700690 DBG("udc_init():\n");
691
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800692 hsusb_clock_init();
693
Amol Jadida118b92012-07-06 19:53:18 -0700694 /* RESET */
Channagoud Kadabi50c92b12013-03-29 14:36:44 -0700695 writel(0x00080002, USB_USBCMD);
Amol Jadida118b92012-07-06 19:53:18 -0700696
697 thread_sleep(20);
Subbaraman Narayanamurthyb0111a12011-02-03 14:24:16 -0800698
Deepa Dinamani0687ecd2012-08-10 16:00:26 -0700699 while((readl(USB_USBCMD)&2));
700
701 /* select ULPI phy */
702 writel(0x80000000, USB_PORTSC);
703
Amol Jadi71303ad2013-02-28 20:56:08 -0800704 /* Do any target specific intialization like GPIO settings,
705 * LDO, PHY configuration etc. needed before USB port can be used.
706 */
707 target_usb_init();
708
709 /* USB_OTG_HS_AHB_BURST */
Deepa Dinamani0687ecd2012-08-10 16:00:26 -0700710 writel(0x0, USB_SBUSCFG);
711
712 /* USB_OTG_HS_AHB_MODE: HPROT_MODE */
713 /* Bus access related config. */
714 writel(0x08, USB_AHB_MODE);
715
Deepa Dinamani4f9db032013-03-15 13:17:16 -0700716 epts = memalign(lcm(4096, CACHE_LINE), ROUNDUP(4096, CACHE_LINE));
Lijuan Gaodc077222014-07-18 16:43:18 +0800717 ASSERT(epts);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800718
719 dprintf(INFO, "USB init ept @ %p\n", epts);
720 memset(epts, 0, 32 * sizeof(struct ept_queue_head));
Ajay Dudanib01e5062011-12-03 23:23:42 -0800721 arch_clean_invalidate_cache_range((addr_t) epts,
722 32 * sizeof(struct ept_queue_head));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800723
Deepa Dinamani0bf2f442012-10-19 11:41:06 -0700724 writel((unsigned)PA((addr_t)epts), USB_ENDPOINTLISTADDR);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800725
Ajay Dudanib01e5062011-12-03 23:23:42 -0800726 /* select DEVICE mode */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800727 writel(0x02, USB_USBMODE);
728
729 writel(0xffffffff, USB_ENDPTFLUSH);
730 thread_sleep(20);
731
732 ep0out = _udc_endpoint_alloc(0, 0, 64);
733 ep0in = _udc_endpoint_alloc(0, 1, 64);
734 ep0req = udc_request_alloc();
Deepa Dinamani4f9db032013-03-15 13:17:16 -0700735 ep0req->buf = memalign(CACHE_LINE, ROUNDUP(4096, CACHE_LINE));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800736
737 {
738 /* create and register a language table descriptor */
739 /* language 0x0409 is US English */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800740 struct udc_descriptor *desc =
741 udc_descriptor_alloc(TYPE_STRING, 0, 4);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800742 desc->data[2] = 0x09;
743 desc->data[3] = 0x04;
744 udc_descriptor_register(desc);
745 }
Amol Jadi4421e652011-06-16 15:00:48 -0700746
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800747 the_device = dev;
748 return 0;
749}
750
751enum handler_return udc_interrupt(void *arg)
752{
753 struct udc_endpoint *ept;
754 unsigned ret = INT_NO_RESCHEDULE;
755 unsigned n = readl(USB_USBSTS);
756 writel(n, USB_USBSTS);
Amol Jadi4421e652011-06-16 15:00:48 -0700757
Amol Jadida118b92012-07-06 19:53:18 -0700758 DBG("\nudc_interrupt(): status = 0x%x\n", n);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800759
Amol Jadida118b92012-07-06 19:53:18 -0700760 n &= (STS_SLI | STS_URI | STS_PCI | STS_UI | STS_UEI);
Amol Jadi4421e652011-06-16 15:00:48 -0700761
762 if (n == 0) {
763 DBG("n = 0\n");
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800764 return ret;
Amol Jadi4421e652011-06-16 15:00:48 -0700765 }
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800766
767 if (n & STS_URI) {
Amol Jadi4421e652011-06-16 15:00:48 -0700768 DBG("STS_URI\n");
769
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800770 writel(readl(USB_ENDPTCOMPLETE), USB_ENDPTCOMPLETE);
771 writel(readl(USB_ENDPTSETUPSTAT), USB_ENDPTSETUPSTAT);
772 writel(0xffffffff, USB_ENDPTFLUSH);
773 writel(0, USB_ENDPTCTRL(1));
Amol Jadi4421e652011-06-16 15:00:48 -0700774 dprintf(INFO, "-- reset --\n");
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800775 usb_online = 0;
776 usb_config_value = 0;
777 the_gadget->notify(the_gadget, UDC_EVENT_OFFLINE);
778
779 /* error out any pending reqs */
780 for (ept = ept_list; ept; ept = ept->next) {
781 /* ensure that ept_complete considers
782 * this to be an error state
783 */
784 if (ept->req) {
785 ept->req->item->info = INFO_HALTED;
786 handle_ept_complete(ept);
787 }
788 }
789 usb_status(0, usb_highspeed);
790 }
791 if (n & STS_SLI) {
Ajay Dudani35f686f2011-07-22 13:12:09 -0700792 DBG("-- suspend --\n");
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800793 }
794 if (n & STS_PCI) {
Amol Jadi4421e652011-06-16 15:00:48 -0700795 dprintf(INFO, "-- portchange --\n");
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800796 unsigned spd = (readl(USB_PORTSC) >> 26) & 3;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800797 if (spd == 2) {
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800798 usb_highspeed = 1;
799 } else {
800 usb_highspeed = 0;
801 }
802 }
803 if (n & STS_UEI) {
Amol Jadi4421e652011-06-16 15:00:48 -0700804 DBG("STS_UEI\n");
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800805 dprintf(INFO, "<UEI %x>\n", readl(USB_ENDPTCOMPLETE));
806 }
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800807 if ((n & STS_UI) || (n & STS_UEI)) {
Amol Jadida118b92012-07-06 19:53:18 -0700808
809 if (n & STS_UEI)
810 DBG("ERROR ");
811 if (n & STS_UI)
812 DBG("USB ");
813
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800814 n = readl(USB_ENDPTSETUPSTAT);
815 if (n & EPT_RX(0)) {
816 handle_setup(ep0out);
817 ret = INT_RESCHEDULE;
818 }
819
820 n = readl(USB_ENDPTCOMPLETE);
821 if (n != 0) {
822 writel(n, USB_ENDPTCOMPLETE);
823 }
824
Ajay Dudanib01e5062011-12-03 23:23:42 -0800825 for (ept = ept_list; ept; ept = ept->next) {
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800826 if (n & ept->bit) {
827 handle_ept_complete(ept);
828 ret = INT_RESCHEDULE;
829 }
830 }
831 }
832 return ret;
833}
834
835int udc_register_gadget(struct udc_gadget *gadget)
836{
837 if (the_gadget) {
838 dprintf(CRITICAL, "only one gadget supported\n");
839 return -1;
840 }
841 the_gadget = gadget;
842 return 0;
843}
844
845static void udc_ept_desc_fill(struct udc_endpoint *ept, unsigned char *data)
846{
847 data[0] = 7;
848 data[1] = TYPE_ENDPOINT;
849 data[2] = ept->num | (ept->in ? 0x80 : 0x00);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800850 data[3] = 0x02; /* bulk -- the only kind we support */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800851 data[4] = ept->maxpkt;
852 data[5] = ept->maxpkt >> 8;
853 data[6] = ept->in ? 0x00 : 0x01;
854}
855
856static unsigned udc_ifc_desc_size(struct udc_gadget *g)
857{
858 return 9 + g->ifc_endpoints * 7;
859}
860
861static void udc_ifc_desc_fill(struct udc_gadget *g, unsigned char *data)
862{
863 unsigned n;
864
865 data[0] = 0x09;
866 data[1] = TYPE_INTERFACE;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800867 data[2] = 0x00; /* ifc number */
868 data[3] = 0x00; /* alt number */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800869 data[4] = g->ifc_endpoints;
870 data[5] = g->ifc_class;
871 data[6] = g->ifc_subclass;
872 data[7] = g->ifc_protocol;
873 data[8] = udc_string_desc_alloc(g->ifc_string);
874
875 data += 9;
876 for (n = 0; n < g->ifc_endpoints; n++) {
877 udc_ept_desc_fill(g->ept[n], data);
878 data += 7;
879 }
880}
881
882int udc_start(void)
883{
884 struct udc_descriptor *desc;
885 unsigned char *data;
886 unsigned size;
Amol Jadi71303ad2013-02-28 20:56:08 -0800887 uint32_t val;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800888
Chandan Uddaraju40b227d2010-08-03 19:25:41 -0700889 dprintf(ALWAYS, "udc_start()\n");
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800890
891 if (!the_device) {
892 dprintf(CRITICAL, "udc cannot start before init\n");
893 return -1;
894 }
895 if (!the_gadget) {
896 dprintf(CRITICAL, "udc has no gadget registered\n");
897 return -1;
898 }
899
900 /* create our device descriptor */
901 desc = udc_descriptor_alloc(TYPE_DEVICE, 0, 18);
902 data = desc->data;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800903 data[2] = 0x00; /* usb spec minor rev */
904 data[3] = 0x02; /* usb spec major rev */
905 data[4] = 0x00; /* class */
906 data[5] = 0x00; /* subclass */
907 data[6] = 0x00; /* protocol */
908 data[7] = 0x40; /* max packet size on ept 0 */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800909 memcpy(data + 8, &the_device->vendor_id, sizeof(short));
910 memcpy(data + 10, &the_device->product_id, sizeof(short));
911 memcpy(data + 12, &the_device->version_id, sizeof(short));
912 data[14] = udc_string_desc_alloc(the_device->manufacturer);
913 data[15] = udc_string_desc_alloc(the_device->product);
914 data[16] = udc_string_desc_alloc(the_device->serialno);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800915 data[17] = 1; /* number of configurations */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800916 udc_descriptor_register(desc);
917
918 /* create our configuration descriptor */
919 size = 9 + udc_ifc_desc_size(the_gadget);
920 desc = udc_descriptor_alloc(TYPE_CONFIGURATION, 0, size);
921 data = desc->data;
922 data[0] = 0x09;
923 data[2] = size;
924 data[3] = size >> 8;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800925 data[4] = 0x01; /* number of interfaces */
926 data[5] = 0x01; /* configuration value */
927 data[6] = 0x00; /* configuration string */
928 data[7] = 0x80; /* attributes */
929 data[8] = 0x80; /* max power (250ma) -- todo fix this */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800930 udc_ifc_desc_fill(the_gadget, data + 9);
931 udc_descriptor_register(desc);
932
Ajay Dudanib01e5062011-12-03 23:23:42 -0800933 register_int_handler(INT_USB_HS, udc_interrupt, (void *)0);
Amol Jadica4f4c92011-01-13 20:19:34 -0800934 writel(STS_URI | STS_SLI | STS_UI | STS_PCI, USB_USBINTR);
935 unmask_interrupt(INT_USB_HS);
936
Ajay Dudanib01e5062011-12-03 23:23:42 -0800937 /* go to RUN mode (D+ pullup enable) */
Amol Jadi71303ad2013-02-28 20:56:08 -0800938 val = readl(USB_USBCMD);
939
940 writel(val | 0x00080001, USB_USBCMD);
Amol Jadica4f4c92011-01-13 20:19:34 -0800941
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800942 return 0;
943}
944
945int udc_stop(void)
946{
Deepa Dinamani761cc952013-03-06 11:15:46 -0800947 uint32_t val;
948
949 /* Flush all primed end points. */
950 writel(0xffffffff, USB_ENDPTFLUSH);
951
952 /* Stop controller. */
953 val = readl(USB_USBCMD);
954 writel(val & ~USBCMD_ATTACH, USB_USBCMD);
955
956 /* Mask the interrupts. */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800957 writel(0, USB_USBINTR);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800958 mask_interrupt(INT_USB_HS);
959
Deepa Dinamani761cc952013-03-06 11:15:46 -0800960 /* Perform any target specific clean up. */
Amol Jadida118b92012-07-06 19:53:18 -0700961 target_usb_stop();
962
Deepa Dinamani761cc952013-03-06 11:15:46 -0800963 /* Reset the controller. */
964 writel(USBCMD_RESET, USB_USBCMD);
965 /* Wait until reset completes. */
966 while(readl(USB_USBCMD) & USBCMD_RESET);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800967
968 return 0;
969}