blob: 4fcd5ea9527a9584d0bc0f8b341378b482073b05 [file] [log] [blame]
Patrick Georgi7f43dc12010-09-25 17:01:13 +00001/*
2 * This file is part of the libpayload project.
3 *
4 * Copyright (C) 2010 coresystems GmbH
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <libpayload.h>
31#include "ehci.h"
32#include "ehci_private.h"
33
Stefan Reinauer528b43d2011-04-14 19:52:04 +000034static void dump_td(u32 addr)
35{
Patrick Georgi7f43dc12010-09-25 17:01:13 +000036 qtd_t *td = phys_to_virt(addr);
Gabe Black93ded592012-11-01 15:44:10 -070037 usb_debug("td at phys(%x): status: %x\n\n", addr, td->token & QTD_STATUS_MASK);
38 usb_debug("- cerr: %x, total_len: %x\n\n", (td->token & QTD_CERR_MASK) >> QTD_CERR_SHIFT,
Patrick Georgi8fa27872011-11-24 13:19:57 +010039 (td->token & QTD_TOTAL_LEN_MASK) >> QTD_TOTAL_LEN_SHIFT);
Patrick Georgi7f43dc12010-09-25 17:01:13 +000040}
41
42static void ehci_start (hci_t *controller)
43{
Patrick Georgi8fa27872011-11-24 13:19:57 +010044 EHCI_INST(controller)->operation->usbcmd |= HC_OP_RS;
Patrick Georgi7f43dc12010-09-25 17:01:13 +000045}
46
47static void ehci_stop (hci_t *controller)
48{
Patrick Georgi8fa27872011-11-24 13:19:57 +010049 EHCI_INST(controller)->operation->usbcmd &= ~HC_OP_RS;
Patrick Georgi7f43dc12010-09-25 17:01:13 +000050}
51
52static void ehci_reset (hci_t *controller)
53{
Anton Kochkov2fef58e2012-11-09 14:06:05 +010054 short count = 0;
55 ehci_stop(controller);
56 /* wait 10 ms just to be shure */
57 mdelay(10);
58 if (EHCI_INST(controller)->operation->usbsts & HC_OP_HC_HALTED) {
59 EHCI_INST(controller)->operation->usbcmd = HC_OP_HC_RESET;
60 /* wait 100 ms */
61 for (count = 0; count < 10; count++) {
62 mdelay(10);
63 if (!(EHCI_INST(controller)->operation->usbcmd & HC_OP_HC_RESET)) {
64 return;
65 }
66 }
67 }
68 usb_debug("ehci_reset(): reset failed!\n");
Patrick Georgi7f43dc12010-09-25 17:01:13 +000069}
70
Nico Huber62eb5b32012-05-25 10:09:13 +020071static int ehci_set_periodic_schedule(ehci_t *ehcic, int enable)
72{
73 /* Set periodic schedule status. */
74 if (enable)
75 ehcic->operation->usbcmd |= HC_OP_PERIODIC_SCHED_EN;
76 else
77 ehcic->operation->usbcmd &= ~HC_OP_PERIODIC_SCHED_EN;
78 /* Wait for the controller to accept periodic schedule status.
79 * This shouldn't take too long, but we should timeout nevertheless.
80 */
81 enable = enable ? HC_OP_PERIODIC_SCHED_STAT : 0;
82 int timeout = 100; /* time out after 100ms */
83 while (((ehcic->operation->usbsts & HC_OP_PERIODIC_SCHED_STAT) != enable)
84 && timeout--)
85 mdelay(1);
86 if (timeout < 0) {
Gabe Black93ded592012-11-01 15:44:10 -070087 usb_debug("ehci periodic schedule status change timed out.\n");
Nico Huber62eb5b32012-05-25 10:09:13 +020088 return 1;
89 }
90 return 0;
91}
92
Patrick Georgi7f43dc12010-09-25 17:01:13 +000093static void ehci_shutdown (hci_t *controller)
94{
Nico Huber62eb5b32012-05-25 10:09:13 +020095 /* Make sure periodic schedule is disabled */
96 ehci_set_periodic_schedule(EHCI_INST(controller), 0);
97 /* Free periodic frame list */
98 free(phys_to_virt(EHCI_INST(controller)->operation->periodiclistbase));
99
Nico Huber3ca35ca2012-06-14 13:27:39 +0200100 /* Free dummy QH */
101 free(EHCI_INST(controller)->dummy_qh);
102
Patrick Georgi01178bb2011-11-04 11:57:46 +0100103 EHCI_INST(controller)->operation->configflag = 0;
Nico Huberd633dda2012-11-12 15:35:44 +0100104
105 free(EHCI_INST(controller));
106 free(controller);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000107}
108
109enum { EHCI_OUT=0, EHCI_IN=1, EHCI_SETUP=2 };
110
Nico Huber1ab60752012-05-23 09:21:54 +0200111/*
112 * returns the address of the closest USB2.0 hub, which is responsible for
113 * split transactions, along with the number of the used downstream port
114 */
115static int closest_usb2_hub(const usbdev_t *dev, int *const addr, int *const port)
116{
117 const usbdev_t *usb1dev;
118 do {
119 usb1dev = dev;
120 if ((dev->hub > 0) && (dev->hub < 128))
121 dev = dev->controller->devices[dev->hub];
122 else
123 dev = NULL;
124 } while (dev && (dev->speed < 2));
125 if (dev) {
126 *addr = usb1dev->hub;
127 *port = usb1dev->port;
128 return 0;
129 } else {
Gabe Black93ded592012-11-01 15:44:10 -0700130 usb_debug("ehci: Couldn't find closest USB2.0 hub.\n");
Nico Huber1ab60752012-05-23 09:21:54 +0200131 return 1;
132 }
133}
134
Patrick Georgi8fa27872011-11-24 13:19:57 +0100135/* returns handled bytes. assumes that the fields it writes are empty on entry */
136static int fill_td(qtd_t *td, void* data, int datalen)
Stefan Reinauer528b43d2011-04-14 19:52:04 +0000137{
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000138 u32 total_len = 0;
Patrick Georgi8fa27872011-11-24 13:19:57 +0100139 u32 page_no = 0;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000140
141 u32 start = virt_to_phys(data);
142 u32 page = start & ~4095;
143 u32 offset = start & 4095;
144 u32 page_len = 4096 - offset;
145
Patrick Georgi8fa27872011-11-24 13:19:57 +0100146 td->token |= 0 << QTD_CPAGE_SHIFT;
147 td->bufptrs[page_no++] = start;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000148
149 if (datalen <= page_len) {
150 total_len = datalen;
151 } else {
152 datalen -= page_len;
153 total_len += page_len;
154
Patrick Georgi8fa27872011-11-24 13:19:57 +0100155 while (page_no < 5) {
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000156 /* we have a continguous mapping between virtual and physical memory */
157 page += 4096;
158
Patrick Georgi8fa27872011-11-24 13:19:57 +0100159 td->bufptrs[page_no++] = page;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000160 if (datalen <= 4096) {
161 total_len += datalen;
162 break;
163 }
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000164 datalen -= 4096;
165 total_len += 4096;
Patrick Georgi8fa27872011-11-24 13:19:57 +0100166 }
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000167 }
Patrick Georgi8fa27872011-11-24 13:19:57 +0100168 td->token |= total_len << QTD_TOTAL_LEN_SHIFT;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000169 return total_len;
170}
171
172/* free up data structures */
Patrick Georgi8fa27872011-11-24 13:19:57 +0100173static void free_qh_and_tds(ehci_qh_t *qh, qtd_t *cur)
Stefan Reinauer528b43d2011-04-14 19:52:04 +0000174{
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000175 qtd_t *next;
176 while (cur) {
177 next = (qtd_t*)phys_to_virt(cur->next_qtd & ~31);
178 free(cur);
179 cur = next;
180 }
181 free(qh);
182}
183
Patrick Georgi8fa27872011-11-24 13:19:57 +0100184static int wait_for_tds(qtd_t *head)
Stefan Reinauer528b43d2011-04-14 19:52:04 +0000185{
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000186 int result = 0;
187 qtd_t *cur = head;
188 while (1) {
189 if (0) dump_td(virt_to_phys(cur));
Nico Huber0421dc82012-05-21 14:53:43 +0200190
191 /* wait for results */
Nico Hubercef86922012-06-01 08:54:29 +0200192 /* how long to wait?
193 * tested with some USB2.0 flash sticks:
194 * TUR turn around took
195 * about 2s for the slowest (14cd:121c)
196 * max. 250ms for the others
197 * slowest non-TUR turn around took about 1.3s
198 * try 2s for now as a failed TUR is not fatal
Nico Huber0421dc82012-05-21 14:53:43 +0200199 */
Nico Hubercef86922012-06-01 08:54:29 +0200200 int timeout = 40000; /* time out after 40000 * 50us == 2s */
Nico Huber0421dc82012-05-21 14:53:43 +0200201 while ((cur->token & QTD_ACTIVE) && !(cur->token & QTD_HALTED)
202 && timeout--)
203 udelay(50);
204 if (timeout < 0) {
205 printf("Error: ehci: queue transfer "
206 "processing timed out.\n");
207 return 1;
208 }
Patrick Georgi8fa27872011-11-24 13:19:57 +0100209 if (cur->token & QTD_HALTED) {
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000210 printf("ERROR with packet\n");
211 dump_td(virt_to_phys(cur));
Gabe Black93ded592012-11-01 15:44:10 -0700212 usb_debug("-----------------\n");
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000213 return 1;
214 }
215 if (cur->next_qtd & 1) {
216 return 0;
217 }
218 if (0) dump_td(virt_to_phys(cur));
219 /* helps debugging the TD chain */
Gabe Black93ded592012-11-01 15:44:10 -0700220 if (0) usb_debug("\nmoving from %x to %x\n", cur, phys_to_virt(cur->next_qtd));
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000221 cur = phys_to_virt(cur->next_qtd);
222 }
223 return result;
224}
225
Nico Huber0421dc82012-05-21 14:53:43 +0200226static int ehci_set_async_schedule(ehci_t *ehcic, int enable)
227{
228 /* Set async schedule status. */
229 if (enable)
230 ehcic->operation->usbcmd |= HC_OP_ASYNC_SCHED_EN;
231 else
232 ehcic->operation->usbcmd &= ~HC_OP_ASYNC_SCHED_EN;
233 /* Wait for the controller to accept async schedule status.
234 * This shouldn't take too long, but we should timeout nevertheless.
235 */
236 enable = enable ? HC_OP_ASYNC_SCHED_STAT : 0;
237 int timeout = 100; /* time out after 100ms */
238 while (((ehcic->operation->usbsts & HC_OP_ASYNC_SCHED_STAT) != enable)
239 && timeout--)
240 mdelay(1);
241 if (timeout < 0) {
Gabe Black93ded592012-11-01 15:44:10 -0700242 usb_debug("ehci async schedule status change timed out.\n");
Nico Huber0421dc82012-05-21 14:53:43 +0200243 return 1;
244 }
245 return 0;
246}
247
248static int ehci_process_async_schedule(
249 ehci_t *ehcic, ehci_qh_t *qhead, qtd_t *head)
250{
251 int result;
252
253 /* make sure async schedule is disabled */
254 if (ehci_set_async_schedule(ehcic, 0)) return 1;
255
256 /* hook up QH */
257 ehcic->operation->asynclistaddr = virt_to_phys(qhead);
258
259 /* start async schedule */
260 if (ehci_set_async_schedule(ehcic, 1)) return 1;
261
262 /* wait for result */
263 result = wait_for_tds(head);
264
265 /* disable async schedule */
266 ehci_set_async_schedule(ehcic, 0);
267
268 return result;
269}
270
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000271static int ehci_bulk (endpoint_t *ep, int size, u8 *data, int finalize)
272{
273 int result = 0;
274 int endp = ep->endpoint & 0xf;
275 int pid = (ep->direction==IN)?EHCI_IN:EHCI_OUT;
276
Nico Huber1ab60752012-05-23 09:21:54 +0200277 int hubaddr = 0, hubport = 0;
278 if (ep->dev->speed < 2) {
279 /* we need a split transaction */
280 if (closest_usb2_hub(ep->dev, &hubaddr, &hubport))
281 return 1;
282 }
283
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000284 qtd_t *head = memalign(32, sizeof(qtd_t));
285 qtd_t *cur = head;
286 while (1) {
287 memset(cur, 0, sizeof(qtd_t));
Patrick Georgi8fa27872011-11-24 13:19:57 +0100288 cur->token = QTD_ACTIVE |
289 (pid << QTD_PID_SHIFT) |
290 (0 << QTD_CERR_SHIFT);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000291 u32 chunk = fill_td(cur, data, size);
292 size -= chunk;
293 data += chunk;
294
Patrick Georgi8fa27872011-11-24 13:19:57 +0100295 cur->alt_next_qtd = QTD_TERMINATE;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000296 if (size == 0) {
Patrick Georgi8fa27872011-11-24 13:19:57 +0100297 cur->next_qtd = virt_to_phys(0) | QTD_TERMINATE;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000298 break;
299 } else {
300 qtd_t *next = memalign(32, sizeof(qtd_t));
301 cur->next_qtd = virt_to_phys(next);
302 cur = next;
303 }
304 }
305
306 /* create QH */
307 ehci_qh_t *qh = memalign(32, sizeof(ehci_qh_t));
308 memset(qh, 0, sizeof(ehci_qh_t));
Patrick Georgi8fa27872011-11-24 13:19:57 +0100309 qh->horiz_link_ptr = virt_to_phys(qh) | QH_QH;
310 qh->epchar = ep->dev->address |
311 (endp << QH_EP_SHIFT) |
312 (ep->dev->speed << QH_EPS_SHIFT) |
313 (0 << QH_DTC_SHIFT) |
314 (1 << QH_RECLAIM_HEAD_SHIFT) |
315 (ep->maxpacketsize << QH_MPS_SHIFT) |
316 (0 << QH_NAK_CNT_SHIFT);
Nico Huber1ab60752012-05-23 09:21:54 +0200317 qh->epcaps = (3 << QH_PIPE_MULTIPLIER_SHIFT) |
318 (hubport << QH_PORT_NUMBER_SHIFT) |
319 (hubaddr << QH_HUB_ADDRESS_SHIFT);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000320
321 qh->td.next_qtd = virt_to_phys(head);
Patrick Georgi8fa27872011-11-24 13:19:57 +0100322 qh->td.token |= (ep->toggle?QTD_TOGGLE_DATA1:0);
323 head->token |= (ep->toggle?QTD_TOGGLE_DATA1:0);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000324
Nico Huber0421dc82012-05-21 14:53:43 +0200325 result = ehci_process_async_schedule(
326 EHCI_INST(ep->dev->controller), qh, head);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000327
Patrick Georgi8fa27872011-11-24 13:19:57 +0100328 ep->toggle = (cur->token & QTD_TOGGLE_MASK) >> QTD_TOGGLE_SHIFT;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000329
330 free_qh_and_tds(qh, head);
331 return result;
332}
333
334
335/* FIXME: Handle control transfers as 3 QHs, so the 2nd stage can be >0x4000 bytes */
336static int ehci_control (usbdev_t *dev, direction_t dir, int drlen, void *devreq,
337 int dalen, u8 *data)
338{
339 int endp = 0; // this is control. always 0 (for now)
340 int toggle = 0;
341 int mlen = dev->endpoints[0].maxpacketsize;
342 int result = 0;
343
Nico Huber1ab60752012-05-23 09:21:54 +0200344 int hubaddr = 0, hubport = 0, non_hs_ctrl_ep = 0;
345 if (dev->speed < 2) {
346 /* we need a split transaction */
347 if (closest_usb2_hub(dev, &hubaddr, &hubport))
348 return 1;
349 non_hs_ctrl_ep = 1;
350 }
351
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000352 /* create qTDs */
353 qtd_t *head = memalign(32, sizeof(qtd_t));
354 qtd_t *cur = head;
355 memset(cur, 0, sizeof(qtd_t));
Patrick Georgi8fa27872011-11-24 13:19:57 +0100356 cur->token = QTD_ACTIVE |
357 (toggle?QTD_TOGGLE_DATA1:0) |
358 (EHCI_SETUP << QTD_PID_SHIFT) |
359 (3 << QTD_CERR_SHIFT);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000360 if (fill_td(cur, devreq, drlen) != drlen) {
361 printf("ERROR: couldn't send the entire device request\n");
362 }
363 qtd_t *next = memalign(32, sizeof(qtd_t));
364 cur->next_qtd = virt_to_phys(next);
Patrick Georgi8fa27872011-11-24 13:19:57 +0100365 cur->alt_next_qtd = QTD_TERMINATE;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000366
367 /* FIXME: We're limited to 16-20K (depending on alignment) for payload for now.
368 * Figure out, how toggle can be set sensibly in this scenario */
369 if (dalen > 0) {
370 toggle ^= 1;
371 cur = next;
372 memset(cur, 0, sizeof(qtd_t));
Patrick Georgi8fa27872011-11-24 13:19:57 +0100373 cur->token = QTD_ACTIVE |
374 (toggle?QTD_TOGGLE_DATA1:0) |
375 (((dir == OUT)?EHCI_OUT:EHCI_IN) << QTD_PID_SHIFT) |
376 (3 << QTD_CERR_SHIFT);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000377 if (fill_td(cur, data, dalen) != dalen) {
378 printf("ERROR: couldn't send the entire control payload\n");
379 }
380 next = memalign(32, sizeof(qtd_t));
381 cur->next_qtd = virt_to_phys(next);
Patrick Georgi8fa27872011-11-24 13:19:57 +0100382 cur->alt_next_qtd = QTD_TERMINATE;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000383 }
384
385 toggle = 1;
386 cur = next;
387 memset(cur, 0, sizeof(qtd_t));
Patrick Georgi8fa27872011-11-24 13:19:57 +0100388 cur->token = QTD_ACTIVE |
389 (toggle?QTD_TOGGLE_DATA1:QTD_TOGGLE_DATA0) |
390 ((dir == OUT)?EHCI_IN:EHCI_OUT) << QTD_PID_SHIFT |
391 (0 << QTD_CERR_SHIFT);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000392 fill_td(cur, NULL, 0);
Patrick Georgi8fa27872011-11-24 13:19:57 +0100393 cur->next_qtd = virt_to_phys(0) | QTD_TERMINATE;
394 cur->alt_next_qtd = QTD_TERMINATE;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000395
396 /* create QH */
397 ehci_qh_t *qh = memalign(32, sizeof(ehci_qh_t));
398 memset(qh, 0, sizeof(ehci_qh_t));
Patrick Georgi8fa27872011-11-24 13:19:57 +0100399 qh->horiz_link_ptr = virt_to_phys(qh) | QH_QH;
400 qh->epchar = dev->address |
401 (endp << QH_EP_SHIFT) |
402 (dev->speed << QH_EPS_SHIFT) |
403 (1 << QH_DTC_SHIFT) | /* ctrl transfers are special: take toggle bit from TD */
404 (1 << QH_RECLAIM_HEAD_SHIFT) |
405 (mlen << QH_MPS_SHIFT) |
Nico Huber1ab60752012-05-23 09:21:54 +0200406 (non_hs_ctrl_ep << QH_NON_HS_CTRL_EP_SHIFT) |
Patrick Georgi8fa27872011-11-24 13:19:57 +0100407 (0 << QH_NAK_CNT_SHIFT);
Nico Huber1ab60752012-05-23 09:21:54 +0200408 qh->epcaps = (3 << QH_PIPE_MULTIPLIER_SHIFT) |
409 (hubport << QH_PORT_NUMBER_SHIFT) |
410 (hubaddr << QH_HUB_ADDRESS_SHIFT);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000411 qh->td.next_qtd = virt_to_phys(head);
412
Nico Huber0421dc82012-05-21 14:53:43 +0200413 result = ehci_process_async_schedule(
414 EHCI_INST(dev->controller), qh, head);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000415
416 free_qh_and_tds(qh, head);
417 return result;
418}
419
Nico Huber62eb5b32012-05-25 10:09:13 +0200420
421typedef struct _intr_qtd_t intr_qtd_t;
422
423struct _intr_qtd_t {
424 volatile qtd_t td;
425 u8 *data;
426 intr_qtd_t *next;
427};
428
429typedef struct {
430 volatile ehci_qh_t qh;
431 intr_qtd_t *head;
432 intr_qtd_t *tail;
Nico Huber0d120f82012-06-14 13:08:36 +0200433 intr_qtd_t *spare;
Nico Huber62eb5b32012-05-25 10:09:13 +0200434 u8 *data;
435 endpoint_t *endp;
436 int reqsize;
437} intr_queue_t;
438
439static void fill_intr_queue_td(
440 intr_queue_t *const intrq,
441 intr_qtd_t *const intr_qtd,
442 u8 *const data)
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000443{
Nico Huber62eb5b32012-05-25 10:09:13 +0200444 const int pid = (intrq->endp->direction == IN) ? EHCI_IN
445 : (intrq->endp->direction == OUT) ? EHCI_OUT
446 : EHCI_SETUP;
447 const int cerr = (intrq->endp->dev->speed < 2) ? 1 : 0;
448
449 memset(intr_qtd, 0, sizeof(*intr_qtd));
450 intr_qtd->td.next_qtd = QTD_TERMINATE;
451 intr_qtd->td.alt_next_qtd = QTD_TERMINATE;
452 intr_qtd->td.token = QTD_ACTIVE |
453 (pid << QTD_PID_SHIFT) |
454 (cerr << QTD_CERR_SHIFT) |
455 ((intrq->endp->toggle & 1) << QTD_TOGGLE_SHIFT);
456 fill_td(&intr_qtd->td, data, intrq->reqsize);
457 intr_qtd->data = data;
458 intr_qtd->next = NULL;
459
460 intrq->endp->toggle ^= 1;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000461}
462
Nico Huber62eb5b32012-05-25 10:09:13 +0200463static void ehci_destroy_intr_queue(endpoint_t *const, void *const);
464
465static void *ehci_create_intr_queue(
466 endpoint_t *const ep,
467 const int reqsize,
468 int reqcount,
469 const int reqtiming)
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000470{
Nico Huber62eb5b32012-05-25 10:09:13 +0200471 int i;
472
473 if ((reqsize > (4 * 4096 + 1)) || /* the maximum for arbitrary aligned
474 data in five 4096 byte pages */
475 (reqtiming > 1024))
476 return NULL;
477 if (reqcount < 2) /* we need at least 2:
478 one for processing, one for the hc to advance to */
479 reqcount = 2;
480
481 int hubaddr = 0, hubport = 0;
482 if (ep->dev->speed < 2) {
483 /* we need a split transaction */
484 if (closest_usb2_hub(ep->dev, &hubaddr, &hubport))
485 return NULL;
486 }
487
488 intr_queue_t *const intrq =
489 (intr_queue_t *)memalign(32, sizeof(intr_queue_t));
Nico Huber0d120f82012-06-14 13:08:36 +0200490 /*
491 * reqcount data chunks
492 * plus one more spare, which we'll leave out of queue
493 */
494 u8 *data = (u8 *)malloc(reqsize * (reqcount + 1));
Nico Huber62eb5b32012-05-25 10:09:13 +0200495 if (!intrq || !data)
496 fatal("Not enough memory to create USB interrupt queue.\n");
497 intrq->data = data;
498 intrq->endp = ep;
499 intrq->reqsize = reqsize;
500
501 /* create #reqcount transfer descriptors (qTDs) */
502 intrq->head = (intr_qtd_t *)memalign(32, sizeof(intr_qtd_t));
503 intr_qtd_t *cur_td = intrq->head;
504 for (i = 0; i < reqcount; ++i) {
505 fill_intr_queue_td(intrq, cur_td, data);
506 data += reqsize;
507 if (i < reqcount - 1) {
508 /* create one more qTD */
509 intr_qtd_t *const next_td =
510 (intr_qtd_t *)memalign(32, sizeof(intr_qtd_t));
511 cur_td->td.next_qtd = virt_to_phys(&next_td->td);
512 cur_td->next = next_td;
513 cur_td = next_td;
514 }
515 }
516 intrq->tail = cur_td;
517
Nico Huber0d120f82012-06-14 13:08:36 +0200518 /* create spare qTD */
519 intrq->spare = (intr_qtd_t *)memalign(32, sizeof(intr_qtd_t));
520 fill_intr_queue_td(intrq, intrq->spare, data);
521
Nico Huber62eb5b32012-05-25 10:09:13 +0200522 /* initialize QH */
523 const int endp = ep->endpoint & 0xf;
524 memset(&intrq->qh, 0, sizeof(intrq->qh));
525 intrq->qh.horiz_link_ptr = PS_TERMINATE;
526 intrq->qh.epchar = ep->dev->address |
527 (endp << QH_EP_SHIFT) |
528 (ep->dev->speed << QH_EPS_SHIFT) |
529 (1 << QH_DTC_SHIFT) |
530 (0 << QH_RECLAIM_HEAD_SHIFT) |
531 (ep->maxpacketsize << QH_MPS_SHIFT) |
532 (0 << QH_NAK_CNT_SHIFT);
533 intrq->qh.epcaps = (1 << QH_PIPE_MULTIPLIER_SHIFT) |
534 (hubport << QH_PORT_NUMBER_SHIFT) |
535 (hubaddr << QH_HUB_ADDRESS_SHIFT) |
536 (0xfe << QH_UFRAME_CMASK_SHIFT) |
537 1 /* uFrame S-mask */;
538 intrq->qh.td.next_qtd = virt_to_phys(&intrq->head->td);
539
540 /* insert QH into periodic schedule */
541 int nothing_placed = 1;
542 u32 *const ps = (u32 *)phys_to_virt(EHCI_INST(ep->dev->controller)
543 ->operation->periodiclistbase);
Nico Huber3ca35ca2012-06-14 13:27:39 +0200544 const u32 dummy_ptr = virt_to_phys(EHCI_INST(
545 ep->dev->controller)->dummy_qh) | PS_TYPE_QH;
Nico Huber62eb5b32012-05-25 10:09:13 +0200546 for (i = 0; i < 1024; i += reqtiming) {
547 /* advance to the next free position */
Nico Huber3ca35ca2012-06-14 13:27:39 +0200548 while ((i < 1024) && (ps[i] != dummy_ptr)) ++i;
Nico Huber62eb5b32012-05-25 10:09:13 +0200549 if (i < 1024) {
550 ps[i] = virt_to_phys(&intrq->qh) | PS_TYPE_QH;
551 nothing_placed = 0;
552 }
553 }
554 if (nothing_placed) {
555 printf("Error: Failed to place ehci interrupt queue head "
556 "into periodic schedule: no space left\n");
557 ehci_destroy_intr_queue(ep, intrq);
558 return NULL;
559 }
560
561 return intrq;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000562}
563
Nico Huber62eb5b32012-05-25 10:09:13 +0200564static void ehci_destroy_intr_queue(endpoint_t *const ep, void *const queue)
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000565{
Nico Huber62eb5b32012-05-25 10:09:13 +0200566 intr_queue_t *const intrq = (intr_queue_t *)queue;
567
568 /* remove QH from periodic schedule */
569 int i;
570 u32 *const ps = (u32 *)phys_to_virt(EHCI_INST(
571 ep->dev->controller)->operation->periodiclistbase);
Nico Huber3ca35ca2012-06-14 13:27:39 +0200572 const u32 dummy_ptr = virt_to_phys(EHCI_INST(
573 ep->dev->controller)->dummy_qh) | PS_TYPE_QH;
Nico Huber62eb5b32012-05-25 10:09:13 +0200574 for (i = 0; i < 1024; ++i) {
575 if ((ps[i] & PS_PTR_MASK) == virt_to_phys(&intrq->qh))
Nico Huber3ca35ca2012-06-14 13:27:39 +0200576 ps[i] = dummy_ptr;
Nico Huber62eb5b32012-05-25 10:09:13 +0200577 }
578
579 /* wait 1ms for frame to end */
580 mdelay(1);
581
582 while (intrq->head) {
583 /* disable qTD and destroy list */
584 intrq->head->td.next_qtd = QTD_TERMINATE;
585 intrq->head->td.token &= ~QTD_ACTIVE;
586
587 /* save and advance head ptr */
588 intr_qtd_t *const to_free = intrq->head;
589 intrq->head = intrq->head->next;
590
591 /* free current interrupt qTD */
592 free(to_free);
593 }
Nico Huber0d120f82012-06-14 13:08:36 +0200594 free(intrq->spare);
Nico Huber62eb5b32012-05-25 10:09:13 +0200595 free(intrq->data);
596 free(intrq);
597}
598
599static u8 *ehci_poll_intr_queue(void *const queue)
600{
601 intr_queue_t *const intrq = (intr_queue_t *)queue;
602
603 u8 *ret = NULL;
604
605 /* process if head qTD is inactive AND QH has been moved forward */
Nico Huber0d120f82012-06-14 13:08:36 +0200606 if (!(intrq->head->td.token & QTD_ACTIVE)) {
Nico Huber62eb5b32012-05-25 10:09:13 +0200607 if (!(intrq->head->td.token & QTD_STATUS_MASK))
608 ret = intrq->head->data;
609 else
Gabe Black93ded592012-11-01 15:44:10 -0700610 usb_debug("ehci_poll_intr_queue: transfer failed, "
Nico Huber62eb5b32012-05-25 10:09:13 +0200611 "status == 0x%02x\n",
612 intrq->head->td.token & QTD_STATUS_MASK);
613
Nico Huber0d120f82012-06-14 13:08:36 +0200614 /* insert spare qTD at the end and advance our tail ptr */
615 fill_intr_queue_td(intrq, intrq->spare, intrq->spare->data);
616 intrq->tail->td.next_qtd = virt_to_phys(&intrq->spare->td);
617 intrq->tail->next = intrq->spare;
Nico Huber62eb5b32012-05-25 10:09:13 +0200618 intrq->tail = intrq->tail->next;
Nico Huber0d120f82012-06-14 13:08:36 +0200619
620 /* reuse executed qTD as spare one and advance our head ptr */
621 intrq->spare = intrq->head;
622 intrq->head = intrq->head->next;
623 }
624 /* reset queue if we fully processed it after underrun */
625 else if (intrq->qh.td.next_qtd & QTD_TERMINATE) {
Gabe Black93ded592012-11-01 15:44:10 -0700626 usb_debug("resetting underrun ehci interrupt queue.\n");
Nico Huber0d120f82012-06-14 13:08:36 +0200627 memset(&intrq->qh.td, 0, sizeof(intrq->qh.td));
628 intrq->qh.td.next_qtd = virt_to_phys(&intrq->head->td);
Nico Huber62eb5b32012-05-25 10:09:13 +0200629 }
630 return ret;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000631}
632
633hci_t *
634ehci_init (pcidev_t addr)
635{
636 int i;
637 hci_t *controller = new_controller ();
638
639 if (!controller)
Patrick Georgi2e768e72011-11-04 11:50:03 +0100640 fatal("Could not create USB controller instance.\n");
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000641
642 controller->instance = malloc (sizeof (ehci_t));
643 if(!controller->instance)
Patrick Georgi2e768e72011-11-04 11:50:03 +0100644 fatal("Not enough memory creating USB controller instance.\n");
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000645
646#define PCI_COMMAND 4
647#define PCI_COMMAND_IO 1
648#define PCI_COMMAND_MEMORY 2
649#define PCI_COMMAND_MASTER 4
650
651 u32 pci_command = pci_read_config32(addr, PCI_COMMAND);
652 pci_command = (pci_command | PCI_COMMAND_MEMORY) & ~PCI_COMMAND_IO ;
653 pci_write_config32(addr, PCI_COMMAND, pci_command);
654
Anton Kochkov1c36ead2012-06-28 08:30:15 +0400655 controller->type = EHCI;
656
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000657 controller->start = ehci_start;
658 controller->stop = ehci_stop;
659 controller->reset = ehci_reset;
660 controller->shutdown = ehci_shutdown;
661 controller->bulk = ehci_bulk;
662 controller->control = ehci_control;
663 controller->create_intr_queue = ehci_create_intr_queue;
664 controller->destroy_intr_queue = ehci_destroy_intr_queue;
665 controller->poll_intr_queue = ehci_poll_intr_queue;
Steven A. Falco9229af92011-07-13 21:01:26 -0400666 controller->bus_address = addr;
Anton Kochkov2e33a652012-06-20 04:03:37 +0400667 controller->reg_base = pci_read_config32 (controller->bus_address, USBBASE);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000668 for (i = 0; i < 128; i++) {
669 controller->devices[i] = 0;
670 }
671 init_device_entry (controller, 0);
672
Anton Kochkov2e33a652012-06-20 04:03:37 +0400673 EHCI_INST(controller)->capabilities = phys_to_virt(controller->reg_base);
674 EHCI_INST(controller)->operation = (hc_op_t *)(phys_to_virt(controller->reg_base) + EHCI_INST(controller)->capabilities->caplength);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000675
676 /* default value for frame length adjust */
677 pci_write_config8(addr, FLADJ, FLADJ_framelength(60000));
678
679 /* Enable operation of controller */
680 controller->start(controller);
681
682 /* take over all ports. USB1 should be blind now */
683 EHCI_INST(controller)->operation->configflag = 1;
684
Nico Huber62eb5b32012-05-25 10:09:13 +0200685 /* Initialize periodic frame list */
686 /* 1024 32-bit pointers, 4kb aligned */
687 u32 *const periodic_list = (u32 *)memalign(4096, 1024 * sizeof(u32));
688 if (!periodic_list)
689 fatal("Not enough memory creating EHCI periodic frame list.\n");
Nico Huber3ca35ca2012-06-14 13:27:39 +0200690
691 /*
692 * Insert dummy QH in periodic frame list
693 * This helps with broken host controllers
694 * and doesn't violate the standard.
695 */
696 EHCI_INST(controller)->dummy_qh = (ehci_qh_t *)memalign(32, sizeof(ehci_qh_t));
697 memset(EHCI_INST(controller)->dummy_qh, 0,
698 sizeof(*EHCI_INST(controller)->dummy_qh));
699 EHCI_INST(controller)->dummy_qh->horiz_link_ptr = QH_TERMINATE;
Nico Huber62eb5b32012-05-25 10:09:13 +0200700 for (i = 0; i < 1024; ++i)
Nico Huber3ca35ca2012-06-14 13:27:39 +0200701 periodic_list[i] = virt_to_phys(EHCI_INST(controller)->dummy_qh)
702 | PS_TYPE_QH;
Nico Huber62eb5b32012-05-25 10:09:13 +0200703
704 /* Make sure periodic schedule is disabled */
705 ehci_set_periodic_schedule(EHCI_INST(controller), 0);
706 /* Set periodic frame list pointer */
707 EHCI_INST(controller)->operation->periodiclistbase =
708 virt_to_phys(periodic_list);
709 /* Enable use of periodic schedule */
710 ehci_set_periodic_schedule(EHCI_INST(controller), 1);
711
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000712 /* TODO lots of stuff missing */
713
714 controller->devices[0]->controller = controller;
715 controller->devices[0]->init = ehci_rh_init;
716 controller->devices[0]->init (controller->devices[0]);
717
718 return controller;
719}