blob: 9ebe36eef7f2ca4534570119d595c3df6106e3b9 [file] [log] [blame]
Brian Swetland3e7e21a2009-01-19 19:41:24 -08001/*
2 * Copyright (c) 2008, Google Inc.
3 * All rights reserved.
4 *
Gaurav Nebhwanief60f402016-05-25 11:53:01 +05305 * Copyright (c) 2009-2016, 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))
Gaurav Nebhwanief60f402016-05-25 11:53:01 +053065 {
66 dprintf(CRITICAL, "Invalid parameters for descriptor allocation\n");
67 ASSERT(0);
68 }
Brian Swetland3e7e21a2009-01-19 19:41:24 -080069
Channagoud Kadabid4e24512015-07-22 11:30:47 -070070 desc = malloc(sizeof(struct udc_descriptor) + len);
71 ASSERT(desc);
Brian Swetland3e7e21a2009-01-19 19:41:24 -080072
73 desc->next = 0;
74 desc->tag = (type << 8) | num;
75 desc->len = len;
76 desc->data[0] = len;
77 desc->data[1] = type;
78
79 return desc;
80}
81
82static struct udc_descriptor *desc_list = 0;
83static unsigned next_string_id = 1;
84
85void udc_descriptor_register(struct udc_descriptor *desc)
86{
87 desc->next = desc_list;
88 desc_list = desc;
89}
90
91unsigned udc_string_desc_alloc(const char *str)
92{
93 unsigned len;
94 struct udc_descriptor *desc;
95 unsigned char *data;
96
97 if (next_string_id > 255)
98 return 0;
99
100 if (!str)
101 return 0;
102
103 len = strlen(str);
104 desc = udc_descriptor_alloc(TYPE_STRING, next_string_id, len * 2 + 2);
105 if (!desc)
106 return 0;
107 next_string_id++;
108
109 /* expand ascii string to utf16 */
110 data = desc->data + 2;
111 while (len-- > 0) {
112 *data++ = *str++;
113 *data++ = 0;
114 }
115
116 udc_descriptor_register(desc);
117 return desc->tag & 0xff;
118}
119
120/* end of common code */
121
Ajay Dudani7d605522010-10-01 19:52:37 -0700122__WEAK void hsusb_clock_init(void)
123{
Greg Griscod6250552011-06-29 14:40:23 -0700124 return;
Ajay Dudani7d605522010-10-01 19:52:37 -0700125}
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800126
127#if 1
128#define DBG(x...) do {} while(0)
129#else
Amol Jadida118b92012-07-06 19:53:18 -0700130#define DBG(x...) dprintf(ALWAYS, x)
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800131#endif
132
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800133#define usb_status(a,b)
134
135struct usb_request {
136 struct udc_request req;
137 struct ept_queue_item *item;
138};
Amol Jadi4421e652011-06-16 15:00:48 -0700139
Ajay Dudanib01e5062011-12-03 23:23:42 -0800140struct udc_endpoint {
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800141 struct udc_endpoint *next;
142 unsigned bit;
143 struct ept_queue_head *head;
144 struct usb_request *req;
145 unsigned char num;
146 unsigned char in;
147 unsigned short maxpkt;
148};
149
150struct udc_endpoint *ept_list = 0;
151struct ept_queue_head *epts = 0;
152
153static int usb_online = 0;
154static int usb_highspeed = 0;
155
156static struct udc_device *the_device;
157static struct udc_gadget *the_gadget;
Shashank Mittal2523e0b2011-10-14 17:32:46 -0700158static unsigned test_mode = 0;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800159
Ajay Dudanib01e5062011-12-03 23:23:42 -0800160struct udc_endpoint *_udc_endpoint_alloc(unsigned num, unsigned in,
161 unsigned max_pkt)
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800162{
163 struct udc_endpoint *ept;
164 unsigned cfg;
165
Hanumant Singh9d519092012-12-06 21:59:52 -0800166 ept = memalign(CACHE_LINE, ROUNDUP(sizeof(*ept), CACHE_LINE));
Lijuan Gaodc077222014-07-18 16:43:18 +0800167 ASSERT(ept);
Amol Jadi4421e652011-06-16 15:00:48 -0700168
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800169 ept->maxpkt = max_pkt;
170 ept->num = num;
171 ept->in = !!in;
172 ept->req = 0;
173
174 cfg = CONFIG_MAX_PKT(max_pkt) | CONFIG_ZLT;
175
Ajay Dudanib01e5062011-12-03 23:23:42 -0800176 if (ept->in) {
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800177 ept->bit = EPT_TX(ept->num);
178 } else {
179 ept->bit = EPT_RX(ept->num);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800180 if (num == 0)
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800181 cfg |= CONFIG_IOS;
182 }
183
184 ept->head = epts + (num * 2) + (ept->in);
185 ept->head->config = cfg;
186
187 ept->next = ept_list;
188 ept_list = ept;
Amol Jadi4421e652011-06-16 15:00:48 -0700189
Matthew Qinc7447202015-02-03 17:45:17 +0800190 arch_clean_invalidate_cache_range((addr_t) ept,
191 sizeof(struct udc_endpoint));
192 arch_clean_invalidate_cache_range((addr_t) ept->head,
193 sizeof(struct ept_queue_head));
194
Amol Jadi4421e652011-06-16 15:00:48 -0700195 DBG("ept%d %s @%p/%p max=%d bit=%x\n",
Ajay Dudanib01e5062011-12-03 23:23:42 -0800196 num, in ? "in" : "out", ept, ept->head, max_pkt, ept->bit);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800197
198 return ept;
199}
200
201static unsigned ept_alloc_table = EPT_TX(0) | EPT_RX(0);
202
203struct udc_endpoint *udc_endpoint_alloc(unsigned type, unsigned maxpkt)
204{
205 struct udc_endpoint *ept;
206 unsigned n;
207 unsigned in;
208
209 if (type == UDC_TYPE_BULK_IN) {
210 in = 1;
211 } else if (type == UDC_TYPE_BULK_OUT) {
212 in = 0;
213 } else {
214 return 0;
215 }
216
217 for (n = 1; n < 16; n++) {
218 unsigned bit = in ? EPT_TX(n) : EPT_RX(n);
219 if (ept_alloc_table & bit)
220 continue;
221 ept = _udc_endpoint_alloc(n, in, maxpkt);
222 if (ept)
223 ept_alloc_table |= bit;
224 return ept;
225 }
226 return 0;
227}
228
229void udc_endpoint_free(struct udc_endpoint *ept)
230{
231 /* todo */
232}
233
234static void endpoint_enable(struct udc_endpoint *ept, unsigned yes)
235{
236 unsigned n = readl(USB_ENDPTCTRL(ept->num));
237
Ajay Dudanib01e5062011-12-03 23:23:42 -0800238 if (yes) {
239 if (ept->in) {
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800240 n |= (CTRL_TXE | CTRL_TXR | CTRL_TXT_BULK);
241 } else {
242 n |= (CTRL_RXE | CTRL_RXR | CTRL_RXT_BULK);
243 }
244
Ajay Dudanib01e5062011-12-03 23:23:42 -0800245 if (ept->num != 0) {
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800246 /* XXX should be more dynamic... */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800247 if (usb_highspeed) {
248 ept->head->config =
249 CONFIG_MAX_PKT(512) | CONFIG_ZLT;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800250 } else {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800251 ept->head->config =
252 CONFIG_MAX_PKT(64) | CONFIG_ZLT;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800253 }
254 }
255 }
256 writel(n, USB_ENDPTCTRL(ept->num));
257}
258
259struct udc_request *udc_request_alloc(void)
260{
261 struct usb_request *req;
Hanumant Singh9d519092012-12-06 21:59:52 -0800262 req = memalign(CACHE_LINE, ROUNDUP(sizeof(*req), CACHE_LINE));
Lijuan Gaodc077222014-07-18 16:43:18 +0800263 ASSERT(req);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800264 req->req.buf = 0;
265 req->req.length = 0;
Hanumant Singh9d519092012-12-06 21:59:52 -0800266 req->item = memalign(CACHE_LINE, ROUNDUP(sizeof(struct ept_queue_item),
267 CACHE_LINE));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800268 return &req->req;
269}
270
271void udc_request_free(struct udc_request *req)
272{
273 free(req);
274}
275
Hanumant Singh5322c742012-12-12 15:40:09 -0800276/*
277 * Assumes that TDs allocated already are not freed.
278 * But it can handle case where TDs are freed as well.
279 */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800280int udc_request_queue(struct udc_endpoint *ept, struct udc_request *_req)
281{
Hanumant Singh5322c742012-12-12 15:40:09 -0800282 unsigned xfer = 0;
283 struct ept_queue_item *item, *curr_item;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800284 struct usb_request *req = (struct usb_request *)_req;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800285 unsigned phys = (unsigned)req->req.buf;
Hanumant Singh5322c742012-12-12 15:40:09 -0800286 unsigned len = req->req.length;
Amol Jadi4421e652011-06-16 15:00:48 -0700287
Hanumant Singh5322c742012-12-12 15:40:09 -0800288 xfer = (len > MAX_TD_XFER_SIZE) ? MAX_TD_XFER_SIZE : len;
289 /*
290 * First TD allocated during request allocation
291 */
vijay kumar40030782015-05-26 16:18:49 +0530292 curr_item = req->item;
293 curr_item->info = INFO_BYTES(xfer) | INFO_ACTIVE;
294 curr_item->page0 = phys;
295 curr_item->page1 = (phys & 0xfffff000) + 0x1000;
296 curr_item->page2 = (phys & 0xfffff000) + 0x2000;
297 curr_item->page3 = (phys & 0xfffff000) + 0x3000;
298 curr_item->page4 = (phys & 0xfffff000) + 0x4000;
Hanumant Singh5322c742012-12-12 15:40:09 -0800299 phys += xfer;
Hanumant Singh5322c742012-12-12 15:40:09 -0800300 len -= xfer;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800301
Hanumant Singh5322c742012-12-12 15:40:09 -0800302 /*
303 * If transfer length is more then
304 * accomodate by 1 TD
305 * we add more transfer descriptors
306 */
307 while (len > 0) {
308 xfer = (len > MAX_TD_XFER_SIZE) ? MAX_TD_XFER_SIZE : len;
309 if (curr_item->next == TERMINATE) {
vijay kumar40030782015-05-26 16:18:49 +0530310 curr_item->next = PA((addr_t)transfer_desc_item);
311 item = (struct ept_queue_item *)transfer_desc_item;
Hanumant Singh5322c742012-12-12 15:40:09 -0800312 item->next = TERMINATE;
Hanumant Singh5322c742012-12-12 15:40:09 -0800313 } else
314 /* Since next TD in chain already exists */
vijay kumar4f4405f2014-08-08 11:49:53 +0530315 item = (struct ept_queue_item *)VA(curr_item->next);
Hanumant Singh5322c742012-12-12 15:40:09 -0800316
317 /* Update TD with transfer information */
318 item->info = INFO_BYTES(xfer) | INFO_ACTIVE;
319 item->page0 = phys;
320 item->page1 = (phys & 0xfffff000) + 0x1000;
321 item->page2 = (phys & 0xfffff000) + 0x2000;
322 item->page3 = (phys & 0xfffff000) + 0x3000;
323 item->page4 = (phys & 0xfffff000) + 0x4000;
324
325 curr_item = item;
326 len -= xfer;
327 phys += xfer;
328 }
329
330 /* Terminate and set interrupt for last TD */
331 curr_item->next = TERMINATE;
332 curr_item->info |= INFO_IOC;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800333 enter_critical_section();
vijay kumar4f4405f2014-08-08 11:49:53 +0530334 ept->head->next = PA((addr_t)req->item);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800335 ept->head->info = 0;
336 ept->req = req;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800337 arch_clean_invalidate_cache_range((addr_t) ept,
338 sizeof(struct udc_endpoint));
339 arch_clean_invalidate_cache_range((addr_t) ept->head,
340 sizeof(struct ept_queue_head));
341 arch_clean_invalidate_cache_range((addr_t) ept->req,
342 sizeof(struct usb_request));
vijay kumar4f4405f2014-08-08 11:49:53 +0530343 arch_clean_invalidate_cache_range((addr_t) VA((addr_t)req->req.buf),
Ajay Dudanib01e5062011-12-03 23:23:42 -0800344 req->req.length);
Hanumant Singh5322c742012-12-12 15:40:09 -0800345
346 item = req->item;
347 /* Write all TD's to memory from cache */
348 while (item != NULL) {
349 curr_item = item;
350 if (curr_item->next == TERMINATE)
351 item = NULL;
352 else
vijay kumar4f4405f2014-08-08 11:49:53 +0530353 item = (struct ept_queue_item *)curr_item->next;
Hanumant Singh5322c742012-12-12 15:40:09 -0800354 arch_clean_invalidate_cache_range((addr_t) curr_item,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800355 sizeof(struct ept_queue_item));
Hanumant Singh5322c742012-12-12 15:40:09 -0800356 }
Amol Jadi4421e652011-06-16 15:00:48 -0700357
Ajay Dudanib01e5062011-12-03 23:23:42 -0800358 DBG("ept%d %s queue req=%p\n", ept->num, ept->in ? "in" : "out", req);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800359 writel(ept->bit, USB_ENDPTPRIME);
360 exit_critical_section();
361 return 0;
362}
363
364static void handle_ept_complete(struct udc_endpoint *ept)
365{
366 struct ept_queue_item *item;
Hanumant Singh5322c742012-12-12 15:40:09 -0800367 unsigned actual, total_len;
vijay kumar4f4405f2014-08-08 11:49:53 +0530368 int status;
Sundarajan Srinivasanafc69282013-11-19 14:07:03 -0800369 struct usb_request *req=NULL;
Amol Jadi4421e652011-06-16 15:00:48 -0700370
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800371 DBG("ept%d %s complete req=%p\n",
Ajay Dudanib01e5062011-12-03 23:23:42 -0800372 ept->num, ept->in ? "in" : "out", ept->req);
Amol Jadi4421e652011-06-16 15:00:48 -0700373
Hanumant Singh5322c742012-12-12 15:40:09 -0800374 arch_invalidate_cache_range((addr_t) ept,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800375 sizeof(struct udc_endpoint));
Sundarajan Srinivasanafc69282013-11-19 14:07:03 -0800376
377 if(ept->req)
378 {
vijay kumar4f4405f2014-08-08 11:49:53 +0530379 req = (struct usb_request *)VA((addr_t)ept->req);
Sundarajan Srinivasanafc69282013-11-19 14:07:03 -0800380 arch_invalidate_cache_range((addr_t) ept->req,
381 sizeof(struct usb_request));
382 }
Amol Jadi4421e652011-06-16 15:00:48 -0700383
Ajay Dudanib01e5062011-12-03 23:23:42 -0800384 if (req) {
vijay kumar4f4405f2014-08-08 11:49:53 +0530385 item = (struct ept_queue_item *)VA((addr_t)req->item);
Hanumant Singh5322c742012-12-12 15:40:09 -0800386 /* total transfer length for transacation */
387 total_len = req->req.length;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800388 ept->req = 0;
Hanumant Singh5322c742012-12-12 15:40:09 -0800389 actual = 0;
390 while(1) {
Amol Jadi4421e652011-06-16 15:00:48 -0700391
Hanumant Singh5322c742012-12-12 15:40:09 -0800392 do {
393 /*
394 * Must clean/invalidate cached item
395 * data before checking the status
396 * every time.
397 */
398 arch_invalidate_cache_range((addr_t)(item),
399 sizeof(
400 struct ept_queue_item));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800401
Hanumant Singh5322c742012-12-12 15:40:09 -0800402 } while(readl(&item->info) & INFO_ACTIVE);
403
404 if ((item->info) & 0xff) {
405 /* error */
406 status = -1;
407 dprintf(INFO, "EP%d/%s FAIL nfo=%x pg0=%x\n",
408 ept->num, ept->in ? "in" : "out",
409 item->info,
410 item->page0);
411 goto out;
412 }
413
414 /* Check if we are processing last TD */
415 if (item->next == TERMINATE) {
416 /*
417 * Record the data transferred for the last TD
418 */
vijay kumar4f4405f2014-08-08 11:49:53 +0530419 actual += (total_len - (item->info >> 16))
Hanumant Singh5322c742012-12-12 15:40:09 -0800420 & 0x7FFF;
421 total_len = 0;
422 break;
423 } else {
424 /*
425 * Since we are not in last TD
426 * the total assumed transfer ascribed to this
427 * TD woulb the max possible TD transfer size
428 * (16K)
429 */
vijay kumar4f4405f2014-08-08 11:49:53 +0530430 actual += (MAX_TD_XFER_SIZE - (item->info >> 16)) & 0x7FFF;
431 total_len -= (MAX_TD_XFER_SIZE - (item->info >> 16)) & 0x7FFF;
Hanumant Singh5322c742012-12-12 15:40:09 -0800432 /*Move to next item in chain*/
vijay kumar4f4405f2014-08-08 11:49:53 +0530433 item = (struct ept_queue_item *)VA(item->next);
Hanumant Singh5322c742012-12-12 15:40:09 -0800434 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800435 }
Hanumant Singh5322c742012-12-12 15:40:09 -0800436 status = 0;
437out:
Ajay Dudanib01e5062011-12-03 23:23:42 -0800438 if (req->req.complete)
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800439 req->req.complete(&req->req, actual, status);
440 }
441}
442
443static const char *reqname(unsigned r)
444{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800445 switch (r) {
446 case GET_STATUS:
447 return "GET_STATUS";
448 case CLEAR_FEATURE:
449 return "CLEAR_FEATURE";
450 case SET_FEATURE:
451 return "SET_FEATURE";
452 case SET_ADDRESS:
453 return "SET_ADDRESS";
454 case GET_DESCRIPTOR:
455 return "GET_DESCRIPTOR";
456 case SET_DESCRIPTOR:
457 return "SET_DESCRIPTOR";
458 case GET_CONFIGURATION:
459 return "GET_CONFIGURATION";
460 case SET_CONFIGURATION:
461 return "SET_CONFIGURATION";
462 case GET_INTERFACE:
463 return "GET_INTERFACE";
464 case SET_INTERFACE:
465 return "SET_INTERFACE";
466 default:
467 return "*UNKNOWN*";
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800468 }
469}
470
471static struct udc_endpoint *ep0in, *ep0out;
472static struct udc_request *ep0req;
473
Ajay Dudanib01e5062011-12-03 23:23:42 -0800474static void
vijay kumar9c9f1cf2014-01-15 16:05:28 +0530475ep0_setup_ack_complete()
Shashank Mittal2523e0b2011-10-14 17:32:46 -0700476{
477 uint32_t mode;
478
Ajay Dudanib01e5062011-12-03 23:23:42 -0800479 if (!test_mode)
Shashank Mittal2523e0b2011-10-14 17:32:46 -0700480 return;
481
Ajay Dudanib01e5062011-12-03 23:23:42 -0800482 switch (test_mode) {
483 case TEST_PACKET:
484 dprintf(INFO, "Entering test mode for TST_PKT\n");
485 mode = readl(USB_PORTSC) & (~PORTSC_PTC);
486 writel(mode | PORTSC_PTC_TST_PKT, USB_PORTSC);
487 break;
Shashank Mittal2523e0b2011-10-14 17:32:46 -0700488
Ajay Dudanib01e5062011-12-03 23:23:42 -0800489 case TEST_SE0_NAK:
490 dprintf(INFO, "Entering test mode for SE0-NAK\n");
491 mode = readl(USB_PORTSC) & (~PORTSC_PTC);
492 writel(mode | PORTSC_PTC_SE0_NAK, USB_PORTSC);
493 break;
Shashank Mittal2523e0b2011-10-14 17:32:46 -0700494 }
495
496}
497
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800498static void setup_ack(void)
499{
Shashank Mittal2523e0b2011-10-14 17:32:46 -0700500 ep0req->complete = ep0_setup_ack_complete;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800501 ep0req->length = 0;
502 udc_request_queue(ep0in, ep0req);
503}
504
505static void ep0in_complete(struct udc_request *req, unsigned actual, int status)
506{
507 DBG("ep0in_complete %p %d %d\n", req, actual, status);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800508 if (status == 0) {
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800509 req->length = 0;
510 req->complete = 0;
511 udc_request_queue(ep0out, req);
512 }
513}
514
515static void setup_tx(void *buf, unsigned len)
516{
517 DBG("setup_tx %p %d\n", buf, len);
518 memcpy(ep0req->buf, buf, len);
vijay kumar4f4405f2014-08-08 11:49:53 +0530519 ep0req->buf = (void *)PA((addr_t)ep0req->buf);
Matthew Qinc7447202015-02-03 17:45:17 +0800520 arch_clean_invalidate_cache_range((addr_t)ep0req->buf, len);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800521 ep0req->complete = ep0in_complete;
522 ep0req->length = len;
523 udc_request_queue(ep0in, ep0req);
524}
525
526static unsigned char usb_config_value = 0;
527
528#define SETUP(type,request) (((type) << 8) | (request))
529
530static void handle_setup(struct udc_endpoint *ept)
531{
532 struct setup_packet s;
Amol Jadi4421e652011-06-16 15:00:48 -0700533
Ajay Dudanib01e5062011-12-03 23:23:42 -0800534 arch_clean_invalidate_cache_range((addr_t) ept->head->setup_data,
535 sizeof(struct ept_queue_head));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800536 memcpy(&s, ept->head->setup_data, sizeof(s));
Matthew Qinc7447202015-02-03 17:45:17 +0800537 arch_clean_invalidate_cache_range((addr_t)&s, sizeof(s));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800538 writel(ept->bit, USB_ENDPTSETUPSTAT);
539
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800540 DBG("handle_setup type=0x%02x req=0x%02x val=%d idx=%d len=%d (%s)\n",
Ajay Dudanib01e5062011-12-03 23:23:42 -0800541 s.type, s.request, s.value, s.index, s.length, reqname(s.request));
Amol Jadi4421e652011-06-16 15:00:48 -0700542
Ajay Dudanib01e5062011-12-03 23:23:42 -0800543 switch (SETUP(s.type, s.request)) {
544 case SETUP(DEVICE_READ, GET_STATUS):
545 {
546 unsigned zero = 0;
547 if (s.length == 2) {
548 setup_tx(&zero, 2);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800549 return;
550 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800551 break;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800552 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800553 case SETUP(DEVICE_READ, GET_DESCRIPTOR):
554 {
555 struct udc_descriptor *desc;
vijay kumarb8639052015-03-09 17:37:31 +0530556 unsigned char* data = NULL;
557 unsigned n;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800558 /* usb_highspeed? */
559 for (desc = desc_list; desc; desc = desc->next) {
560 if (desc->tag == s.value) {
vijay kumarb8639052015-03-09 17:37:31 +0530561 /*Check for configuration type of descriptor*/
562 if (desc->tag == (TYPE_CONFIGURATION << 8)) {
563 data = desc->data;
564 data+= 9; /* skip config desc */
565 data+= 9; /* skip interface desc */
566 /* taking the max packet size based on the USB host speed connected */
567 for (n = 0; n < 2; n++) {
568 data[4] = usb_highspeed ? 512:64;
569 data[5] = (usb_highspeed ? 512:64)>>8;
570 data += 7;
571 }
572 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800573 unsigned len = desc->len;
574 if (len > s.length)
575 len = s.length;
576 setup_tx(desc->data, len);
577 return;
578 }
579 }
580 break;
581 }
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800582 case SETUP(DEVICE_READ, GET_CONFIGURATION):
583 /* disabling this causes data transaction failures on OSX. Why? */
584 if ((s.value == 0) && (s.index == 0) && (s.length == 1)) {
585 setup_tx(&usb_config_value, 1);
586 return;
587 }
588 break;
589 case SETUP(DEVICE_WRITE, SET_CONFIGURATION):
590 if (s.value == 1) {
591 struct udc_endpoint *ept;
592 /* enable endpoints */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800593 for (ept = ept_list; ept; ept = ept->next) {
Amol Jadi4421e652011-06-16 15:00:48 -0700594 if (ept->num == 0)
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800595 continue;
596 endpoint_enable(ept, s.value);
597 }
598 usb_config_value = 1;
599 the_gadget->notify(the_gadget, UDC_EVENT_ONLINE);
600 } else {
601 writel(0, USB_ENDPTCTRL(1));
602 usb_config_value = 0;
603 the_gadget->notify(the_gadget, UDC_EVENT_OFFLINE);
604 }
605 setup_ack();
606 usb_online = s.value ? 1 : 0;
607 usb_status(s.value ? 1 : 0, usb_highspeed);
608 return;
609 case SETUP(DEVICE_WRITE, SET_ADDRESS):
610 /* write address delayed (will take effect
Ajay Dudanib01e5062011-12-03 23:23:42 -0800611 ** after the next IN txn)
612 */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800613 writel((s.value << 25) | (1 << 24), USB_DEVICEADDR);
614 setup_ack();
615 return;
616 case SETUP(INTERFACE_WRITE, SET_INTERFACE):
617 /* if we ack this everything hangs */
618 /* per spec, STALL is valid if there is not alt func */
619 goto stall;
Subbaraman Narayanamurthyd8b7afc2011-06-30 15:42:41 -0700620 case SETUP(DEVICE_WRITE, SET_FEATURE):
Shashank Mittal2523e0b2011-10-14 17:32:46 -0700621 test_mode = s.index;
Subbaraman Narayanamurthyd8b7afc2011-06-30 15:42:41 -0700622 setup_ack();
Subbaraman Narayanamurthyd8b7afc2011-06-30 15:42:41 -0700623 return;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800624 case SETUP(ENDPOINT_WRITE, CLEAR_FEATURE):
625 {
626 struct udc_endpoint *ept;
627 unsigned num = s.index & 15;
628 unsigned in = !!(s.index & 0x80);
Amol Jadi4421e652011-06-16 15:00:48 -0700629
Ajay Dudanib01e5062011-12-03 23:23:42 -0800630 if ((s.value == 0) && (s.length == 0)) {
631 DBG("clr feat %d %d\n", num, in);
632 for (ept = ept_list; ept; ept = ept->next) {
633 if ((ept->num == num)
634 && (ept->in == in)) {
635 endpoint_enable(ept, 1);
636 setup_ack();
637 return;
638 }
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800639 }
640 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800641 break;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800642 }
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800643 }
644
645 dprintf(INFO, "STALL %s %d %d %d %d %d\n",
646 reqname(s.request),
647 s.type, s.request, s.value, s.index, s.length);
648
Ajay Dudanib01e5062011-12-03 23:23:42 -0800649 stall:
650 writel((1 << 16) | (1 << 0), USB_ENDPTCTRL(ept->num));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800651}
652
653unsigned ulpi_read(unsigned reg)
654{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800655 /* initiate read operation */
656 writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg), USB_ULPI_VIEWPORT);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800657
Ajay Dudanib01e5062011-12-03 23:23:42 -0800658 /* wait for completion */
659 while (readl(USB_ULPI_VIEWPORT) & ULPI_RUN) ;
Amol Jadi4421e652011-06-16 15:00:48 -0700660
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800661 return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
662}
663
664void ulpi_write(unsigned val, unsigned reg)
665{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800666 /* initiate write operation */
Amol Jadi4421e652011-06-16 15:00:48 -0700667 writel(ULPI_RUN | ULPI_WRITE |
Ajay Dudanib01e5062011-12-03 23:23:42 -0800668 ULPI_ADDR(reg) | ULPI_DATA(val), USB_ULPI_VIEWPORT);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800669
Ajay Dudanib01e5062011-12-03 23:23:42 -0800670 /* wait for completion */
671 while (readl(USB_ULPI_VIEWPORT) & ULPI_RUN) ;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800672}
Ajay Dudani5a1e3302009-12-05 13:19:17 -0800673
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800674
Amol Jadi4421e652011-06-16 15:00:48 -0700675int udc_init(struct udc_device *dev)
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800676{
Amol Jadi4421e652011-06-16 15:00:48 -0700677 DBG("udc_init():\n");
678
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800679 hsusb_clock_init();
680
Amol Jadida118b92012-07-06 19:53:18 -0700681 /* RESET */
Channagoud Kadabi50c92b12013-03-29 14:36:44 -0700682 writel(0x00080002, USB_USBCMD);
Amol Jadida118b92012-07-06 19:53:18 -0700683
684 thread_sleep(20);
Subbaraman Narayanamurthyb0111a12011-02-03 14:24:16 -0800685
Deepa Dinamani0687ecd2012-08-10 16:00:26 -0700686 while((readl(USB_USBCMD)&2));
687
688 /* select ULPI phy */
689 writel(0x80000000, USB_PORTSC);
690
Amol Jadi71303ad2013-02-28 20:56:08 -0800691 /* Do any target specific intialization like GPIO settings,
692 * LDO, PHY configuration etc. needed before USB port can be used.
693 */
694 target_usb_init();
695
696 /* USB_OTG_HS_AHB_BURST */
Deepa Dinamani0687ecd2012-08-10 16:00:26 -0700697 writel(0x0, USB_SBUSCFG);
698
699 /* USB_OTG_HS_AHB_MODE: HPROT_MODE */
700 /* Bus access related config. */
701 writel(0x08, USB_AHB_MODE);
702
Deepa Dinamani4f9db032013-03-15 13:17:16 -0700703 epts = memalign(lcm(4096, CACHE_LINE), ROUNDUP(4096, CACHE_LINE));
Lijuan Gaodc077222014-07-18 16:43:18 +0800704 ASSERT(epts);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800705
706 dprintf(INFO, "USB init ept @ %p\n", epts);
707 memset(epts, 0, 32 * sizeof(struct ept_queue_head));
Ajay Dudanib01e5062011-12-03 23:23:42 -0800708 arch_clean_invalidate_cache_range((addr_t) epts,
709 32 * sizeof(struct ept_queue_head));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800710
Deepa Dinamani0bf2f442012-10-19 11:41:06 -0700711 writel((unsigned)PA((addr_t)epts), USB_ENDPOINTLISTADDR);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800712
Ajay Dudanib01e5062011-12-03 23:23:42 -0800713 /* select DEVICE mode */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800714 writel(0x02, USB_USBMODE);
715
716 writel(0xffffffff, USB_ENDPTFLUSH);
717 thread_sleep(20);
718
719 ep0out = _udc_endpoint_alloc(0, 0, 64);
720 ep0in = _udc_endpoint_alloc(0, 1, 64);
721 ep0req = udc_request_alloc();
Deepa Dinamani4f9db032013-03-15 13:17:16 -0700722 ep0req->buf = memalign(CACHE_LINE, ROUNDUP(4096, CACHE_LINE));
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800723
724 {
725 /* create and register a language table descriptor */
726 /* language 0x0409 is US English */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800727 struct udc_descriptor *desc =
728 udc_descriptor_alloc(TYPE_STRING, 0, 4);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800729 desc->data[2] = 0x09;
730 desc->data[3] = 0x04;
731 udc_descriptor_register(desc);
732 }
Amol Jadi4421e652011-06-16 15:00:48 -0700733
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800734 the_device = dev;
735 return 0;
736}
737
738enum handler_return udc_interrupt(void *arg)
739{
740 struct udc_endpoint *ept;
741 unsigned ret = INT_NO_RESCHEDULE;
742 unsigned n = readl(USB_USBSTS);
743 writel(n, USB_USBSTS);
Amol Jadi4421e652011-06-16 15:00:48 -0700744
Amol Jadida118b92012-07-06 19:53:18 -0700745 DBG("\nudc_interrupt(): status = 0x%x\n", n);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800746
Amol Jadida118b92012-07-06 19:53:18 -0700747 n &= (STS_SLI | STS_URI | STS_PCI | STS_UI | STS_UEI);
Amol Jadi4421e652011-06-16 15:00:48 -0700748
749 if (n == 0) {
750 DBG("n = 0\n");
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800751 return ret;
Amol Jadi4421e652011-06-16 15:00:48 -0700752 }
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800753
754 if (n & STS_URI) {
Amol Jadi4421e652011-06-16 15:00:48 -0700755 DBG("STS_URI\n");
756
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800757 writel(readl(USB_ENDPTCOMPLETE), USB_ENDPTCOMPLETE);
758 writel(readl(USB_ENDPTSETUPSTAT), USB_ENDPTSETUPSTAT);
759 writel(0xffffffff, USB_ENDPTFLUSH);
760 writel(0, USB_ENDPTCTRL(1));
Amol Jadi4421e652011-06-16 15:00:48 -0700761 dprintf(INFO, "-- reset --\n");
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800762 usb_online = 0;
763 usb_config_value = 0;
764 the_gadget->notify(the_gadget, UDC_EVENT_OFFLINE);
765
766 /* error out any pending reqs */
767 for (ept = ept_list; ept; ept = ept->next) {
768 /* ensure that ept_complete considers
769 * this to be an error state
770 */
771 if (ept->req) {
772 ept->req->item->info = INFO_HALTED;
773 handle_ept_complete(ept);
774 }
775 }
776 usb_status(0, usb_highspeed);
777 }
778 if (n & STS_SLI) {
Ajay Dudani35f686f2011-07-22 13:12:09 -0700779 DBG("-- suspend --\n");
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800780 }
781 if (n & STS_PCI) {
Amol Jadi4421e652011-06-16 15:00:48 -0700782 dprintf(INFO, "-- portchange --\n");
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800783 unsigned spd = (readl(USB_PORTSC) >> 26) & 3;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800784 if (spd == 2) {
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800785 usb_highspeed = 1;
786 } else {
787 usb_highspeed = 0;
788 }
789 }
790 if (n & STS_UEI) {
Amol Jadi4421e652011-06-16 15:00:48 -0700791 DBG("STS_UEI\n");
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800792 dprintf(INFO, "<UEI %x>\n", readl(USB_ENDPTCOMPLETE));
793 }
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800794 if ((n & STS_UI) || (n & STS_UEI)) {
Amol Jadida118b92012-07-06 19:53:18 -0700795
796 if (n & STS_UEI)
797 DBG("ERROR ");
798 if (n & STS_UI)
799 DBG("USB ");
800
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800801 n = readl(USB_ENDPTSETUPSTAT);
802 if (n & EPT_RX(0)) {
803 handle_setup(ep0out);
804 ret = INT_RESCHEDULE;
805 }
806
807 n = readl(USB_ENDPTCOMPLETE);
808 if (n != 0) {
809 writel(n, USB_ENDPTCOMPLETE);
810 }
811
Ajay Dudanib01e5062011-12-03 23:23:42 -0800812 for (ept = ept_list; ept; ept = ept->next) {
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800813 if (n & ept->bit) {
814 handle_ept_complete(ept);
815 ret = INT_RESCHEDULE;
816 }
817 }
818 }
819 return ret;
820}
821
822int udc_register_gadget(struct udc_gadget *gadget)
823{
824 if (the_gadget) {
825 dprintf(CRITICAL, "only one gadget supported\n");
826 return -1;
827 }
828 the_gadget = gadget;
829 return 0;
830}
831
832static void udc_ept_desc_fill(struct udc_endpoint *ept, unsigned char *data)
833{
834 data[0] = 7;
835 data[1] = TYPE_ENDPOINT;
836 data[2] = ept->num | (ept->in ? 0x80 : 0x00);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800837 data[3] = 0x02; /* bulk -- the only kind we support */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800838 data[4] = ept->maxpkt;
839 data[5] = ept->maxpkt >> 8;
840 data[6] = ept->in ? 0x00 : 0x01;
841}
842
843static unsigned udc_ifc_desc_size(struct udc_gadget *g)
844{
845 return 9 + g->ifc_endpoints * 7;
846}
847
848static void udc_ifc_desc_fill(struct udc_gadget *g, unsigned char *data)
849{
850 unsigned n;
851
852 data[0] = 0x09;
853 data[1] = TYPE_INTERFACE;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800854 data[2] = 0x00; /* ifc number */
855 data[3] = 0x00; /* alt number */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800856 data[4] = g->ifc_endpoints;
857 data[5] = g->ifc_class;
858 data[6] = g->ifc_subclass;
859 data[7] = g->ifc_protocol;
860 data[8] = udc_string_desc_alloc(g->ifc_string);
861
862 data += 9;
863 for (n = 0; n < g->ifc_endpoints; n++) {
864 udc_ept_desc_fill(g->ept[n], data);
865 data += 7;
866 }
867}
868
869int udc_start(void)
870{
871 struct udc_descriptor *desc;
872 unsigned char *data;
873 unsigned size;
Amol Jadi71303ad2013-02-28 20:56:08 -0800874 uint32_t val;
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800875
Chandan Uddaraju40b227d2010-08-03 19:25:41 -0700876 dprintf(ALWAYS, "udc_start()\n");
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800877
878 if (!the_device) {
879 dprintf(CRITICAL, "udc cannot start before init\n");
880 return -1;
881 }
882 if (!the_gadget) {
883 dprintf(CRITICAL, "udc has no gadget registered\n");
884 return -1;
885 }
886
887 /* create our device descriptor */
Sridhar Parasuram08045f42015-06-22 14:19:38 -0700888 if(!(desc = udc_descriptor_alloc(TYPE_DEVICE, 0, 18)))
889 {
890 dprintf(CRITICAL, "Failed to allocate device descriptor\n");
891 ASSERT(0);
892 }
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800893 data = desc->data;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800894 data[2] = 0x00; /* usb spec minor rev */
895 data[3] = 0x02; /* usb spec major rev */
896 data[4] = 0x00; /* class */
897 data[5] = 0x00; /* subclass */
898 data[6] = 0x00; /* protocol */
899 data[7] = 0x40; /* max packet size on ept 0 */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800900 memcpy(data + 8, &the_device->vendor_id, sizeof(short));
901 memcpy(data + 10, &the_device->product_id, sizeof(short));
902 memcpy(data + 12, &the_device->version_id, sizeof(short));
903 data[14] = udc_string_desc_alloc(the_device->manufacturer);
904 data[15] = udc_string_desc_alloc(the_device->product);
905 data[16] = udc_string_desc_alloc(the_device->serialno);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800906 data[17] = 1; /* number of configurations */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800907 udc_descriptor_register(desc);
908
909 /* create our configuration descriptor */
910 size = 9 + udc_ifc_desc_size(the_gadget);
911 desc = udc_descriptor_alloc(TYPE_CONFIGURATION, 0, size);
Parth Dixit859972b2016-01-07 11:04:39 +0530912 if(!desc)
913 {
914 dprintf(CRITICAL, "Failed to allocate device descriptor\n");
915 ASSERT(0);
916 }
917
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800918 data = desc->data;
919 data[0] = 0x09;
920 data[2] = size;
921 data[3] = size >> 8;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800922 data[4] = 0x01; /* number of interfaces */
923 data[5] = 0x01; /* configuration value */
924 data[6] = 0x00; /* configuration string */
925 data[7] = 0x80; /* attributes */
926 data[8] = 0x80; /* max power (250ma) -- todo fix this */
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800927 udc_ifc_desc_fill(the_gadget, data + 9);
928 udc_descriptor_register(desc);
929
Ajay Dudanib01e5062011-12-03 23:23:42 -0800930 register_int_handler(INT_USB_HS, udc_interrupt, (void *)0);
Amol Jadica4f4c92011-01-13 20:19:34 -0800931 writel(STS_URI | STS_SLI | STS_UI | STS_PCI, USB_USBINTR);
932 unmask_interrupt(INT_USB_HS);
933
Ajay Dudanib01e5062011-12-03 23:23:42 -0800934 /* go to RUN mode (D+ pullup enable) */
Amol Jadi71303ad2013-02-28 20:56:08 -0800935 val = readl(USB_USBCMD);
936
937 writel(val | 0x00080001, USB_USBCMD);
Amol Jadica4f4c92011-01-13 20:19:34 -0800938
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800939 return 0;
940}
941
942int udc_stop(void)
943{
Deepa Dinamani761cc952013-03-06 11:15:46 -0800944 uint32_t val;
945
946 /* Flush all primed end points. */
947 writel(0xffffffff, USB_ENDPTFLUSH);
948
949 /* Stop controller. */
950 val = readl(USB_USBCMD);
951 writel(val & ~USBCMD_ATTACH, USB_USBCMD);
952
953 /* Mask the interrupts. */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800954 writel(0, USB_USBINTR);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800955 mask_interrupt(INT_USB_HS);
956
Deepa Dinamani761cc952013-03-06 11:15:46 -0800957 /* Perform any target specific clean up. */
Amol Jadida118b92012-07-06 19:53:18 -0700958 target_usb_stop();
959
Deepa Dinamani761cc952013-03-06 11:15:46 -0800960 /* Reset the controller. */
961 writel(USBCMD_RESET, USB_USBCMD);
962 /* Wait until reset completes. */
963 while(readl(USB_USBCMD) & USBCMD_RESET);
Brian Swetland3e7e21a2009-01-19 19:41:24 -0800964
965 return 0;
966}