blob: 6a8e9e6d136cd1eb0ed6d041ca5225dce9c3bc0c [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
vijay kumar40030782015-05-26 16:18:49 +053049BUF_DMA_ALIGN(transfer_desc_item, ROUNDUP(sizeof(struct ept_queue_item), CACHE_LINE));
Hanumant Singh5322c742012-12-12 15:40:09 -080050
Brian Swetland3e7e21a2009-01-19 19:41:24 -080051/* common code - factor out into a shared file */
52
53struct udc_descriptor {
54 struct udc_descriptor *next;
Ajay Dudanib01e5062011-12-03 23:23:42 -080055 unsigned short tag; /* ((TYPE << 8) | NUM) */
56 unsigned short len; /* total length */
Brian Swetland3e7e21a2009-01-19 19:41:24 -080057 unsigned char data[0];
58};
59
Ajay Dudanib01e5062011-12-03 23:23:42 -080060struct udc_descriptor *udc_descriptor_alloc(unsigned type, unsigned num,
61 unsigned len)
Brian Swetland3e7e21a2009-01-19 19:41:24 -080062{
63 struct udc_descriptor *desc;
64 if ((len > 255) || (len < 2) || (num > 255) || (type > 255))
65 return 0;
66
Channagoud Kadabid4e24512015-07-22 11:30:47 -070067 desc = malloc(sizeof(struct udc_descriptor) + len);
68 ASSERT(desc);
Brian Swetland3e7e21a2009-01-19 19:41:24 -080069
70 desc->next = 0;
71 desc->tag = (type << 8) | num;
72 desc->len = len;
73 desc->data[0] = len;
74 desc->data[1] = type;
75
76 return desc;
77}
78
79static struct udc_descriptor *desc_list = 0;
80static unsigned next_string_id = 1;
81
82void udc_descriptor_register(struct udc_descriptor *desc)
83{
84 desc->next = desc_list;
85 desc_list = desc;
86}
87
88unsigned udc_string_desc_alloc(const char *str)
89{
90 unsigned len;
91 struct udc_descriptor *desc;
92 unsigned char *data;
93
94 if (next_string_id > 255)
95 return 0;
96
97 if (!str)
98 return 0;
99
100 len = strlen(str);
101 desc = udc_descriptor_alloc(TYPE_STRING, next_string_id, len * 2 + 2);
102 if (!desc)
103 return 0;
104 next_string_id++;
105
106 /* expand ascii string to utf16 */
107 data = desc->data + 2;
108 while (len-- > 0) {
109 *data++ = *str++;
110 *data++ = 0;
111 }
112
113 udc_descriptor_register(desc);
114 return desc->tag & 0xff;
115}
116
117/* end of common code */
118
Ajay Dudani7d605522010-10-01 19:52:37 -0700119__WEAK void hsusb_clock_init(void)
120{
Greg Griscod6250552011-06-29 14:40:23 -0700121 return;
Ajay Dudani7d605522010-10-01 19:52:37 -0700122}
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800123
124#if 1
125#define DBG(x...) do {} while(0)
126#else
Amol Jadida118b92012-07-06 19:53:18 -0700127#define DBG(x...) dprintf(ALWAYS, x)
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800128#endif
129
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800130#define usb_status(a,b)
131
132struct usb_request {
133 struct udc_request req;
134 struct ept_queue_item *item;
135};
Amol Jadi4421e652011-06-16 15:00:48 -0700136
Ajay Dudanib01e5062011-12-03 23:23:42 -0800137struct udc_endpoint {
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800138 struct udc_endpoint *next;
139 unsigned bit;
140 struct ept_queue_head *head;
141 struct usb_request *req;
142 unsigned char num;
143 unsigned char in;
144 unsigned short maxpkt;
145};
146
147struct udc_endpoint *ept_list = 0;
148struct ept_queue_head *epts = 0;
149
150static int usb_online = 0;
151static int usb_highspeed = 0;
152
153static struct udc_device *the_device;
154static struct udc_gadget *the_gadget;
Shashank Mittal2523e0b2011-10-14 17:32:46 -0700155static unsigned test_mode = 0;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800156
Ajay Dudanib01e5062011-12-03 23:23:42 -0800157struct udc_endpoint *_udc_endpoint_alloc(unsigned num, unsigned in,
158 unsigned max_pkt)
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800159{
160 struct udc_endpoint *ept;
161 unsigned cfg;
162
Hanumant Singh9d519092012-12-06 21:59:52 -0800163 ept = memalign(CACHE_LINE, ROUNDUP(sizeof(*ept), CACHE_LINE));
Lijuan Gaodc077222014-07-18 16:43:18 +0800164 ASSERT(ept);
Amol Jadi4421e652011-06-16 15:00:48 -0700165
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800166 ept->maxpkt = max_pkt;
167 ept->num = num;
168 ept->in = !!in;
169 ept->req = 0;
170
171 cfg = CONFIG_MAX_PKT(max_pkt) | CONFIG_ZLT;
172
Ajay Dudanib01e5062011-12-03 23:23:42 -0800173 if (ept->in) {
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800174 ept->bit = EPT_TX(ept->num);
175 } else {
176 ept->bit = EPT_RX(ept->num);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800177 if (num == 0)
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800178 cfg |= CONFIG_IOS;
179 }
180
181 ept->head = epts + (num * 2) + (ept->in);
182 ept->head->config = cfg;
183
184 ept->next = ept_list;
185 ept_list = ept;
Amol Jadi4421e652011-06-16 15:00:48 -0700186
Matthew Qinc7447202015-02-03 17:45:17 +0800187 arch_clean_invalidate_cache_range((addr_t) ept,
188 sizeof(struct udc_endpoint));
189 arch_clean_invalidate_cache_range((addr_t) ept->head,
190 sizeof(struct ept_queue_head));
191
Amol Jadi4421e652011-06-16 15:00:48 -0700192 DBG("ept%d %s @%p/%p max=%d bit=%x\n",
Ajay Dudanib01e5062011-12-03 23:23:42 -0800193 num, in ? "in" : "out", ept, ept->head, max_pkt, ept->bit);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800194
195 return ept;
196}
197
198static unsigned ept_alloc_table = EPT_TX(0) | EPT_RX(0);
199
200struct udc_endpoint *udc_endpoint_alloc(unsigned type, unsigned maxpkt)
201{
202 struct udc_endpoint *ept;
203 unsigned n;
204 unsigned in;
205
206 if (type == UDC_TYPE_BULK_IN) {
207 in = 1;
208 } else if (type == UDC_TYPE_BULK_OUT) {
209 in = 0;
210 } else {
211 return 0;
212 }
213
214 for (n = 1; n < 16; n++) {
215 unsigned bit = in ? EPT_TX(n) : EPT_RX(n);
216 if (ept_alloc_table & bit)
217 continue;
218 ept = _udc_endpoint_alloc(n, in, maxpkt);
219 if (ept)
220 ept_alloc_table |= bit;
221 return ept;
222 }
223 return 0;
224}
225
226void udc_endpoint_free(struct udc_endpoint *ept)
227{
228 /* todo */
229}
230
231static void endpoint_enable(struct udc_endpoint *ept, unsigned yes)
232{
233 unsigned n = readl(USB_ENDPTCTRL(ept->num));
234
Ajay Dudanib01e5062011-12-03 23:23:42 -0800235 if (yes) {
236 if (ept->in) {
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800237 n |= (CTRL_TXE | CTRL_TXR | CTRL_TXT_BULK);
238 } else {
239 n |= (CTRL_RXE | CTRL_RXR | CTRL_RXT_BULK);
240 }
241
Ajay Dudanib01e5062011-12-03 23:23:42 -0800242 if (ept->num != 0) {
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800243 /* XXX should be more dynamic... */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800244 if (usb_highspeed) {
245 ept->head->config =
246 CONFIG_MAX_PKT(512) | CONFIG_ZLT;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800247 } else {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800248 ept->head->config =
249 CONFIG_MAX_PKT(64) | CONFIG_ZLT;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800250 }
251 }
252 }
253 writel(n, USB_ENDPTCTRL(ept->num));
254}
255
256struct udc_request *udc_request_alloc(void)
257{
258 struct usb_request *req;
Hanumant Singh9d519092012-12-06 21:59:52 -0800259 req = memalign(CACHE_LINE, ROUNDUP(sizeof(*req), CACHE_LINE));
Lijuan Gaodc077222014-07-18 16:43:18 +0800260 ASSERT(req);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800261 req->req.buf = 0;
262 req->req.length = 0;
Hanumant Singh9d519092012-12-06 21:59:52 -0800263 req->item = memalign(CACHE_LINE, ROUNDUP(sizeof(struct ept_queue_item),
264 CACHE_LINE));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800265 return &req->req;
266}
267
268void udc_request_free(struct udc_request *req)
269{
270 free(req);
271}
272
Hanumant Singh5322c742012-12-12 15:40:09 -0800273/*
274 * Assumes that TDs allocated already are not freed.
275 * But it can handle case where TDs are freed as well.
276 */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800277int udc_request_queue(struct udc_endpoint *ept, struct udc_request *_req)
278{
Hanumant Singh5322c742012-12-12 15:40:09 -0800279 unsigned xfer = 0;
280 struct ept_queue_item *item, *curr_item;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800281 struct usb_request *req = (struct usb_request *)_req;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800282 unsigned phys = (unsigned)req->req.buf;
Hanumant Singh5322c742012-12-12 15:40:09 -0800283 unsigned len = req->req.length;
Amol Jadi4421e652011-06-16 15:00:48 -0700284
Hanumant Singh5322c742012-12-12 15:40:09 -0800285 xfer = (len > MAX_TD_XFER_SIZE) ? MAX_TD_XFER_SIZE : len;
286 /*
287 * First TD allocated during request allocation
288 */
vijay kumar40030782015-05-26 16:18:49 +0530289 curr_item = req->item;
290 curr_item->info = INFO_BYTES(xfer) | INFO_ACTIVE;
291 curr_item->page0 = phys;
292 curr_item->page1 = (phys & 0xfffff000) + 0x1000;
293 curr_item->page2 = (phys & 0xfffff000) + 0x2000;
294 curr_item->page3 = (phys & 0xfffff000) + 0x3000;
295 curr_item->page4 = (phys & 0xfffff000) + 0x4000;
Hanumant Singh5322c742012-12-12 15:40:09 -0800296 phys += xfer;
Hanumant Singh5322c742012-12-12 15:40:09 -0800297 len -= xfer;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800298
Hanumant Singh5322c742012-12-12 15:40:09 -0800299 /*
300 * If transfer length is more then
301 * accomodate by 1 TD
302 * we add more transfer descriptors
303 */
304 while (len > 0) {
305 xfer = (len > MAX_TD_XFER_SIZE) ? MAX_TD_XFER_SIZE : len;
306 if (curr_item->next == TERMINATE) {
vijay kumar40030782015-05-26 16:18:49 +0530307 curr_item->next = PA((addr_t)transfer_desc_item);
308 item = (struct ept_queue_item *)transfer_desc_item;
Hanumant Singh5322c742012-12-12 15:40:09 -0800309 item->next = TERMINATE;
Hanumant Singh5322c742012-12-12 15:40:09 -0800310 } else
311 /* Since next TD in chain already exists */
vijay kumar4f4405f2014-08-08 11:49:53 +0530312 item = (struct ept_queue_item *)VA(curr_item->next);
Hanumant Singh5322c742012-12-12 15:40:09 -0800313
314 /* Update TD with transfer information */
315 item->info = INFO_BYTES(xfer) | INFO_ACTIVE;
316 item->page0 = phys;
317 item->page1 = (phys & 0xfffff000) + 0x1000;
318 item->page2 = (phys & 0xfffff000) + 0x2000;
319 item->page3 = (phys & 0xfffff000) + 0x3000;
320 item->page4 = (phys & 0xfffff000) + 0x4000;
321
322 curr_item = item;
323 len -= xfer;
324 phys += xfer;
325 }
326
327 /* Terminate and set interrupt for last TD */
328 curr_item->next = TERMINATE;
329 curr_item->info |= INFO_IOC;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800330 enter_critical_section();
vijay kumar4f4405f2014-08-08 11:49:53 +0530331 ept->head->next = PA((addr_t)req->item);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800332 ept->head->info = 0;
333 ept->req = req;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800334 arch_clean_invalidate_cache_range((addr_t) ept,
335 sizeof(struct udc_endpoint));
336 arch_clean_invalidate_cache_range((addr_t) ept->head,
337 sizeof(struct ept_queue_head));
338 arch_clean_invalidate_cache_range((addr_t) ept->req,
339 sizeof(struct usb_request));
vijay kumar4f4405f2014-08-08 11:49:53 +0530340 arch_clean_invalidate_cache_range((addr_t) VA((addr_t)req->req.buf),
Ajay Dudanib01e5062011-12-03 23:23:42 -0800341 req->req.length);
Hanumant Singh5322c742012-12-12 15:40:09 -0800342
343 item = req->item;
344 /* Write all TD's to memory from cache */
345 while (item != NULL) {
346 curr_item = item;
347 if (curr_item->next == TERMINATE)
348 item = NULL;
349 else
vijay kumar4f4405f2014-08-08 11:49:53 +0530350 item = (struct ept_queue_item *)curr_item->next;
Hanumant Singh5322c742012-12-12 15:40:09 -0800351 arch_clean_invalidate_cache_range((addr_t) curr_item,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800352 sizeof(struct ept_queue_item));
Hanumant Singh5322c742012-12-12 15:40:09 -0800353 }
Amol Jadi4421e652011-06-16 15:00:48 -0700354
Ajay Dudanib01e5062011-12-03 23:23:42 -0800355 DBG("ept%d %s queue req=%p\n", ept->num, ept->in ? "in" : "out", req);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800356 writel(ept->bit, USB_ENDPTPRIME);
357 exit_critical_section();
358 return 0;
359}
360
361static void handle_ept_complete(struct udc_endpoint *ept)
362{
363 struct ept_queue_item *item;
Hanumant Singh5322c742012-12-12 15:40:09 -0800364 unsigned actual, total_len;
vijay kumar4f4405f2014-08-08 11:49:53 +0530365 int status;
Sundarajan Srinivasanafc69282013-11-19 14:07:03 -0800366 struct usb_request *req=NULL;
Amol Jadi4421e652011-06-16 15:00:48 -0700367
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800368 DBG("ept%d %s complete req=%p\n",
Ajay Dudanib01e5062011-12-03 23:23:42 -0800369 ept->num, ept->in ? "in" : "out", ept->req);
Amol Jadi4421e652011-06-16 15:00:48 -0700370
Hanumant Singh5322c742012-12-12 15:40:09 -0800371 arch_invalidate_cache_range((addr_t) ept,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800372 sizeof(struct udc_endpoint));
Sundarajan Srinivasanafc69282013-11-19 14:07:03 -0800373
374 if(ept->req)
375 {
vijay kumar4f4405f2014-08-08 11:49:53 +0530376 req = (struct usb_request *)VA((addr_t)ept->req);
Sundarajan Srinivasanafc69282013-11-19 14:07:03 -0800377 arch_invalidate_cache_range((addr_t) ept->req,
378 sizeof(struct usb_request));
379 }
Amol Jadi4421e652011-06-16 15:00:48 -0700380
Ajay Dudanib01e5062011-12-03 23:23:42 -0800381 if (req) {
vijay kumar4f4405f2014-08-08 11:49:53 +0530382 item = (struct ept_queue_item *)VA((addr_t)req->item);
Hanumant Singh5322c742012-12-12 15:40:09 -0800383 /* total transfer length for transacation */
384 total_len = req->req.length;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800385 ept->req = 0;
Hanumant Singh5322c742012-12-12 15:40:09 -0800386 actual = 0;
387 while(1) {
Amol Jadi4421e652011-06-16 15:00:48 -0700388
Hanumant Singh5322c742012-12-12 15:40:09 -0800389 do {
390 /*
391 * Must clean/invalidate cached item
392 * data before checking the status
393 * every time.
394 */
395 arch_invalidate_cache_range((addr_t)(item),
396 sizeof(
397 struct ept_queue_item));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800398
Hanumant Singh5322c742012-12-12 15:40:09 -0800399 } while(readl(&item->info) & INFO_ACTIVE);
400
401 if ((item->info) & 0xff) {
402 /* error */
403 status = -1;
404 dprintf(INFO, "EP%d/%s FAIL nfo=%x pg0=%x\n",
405 ept->num, ept->in ? "in" : "out",
406 item->info,
407 item->page0);
408 goto out;
409 }
410
411 /* Check if we are processing last TD */
412 if (item->next == TERMINATE) {
413 /*
414 * Record the data transferred for the last TD
415 */
vijay kumar4f4405f2014-08-08 11:49:53 +0530416 actual += (total_len - (item->info >> 16))
Hanumant Singh5322c742012-12-12 15:40:09 -0800417 & 0x7FFF;
418 total_len = 0;
419 break;
420 } else {
421 /*
422 * Since we are not in last TD
423 * the total assumed transfer ascribed to this
424 * TD woulb the max possible TD transfer size
425 * (16K)
426 */
vijay kumar4f4405f2014-08-08 11:49:53 +0530427 actual += (MAX_TD_XFER_SIZE - (item->info >> 16)) & 0x7FFF;
428 total_len -= (MAX_TD_XFER_SIZE - (item->info >> 16)) & 0x7FFF;
Hanumant Singh5322c742012-12-12 15:40:09 -0800429 /*Move to next item in chain*/
vijay kumar4f4405f2014-08-08 11:49:53 +0530430 item = (struct ept_queue_item *)VA(item->next);
Hanumant Singh5322c742012-12-12 15:40:09 -0800431 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800432 }
Hanumant Singh5322c742012-12-12 15:40:09 -0800433 status = 0;
434out:
Ajay Dudanib01e5062011-12-03 23:23:42 -0800435 if (req->req.complete)
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800436 req->req.complete(&req->req, actual, status);
437 }
438}
439
440static const char *reqname(unsigned r)
441{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800442 switch (r) {
443 case GET_STATUS:
444 return "GET_STATUS";
445 case CLEAR_FEATURE:
446 return "CLEAR_FEATURE";
447 case SET_FEATURE:
448 return "SET_FEATURE";
449 case SET_ADDRESS:
450 return "SET_ADDRESS";
451 case GET_DESCRIPTOR:
452 return "GET_DESCRIPTOR";
453 case SET_DESCRIPTOR:
454 return "SET_DESCRIPTOR";
455 case GET_CONFIGURATION:
456 return "GET_CONFIGURATION";
457 case SET_CONFIGURATION:
458 return "SET_CONFIGURATION";
459 case GET_INTERFACE:
460 return "GET_INTERFACE";
461 case SET_INTERFACE:
462 return "SET_INTERFACE";
463 default:
464 return "*UNKNOWN*";
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800465 }
466}
467
468static struct udc_endpoint *ep0in, *ep0out;
469static struct udc_request *ep0req;
470
Ajay Dudanib01e5062011-12-03 23:23:42 -0800471static void
vijay kumar9c9f1cf2014-01-15 16:05:28 +0530472ep0_setup_ack_complete()
Shashank Mittal2523e0b2011-10-14 17:32:46 -0700473{
474 uint32_t mode;
475
Ajay Dudanib01e5062011-12-03 23:23:42 -0800476 if (!test_mode)
Shashank Mittal2523e0b2011-10-14 17:32:46 -0700477 return;
478
Ajay Dudanib01e5062011-12-03 23:23:42 -0800479 switch (test_mode) {
480 case TEST_PACKET:
481 dprintf(INFO, "Entering test mode for TST_PKT\n");
482 mode = readl(USB_PORTSC) & (~PORTSC_PTC);
483 writel(mode | PORTSC_PTC_TST_PKT, USB_PORTSC);
484 break;
Shashank Mittal2523e0b2011-10-14 17:32:46 -0700485
Ajay Dudanib01e5062011-12-03 23:23:42 -0800486 case TEST_SE0_NAK:
487 dprintf(INFO, "Entering test mode for SE0-NAK\n");
488 mode = readl(USB_PORTSC) & (~PORTSC_PTC);
489 writel(mode | PORTSC_PTC_SE0_NAK, USB_PORTSC);
490 break;
Shashank Mittal2523e0b2011-10-14 17:32:46 -0700491 }
492
493}
494
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800495static void setup_ack(void)
496{
Shashank Mittal2523e0b2011-10-14 17:32:46 -0700497 ep0req->complete = ep0_setup_ack_complete;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800498 ep0req->length = 0;
499 udc_request_queue(ep0in, ep0req);
500}
501
502static void ep0in_complete(struct udc_request *req, unsigned actual, int status)
503{
504 DBG("ep0in_complete %p %d %d\n", req, actual, status);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800505 if (status == 0) {
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800506 req->length = 0;
507 req->complete = 0;
508 udc_request_queue(ep0out, req);
509 }
510}
511
512static void setup_tx(void *buf, unsigned len)
513{
514 DBG("setup_tx %p %d\n", buf, len);
515 memcpy(ep0req->buf, buf, len);
vijay kumar4f4405f2014-08-08 11:49:53 +0530516 ep0req->buf = (void *)PA((addr_t)ep0req->buf);
Matthew Qinc7447202015-02-03 17:45:17 +0800517 arch_clean_invalidate_cache_range((addr_t)ep0req->buf, len);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800518 ep0req->complete = ep0in_complete;
519 ep0req->length = len;
520 udc_request_queue(ep0in, ep0req);
521}
522
523static unsigned char usb_config_value = 0;
524
525#define SETUP(type,request) (((type) << 8) | (request))
526
527static void handle_setup(struct udc_endpoint *ept)
528{
529 struct setup_packet s;
Amol Jadi4421e652011-06-16 15:00:48 -0700530
Ajay Dudanib01e5062011-12-03 23:23:42 -0800531 arch_clean_invalidate_cache_range((addr_t) ept->head->setup_data,
532 sizeof(struct ept_queue_head));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800533 memcpy(&s, ept->head->setup_data, sizeof(s));
Matthew Qinc7447202015-02-03 17:45:17 +0800534 arch_clean_invalidate_cache_range((addr_t)&s, sizeof(s));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800535 writel(ept->bit, USB_ENDPTSETUPSTAT);
536
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800537 DBG("handle_setup type=0x%02x req=0x%02x val=%d idx=%d len=%d (%s)\n",
Ajay Dudanib01e5062011-12-03 23:23:42 -0800538 s.type, s.request, s.value, s.index, s.length, reqname(s.request));
Amol Jadi4421e652011-06-16 15:00:48 -0700539
Ajay Dudanib01e5062011-12-03 23:23:42 -0800540 switch (SETUP(s.type, s.request)) {
541 case SETUP(DEVICE_READ, GET_STATUS):
542 {
543 unsigned zero = 0;
544 if (s.length == 2) {
545 setup_tx(&zero, 2);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800546 return;
547 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800548 break;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800549 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800550 case SETUP(DEVICE_READ, GET_DESCRIPTOR):
551 {
552 struct udc_descriptor *desc;
vijay kumarb8639052015-03-09 17:37:31 +0530553 unsigned char* data = NULL;
554 unsigned n;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800555 /* usb_highspeed? */
556 for (desc = desc_list; desc; desc = desc->next) {
557 if (desc->tag == s.value) {
vijay kumarb8639052015-03-09 17:37:31 +0530558 /*Check for configuration type of descriptor*/
559 if (desc->tag == (TYPE_CONFIGURATION << 8)) {
560 data = desc->data;
561 data+= 9; /* skip config desc */
562 data+= 9; /* skip interface desc */
563 /* taking the max packet size based on the USB host speed connected */
564 for (n = 0; n < 2; n++) {
565 data[4] = usb_highspeed ? 512:64;
566 data[5] = (usb_highspeed ? 512:64)>>8;
567 data += 7;
568 }
569 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800570 unsigned len = desc->len;
571 if (len > s.length)
572 len = s.length;
573 setup_tx(desc->data, len);
574 return;
575 }
576 }
577 break;
578 }
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800579 case SETUP(DEVICE_READ, GET_CONFIGURATION):
580 /* disabling this causes data transaction failures on OSX. Why? */
581 if ((s.value == 0) && (s.index == 0) && (s.length == 1)) {
582 setup_tx(&usb_config_value, 1);
583 return;
584 }
585 break;
586 case SETUP(DEVICE_WRITE, SET_CONFIGURATION):
587 if (s.value == 1) {
588 struct udc_endpoint *ept;
589 /* enable endpoints */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800590 for (ept = ept_list; ept; ept = ept->next) {
Amol Jadi4421e652011-06-16 15:00:48 -0700591 if (ept->num == 0)
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800592 continue;
593 endpoint_enable(ept, s.value);
594 }
595 usb_config_value = 1;
596 the_gadget->notify(the_gadget, UDC_EVENT_ONLINE);
597 } else {
598 writel(0, USB_ENDPTCTRL(1));
599 usb_config_value = 0;
600 the_gadget->notify(the_gadget, UDC_EVENT_OFFLINE);
601 }
602 setup_ack();
603 usb_online = s.value ? 1 : 0;
604 usb_status(s.value ? 1 : 0, usb_highspeed);
605 return;
606 case SETUP(DEVICE_WRITE, SET_ADDRESS):
607 /* write address delayed (will take effect
Ajay Dudanib01e5062011-12-03 23:23:42 -0800608 ** after the next IN txn)
609 */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800610 writel((s.value << 25) | (1 << 24), USB_DEVICEADDR);
611 setup_ack();
612 return;
613 case SETUP(INTERFACE_WRITE, SET_INTERFACE):
614 /* if we ack this everything hangs */
615 /* per spec, STALL is valid if there is not alt func */
616 goto stall;
Subbaraman Narayanamurthyd8b7afc2011-06-30 15:42:41 -0700617 case SETUP(DEVICE_WRITE, SET_FEATURE):
Shashank Mittal2523e0b2011-10-14 17:32:46 -0700618 test_mode = s.index;
Subbaraman Narayanamurthyd8b7afc2011-06-30 15:42:41 -0700619 setup_ack();
Subbaraman Narayanamurthyd8b7afc2011-06-30 15:42:41 -0700620 return;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800621 case SETUP(ENDPOINT_WRITE, CLEAR_FEATURE):
622 {
623 struct udc_endpoint *ept;
624 unsigned num = s.index & 15;
625 unsigned in = !!(s.index & 0x80);
Amol Jadi4421e652011-06-16 15:00:48 -0700626
Ajay Dudanib01e5062011-12-03 23:23:42 -0800627 if ((s.value == 0) && (s.length == 0)) {
628 DBG("clr feat %d %d\n", num, in);
629 for (ept = ept_list; ept; ept = ept->next) {
630 if ((ept->num == num)
631 && (ept->in == in)) {
632 endpoint_enable(ept, 1);
633 setup_ack();
634 return;
635 }
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800636 }
637 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800638 break;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800639 }
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800640 }
641
642 dprintf(INFO, "STALL %s %d %d %d %d %d\n",
643 reqname(s.request),
644 s.type, s.request, s.value, s.index, s.length);
645
Ajay Dudanib01e5062011-12-03 23:23:42 -0800646 stall:
647 writel((1 << 16) | (1 << 0), USB_ENDPTCTRL(ept->num));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800648}
649
650unsigned ulpi_read(unsigned reg)
651{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800652 /* initiate read operation */
653 writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg), USB_ULPI_VIEWPORT);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800654
Ajay Dudanib01e5062011-12-03 23:23:42 -0800655 /* wait for completion */
656 while (readl(USB_ULPI_VIEWPORT) & ULPI_RUN) ;
Amol Jadi4421e652011-06-16 15:00:48 -0700657
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800658 return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
659}
660
661void ulpi_write(unsigned val, unsigned reg)
662{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800663 /* initiate write operation */
Amol Jadi4421e652011-06-16 15:00:48 -0700664 writel(ULPI_RUN | ULPI_WRITE |
Ajay Dudanib01e5062011-12-03 23:23:42 -0800665 ULPI_ADDR(reg) | ULPI_DATA(val), USB_ULPI_VIEWPORT);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800666
Ajay Dudanib01e5062011-12-03 23:23:42 -0800667 /* wait for completion */
668 while (readl(USB_ULPI_VIEWPORT) & ULPI_RUN) ;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800669}
Ajay Dudani5a1e3302009-12-05 13:19:17 -0800670
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800671
Amol Jadi4421e652011-06-16 15:00:48 -0700672int udc_init(struct udc_device *dev)
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800673{
Amol Jadi4421e652011-06-16 15:00:48 -0700674 DBG("udc_init():\n");
675
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800676 hsusb_clock_init();
677
Amol Jadida118b92012-07-06 19:53:18 -0700678 /* RESET */
Channagoud Kadabi50c92b12013-03-29 14:36:44 -0700679 writel(0x00080002, USB_USBCMD);
Amol Jadida118b92012-07-06 19:53:18 -0700680
681 thread_sleep(20);
Subbaraman Narayanamurthyb0111a12011-02-03 14:24:16 -0800682
Deepa Dinamani0687ecd2012-08-10 16:00:26 -0700683 while((readl(USB_USBCMD)&2));
684
685 /* select ULPI phy */
686 writel(0x80000000, USB_PORTSC);
687
Amol Jadi71303ad2013-02-28 20:56:08 -0800688 /* Do any target specific intialization like GPIO settings,
689 * LDO, PHY configuration etc. needed before USB port can be used.
690 */
691 target_usb_init();
692
693 /* USB_OTG_HS_AHB_BURST */
Deepa Dinamani0687ecd2012-08-10 16:00:26 -0700694 writel(0x0, USB_SBUSCFG);
695
696 /* USB_OTG_HS_AHB_MODE: HPROT_MODE */
697 /* Bus access related config. */
698 writel(0x08, USB_AHB_MODE);
699
Deepa Dinamani4f9db032013-03-15 13:17:16 -0700700 epts = memalign(lcm(4096, CACHE_LINE), ROUNDUP(4096, CACHE_LINE));
Lijuan Gaodc077222014-07-18 16:43:18 +0800701 ASSERT(epts);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800702
703 dprintf(INFO, "USB init ept @ %p\n", epts);
704 memset(epts, 0, 32 * sizeof(struct ept_queue_head));
Ajay Dudanib01e5062011-12-03 23:23:42 -0800705 arch_clean_invalidate_cache_range((addr_t) epts,
706 32 * sizeof(struct ept_queue_head));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800707
Deepa Dinamani0bf2f442012-10-19 11:41:06 -0700708 writel((unsigned)PA((addr_t)epts), USB_ENDPOINTLISTADDR);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800709
Ajay Dudanib01e5062011-12-03 23:23:42 -0800710 /* select DEVICE mode */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800711 writel(0x02, USB_USBMODE);
712
713 writel(0xffffffff, USB_ENDPTFLUSH);
714 thread_sleep(20);
715
716 ep0out = _udc_endpoint_alloc(0, 0, 64);
717 ep0in = _udc_endpoint_alloc(0, 1, 64);
718 ep0req = udc_request_alloc();
Deepa Dinamani4f9db032013-03-15 13:17:16 -0700719 ep0req->buf = memalign(CACHE_LINE, ROUNDUP(4096, CACHE_LINE));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800720
721 {
722 /* create and register a language table descriptor */
723 /* language 0x0409 is US English */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800724 struct udc_descriptor *desc =
725 udc_descriptor_alloc(TYPE_STRING, 0, 4);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800726 desc->data[2] = 0x09;
727 desc->data[3] = 0x04;
728 udc_descriptor_register(desc);
729 }
Amol Jadi4421e652011-06-16 15:00:48 -0700730
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800731 the_device = dev;
732 return 0;
733}
734
735enum handler_return udc_interrupt(void *arg)
736{
737 struct udc_endpoint *ept;
738 unsigned ret = INT_NO_RESCHEDULE;
739 unsigned n = readl(USB_USBSTS);
740 writel(n, USB_USBSTS);
Amol Jadi4421e652011-06-16 15:00:48 -0700741
Amol Jadida118b92012-07-06 19:53:18 -0700742 DBG("\nudc_interrupt(): status = 0x%x\n", n);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800743
Amol Jadida118b92012-07-06 19:53:18 -0700744 n &= (STS_SLI | STS_URI | STS_PCI | STS_UI | STS_UEI);
Amol Jadi4421e652011-06-16 15:00:48 -0700745
746 if (n == 0) {
747 DBG("n = 0\n");
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800748 return ret;
Amol Jadi4421e652011-06-16 15:00:48 -0700749 }
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800750
751 if (n & STS_URI) {
Amol Jadi4421e652011-06-16 15:00:48 -0700752 DBG("STS_URI\n");
753
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800754 writel(readl(USB_ENDPTCOMPLETE), USB_ENDPTCOMPLETE);
755 writel(readl(USB_ENDPTSETUPSTAT), USB_ENDPTSETUPSTAT);
756 writel(0xffffffff, USB_ENDPTFLUSH);
757 writel(0, USB_ENDPTCTRL(1));
Amol Jadi4421e652011-06-16 15:00:48 -0700758 dprintf(INFO, "-- reset --\n");
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800759 usb_online = 0;
760 usb_config_value = 0;
761 the_gadget->notify(the_gadget, UDC_EVENT_OFFLINE);
762
763 /* error out any pending reqs */
764 for (ept = ept_list; ept; ept = ept->next) {
765 /* ensure that ept_complete considers
766 * this to be an error state
767 */
768 if (ept->req) {
769 ept->req->item->info = INFO_HALTED;
770 handle_ept_complete(ept);
771 }
772 }
773 usb_status(0, usb_highspeed);
774 }
775 if (n & STS_SLI) {
Ajay Dudani35f686f2011-07-22 13:12:09 -0700776 DBG("-- suspend --\n");
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800777 }
778 if (n & STS_PCI) {
Amol Jadi4421e652011-06-16 15:00:48 -0700779 dprintf(INFO, "-- portchange --\n");
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800780 unsigned spd = (readl(USB_PORTSC) >> 26) & 3;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800781 if (spd == 2) {
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800782 usb_highspeed = 1;
783 } else {
784 usb_highspeed = 0;
785 }
786 }
787 if (n & STS_UEI) {
Amol Jadi4421e652011-06-16 15:00:48 -0700788 DBG("STS_UEI\n");
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800789 dprintf(INFO, "<UEI %x>\n", readl(USB_ENDPTCOMPLETE));
790 }
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800791 if ((n & STS_UI) || (n & STS_UEI)) {
Amol Jadida118b92012-07-06 19:53:18 -0700792
793 if (n & STS_UEI)
794 DBG("ERROR ");
795 if (n & STS_UI)
796 DBG("USB ");
797
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800798 n = readl(USB_ENDPTSETUPSTAT);
799 if (n & EPT_RX(0)) {
800 handle_setup(ep0out);
801 ret = INT_RESCHEDULE;
802 }
803
804 n = readl(USB_ENDPTCOMPLETE);
805 if (n != 0) {
806 writel(n, USB_ENDPTCOMPLETE);
807 }
808
Ajay Dudanib01e5062011-12-03 23:23:42 -0800809 for (ept = ept_list; ept; ept = ept->next) {
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800810 if (n & ept->bit) {
811 handle_ept_complete(ept);
812 ret = INT_RESCHEDULE;
813 }
814 }
815 }
816 return ret;
817}
818
819int udc_register_gadget(struct udc_gadget *gadget)
820{
821 if (the_gadget) {
822 dprintf(CRITICAL, "only one gadget supported\n");
823 return -1;
824 }
825 the_gadget = gadget;
826 return 0;
827}
828
829static void udc_ept_desc_fill(struct udc_endpoint *ept, unsigned char *data)
830{
831 data[0] = 7;
832 data[1] = TYPE_ENDPOINT;
833 data[2] = ept->num | (ept->in ? 0x80 : 0x00);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800834 data[3] = 0x02; /* bulk -- the only kind we support */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800835 data[4] = ept->maxpkt;
836 data[5] = ept->maxpkt >> 8;
837 data[6] = ept->in ? 0x00 : 0x01;
838}
839
840static unsigned udc_ifc_desc_size(struct udc_gadget *g)
841{
842 return 9 + g->ifc_endpoints * 7;
843}
844
845static void udc_ifc_desc_fill(struct udc_gadget *g, unsigned char *data)
846{
847 unsigned n;
848
849 data[0] = 0x09;
850 data[1] = TYPE_INTERFACE;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800851 data[2] = 0x00; /* ifc number */
852 data[3] = 0x00; /* alt number */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800853 data[4] = g->ifc_endpoints;
854 data[5] = g->ifc_class;
855 data[6] = g->ifc_subclass;
856 data[7] = g->ifc_protocol;
857 data[8] = udc_string_desc_alloc(g->ifc_string);
858
859 data += 9;
860 for (n = 0; n < g->ifc_endpoints; n++) {
861 udc_ept_desc_fill(g->ept[n], data);
862 data += 7;
863 }
864}
865
866int udc_start(void)
867{
868 struct udc_descriptor *desc;
869 unsigned char *data;
870 unsigned size;
Amol Jadi71303ad2013-02-28 20:56:08 -0800871 uint32_t val;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800872
Chandan Uddaraju40b227d2010-08-03 19:25:41 -0700873 dprintf(ALWAYS, "udc_start()\n");
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800874
875 if (!the_device) {
876 dprintf(CRITICAL, "udc cannot start before init\n");
877 return -1;
878 }
879 if (!the_gadget) {
880 dprintf(CRITICAL, "udc has no gadget registered\n");
881 return -1;
882 }
883
884 /* create our device descriptor */
Sridhar Parasuram08045f42015-06-22 14:19:38 -0700885 if(!(desc = udc_descriptor_alloc(TYPE_DEVICE, 0, 18)))
886 {
887 dprintf(CRITICAL, "Failed to allocate device descriptor\n");
888 ASSERT(0);
889 }
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800890 data = desc->data;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800891 data[2] = 0x00; /* usb spec minor rev */
892 data[3] = 0x02; /* usb spec major rev */
893 data[4] = 0x00; /* class */
894 data[5] = 0x00; /* subclass */
895 data[6] = 0x00; /* protocol */
896 data[7] = 0x40; /* max packet size on ept 0 */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800897 memcpy(data + 8, &the_device->vendor_id, sizeof(short));
898 memcpy(data + 10, &the_device->product_id, sizeof(short));
899 memcpy(data + 12, &the_device->version_id, sizeof(short));
900 data[14] = udc_string_desc_alloc(the_device->manufacturer);
901 data[15] = udc_string_desc_alloc(the_device->product);
902 data[16] = udc_string_desc_alloc(the_device->serialno);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800903 data[17] = 1; /* number of configurations */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800904 udc_descriptor_register(desc);
905
906 /* create our configuration descriptor */
907 size = 9 + udc_ifc_desc_size(the_gadget);
908 desc = udc_descriptor_alloc(TYPE_CONFIGURATION, 0, size);
909 data = desc->data;
910 data[0] = 0x09;
911 data[2] = size;
912 data[3] = size >> 8;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800913 data[4] = 0x01; /* number of interfaces */
914 data[5] = 0x01; /* configuration value */
915 data[6] = 0x00; /* configuration string */
916 data[7] = 0x80; /* attributes */
917 data[8] = 0x80; /* max power (250ma) -- todo fix this */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800918 udc_ifc_desc_fill(the_gadget, data + 9);
919 udc_descriptor_register(desc);
920
Ajay Dudanib01e5062011-12-03 23:23:42 -0800921 register_int_handler(INT_USB_HS, udc_interrupt, (void *)0);
Amol Jadica4f4c92011-01-13 20:19:34 -0800922 writel(STS_URI | STS_SLI | STS_UI | STS_PCI, USB_USBINTR);
923 unmask_interrupt(INT_USB_HS);
924
Ajay Dudanib01e5062011-12-03 23:23:42 -0800925 /* go to RUN mode (D+ pullup enable) */
Amol Jadi71303ad2013-02-28 20:56:08 -0800926 val = readl(USB_USBCMD);
927
928 writel(val | 0x00080001, USB_USBCMD);
Amol Jadica4f4c92011-01-13 20:19:34 -0800929
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800930 return 0;
931}
932
933int udc_stop(void)
934{
Deepa Dinamani761cc952013-03-06 11:15:46 -0800935 uint32_t val;
936
937 /* Flush all primed end points. */
938 writel(0xffffffff, USB_ENDPTFLUSH);
939
940 /* Stop controller. */
941 val = readl(USB_USBCMD);
942 writel(val & ~USBCMD_ATTACH, USB_USBCMD);
943
944 /* Mask the interrupts. */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800945 writel(0, USB_USBINTR);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800946 mask_interrupt(INT_USB_HS);
947
Deepa Dinamani761cc952013-03-06 11:15:46 -0800948 /* Perform any target specific clean up. */
Amol Jadida118b92012-07-06 19:53:18 -0700949 target_usb_stop();
950
Deepa Dinamani761cc952013-03-06 11:15:46 -0800951 /* Reset the controller. */
952 writel(USBCMD_RESET, USB_USBCMD);
953 /* Wait until reset completes. */
954 while(readl(USB_USBCMD) & USBCMD_RESET);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800955
956 return 0;
957}