blob: 27e160b473ab01e3814246e11d36ab6388adfe0f [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);
Patrick Georgi8fa27872011-11-24 13:19:57 +010037 debug("td at phys(%x): status: %x\n\n", addr, td->token & QTD_STATUS_MASK);
38 debug("- cerr: %x, total_len: %x\n\n", (td->token & QTD_CERR_MASK) >> QTD_CERR_SHIFT,
39 (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{
54
55}
56
Nico Huber62eb5b32012-05-25 10:09:13 +020057static int ehci_set_periodic_schedule(ehci_t *ehcic, int enable)
58{
59 /* Set periodic schedule status. */
60 if (enable)
61 ehcic->operation->usbcmd |= HC_OP_PERIODIC_SCHED_EN;
62 else
63 ehcic->operation->usbcmd &= ~HC_OP_PERIODIC_SCHED_EN;
64 /* Wait for the controller to accept periodic schedule status.
65 * This shouldn't take too long, but we should timeout nevertheless.
66 */
67 enable = enable ? HC_OP_PERIODIC_SCHED_STAT : 0;
68 int timeout = 100; /* time out after 100ms */
69 while (((ehcic->operation->usbsts & HC_OP_PERIODIC_SCHED_STAT) != enable)
70 && timeout--)
71 mdelay(1);
72 if (timeout < 0) {
73 debug("ehci periodic schedule status change timed out.\n");
74 return 1;
75 }
76 return 0;
77}
78
Patrick Georgi7f43dc12010-09-25 17:01:13 +000079static void ehci_shutdown (hci_t *controller)
80{
Nico Huber62eb5b32012-05-25 10:09:13 +020081 /* Make sure periodic schedule is disabled */
82 ehci_set_periodic_schedule(EHCI_INST(controller), 0);
83 /* Free periodic frame list */
84 free(phys_to_virt(EHCI_INST(controller)->operation->periodiclistbase));
85
Patrick Georgi01178bb2011-11-04 11:57:46 +010086 EHCI_INST(controller)->operation->configflag = 0;
Patrick Georgi7f43dc12010-09-25 17:01:13 +000087}
88
89enum { EHCI_OUT=0, EHCI_IN=1, EHCI_SETUP=2 };
90
Nico Huber1ab60752012-05-23 09:21:54 +020091/*
92 * returns the address of the closest USB2.0 hub, which is responsible for
93 * split transactions, along with the number of the used downstream port
94 */
95static int closest_usb2_hub(const usbdev_t *dev, int *const addr, int *const port)
96{
97 const usbdev_t *usb1dev;
98 do {
99 usb1dev = dev;
100 if ((dev->hub > 0) && (dev->hub < 128))
101 dev = dev->controller->devices[dev->hub];
102 else
103 dev = NULL;
104 } while (dev && (dev->speed < 2));
105 if (dev) {
106 *addr = usb1dev->hub;
107 *port = usb1dev->port;
108 return 0;
109 } else {
110 debug("ehci: Couldn't find closest USB2.0 hub.\n");
111 return 1;
112 }
113}
114
Patrick Georgi8fa27872011-11-24 13:19:57 +0100115/* returns handled bytes. assumes that the fields it writes are empty on entry */
116static int fill_td(qtd_t *td, void* data, int datalen)
Stefan Reinauer528b43d2011-04-14 19:52:04 +0000117{
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000118 u32 total_len = 0;
Patrick Georgi8fa27872011-11-24 13:19:57 +0100119 u32 page_no = 0;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000120
121 u32 start = virt_to_phys(data);
122 u32 page = start & ~4095;
123 u32 offset = start & 4095;
124 u32 page_len = 4096 - offset;
125
Patrick Georgi8fa27872011-11-24 13:19:57 +0100126 td->token |= 0 << QTD_CPAGE_SHIFT;
127 td->bufptrs[page_no++] = start;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000128
129 if (datalen <= page_len) {
130 total_len = datalen;
131 } else {
132 datalen -= page_len;
133 total_len += page_len;
134
Patrick Georgi8fa27872011-11-24 13:19:57 +0100135 while (page_no < 5) {
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000136 /* we have a continguous mapping between virtual and physical memory */
137 page += 4096;
138
Patrick Georgi8fa27872011-11-24 13:19:57 +0100139 td->bufptrs[page_no++] = page;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000140 if (datalen <= 4096) {
141 total_len += datalen;
142 break;
143 }
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000144 datalen -= 4096;
145 total_len += 4096;
Patrick Georgi8fa27872011-11-24 13:19:57 +0100146 }
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000147 }
Patrick Georgi8fa27872011-11-24 13:19:57 +0100148 td->token |= total_len << QTD_TOTAL_LEN_SHIFT;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000149 return total_len;
150}
151
152/* free up data structures */
Patrick Georgi8fa27872011-11-24 13:19:57 +0100153static void free_qh_and_tds(ehci_qh_t *qh, qtd_t *cur)
Stefan Reinauer528b43d2011-04-14 19:52:04 +0000154{
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000155 qtd_t *next;
156 while (cur) {
157 next = (qtd_t*)phys_to_virt(cur->next_qtd & ~31);
158 free(cur);
159 cur = next;
160 }
161 free(qh);
162}
163
Patrick Georgi8fa27872011-11-24 13:19:57 +0100164static int wait_for_tds(qtd_t *head)
Stefan Reinauer528b43d2011-04-14 19:52:04 +0000165{
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000166 int result = 0;
167 qtd_t *cur = head;
168 while (1) {
169 if (0) dump_td(virt_to_phys(cur));
Nico Huber0421dc82012-05-21 14:53:43 +0200170
171 /* wait for results */
Nico Hubercef86922012-06-01 08:54:29 +0200172 /* how long to wait?
173 * tested with some USB2.0 flash sticks:
174 * TUR turn around took
175 * about 2s for the slowest (14cd:121c)
176 * max. 250ms for the others
177 * slowest non-TUR turn around took about 1.3s
178 * try 2s for now as a failed TUR is not fatal
Nico Huber0421dc82012-05-21 14:53:43 +0200179 */
Nico Hubercef86922012-06-01 08:54:29 +0200180 int timeout = 40000; /* time out after 40000 * 50us == 2s */
Nico Huber0421dc82012-05-21 14:53:43 +0200181 while ((cur->token & QTD_ACTIVE) && !(cur->token & QTD_HALTED)
182 && timeout--)
183 udelay(50);
184 if (timeout < 0) {
185 printf("Error: ehci: queue transfer "
186 "processing timed out.\n");
187 return 1;
188 }
Patrick Georgi8fa27872011-11-24 13:19:57 +0100189 if (cur->token & QTD_HALTED) {
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000190 printf("ERROR with packet\n");
191 dump_td(virt_to_phys(cur));
Mathias Krausec4716b42011-06-08 15:36:55 +0200192 debug("-----------------\n");
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000193 return 1;
194 }
195 if (cur->next_qtd & 1) {
196 return 0;
197 }
198 if (0) dump_td(virt_to_phys(cur));
199 /* helps debugging the TD chain */
Mathias Krausec4716b42011-06-08 15:36:55 +0200200 if (0) debug("\nmoving from %x to %x\n", cur, phys_to_virt(cur->next_qtd));
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000201 cur = phys_to_virt(cur->next_qtd);
202 }
203 return result;
204}
205
Nico Huber0421dc82012-05-21 14:53:43 +0200206static int ehci_set_async_schedule(ehci_t *ehcic, int enable)
207{
208 /* Set async schedule status. */
209 if (enable)
210 ehcic->operation->usbcmd |= HC_OP_ASYNC_SCHED_EN;
211 else
212 ehcic->operation->usbcmd &= ~HC_OP_ASYNC_SCHED_EN;
213 /* Wait for the controller to accept async schedule status.
214 * This shouldn't take too long, but we should timeout nevertheless.
215 */
216 enable = enable ? HC_OP_ASYNC_SCHED_STAT : 0;
217 int timeout = 100; /* time out after 100ms */
218 while (((ehcic->operation->usbsts & HC_OP_ASYNC_SCHED_STAT) != enable)
219 && timeout--)
220 mdelay(1);
221 if (timeout < 0) {
222 debug("ehci async schedule status change timed out.\n");
223 return 1;
224 }
225 return 0;
226}
227
228static int ehci_process_async_schedule(
229 ehci_t *ehcic, ehci_qh_t *qhead, qtd_t *head)
230{
231 int result;
232
233 /* make sure async schedule is disabled */
234 if (ehci_set_async_schedule(ehcic, 0)) return 1;
235
236 /* hook up QH */
237 ehcic->operation->asynclistaddr = virt_to_phys(qhead);
238
239 /* start async schedule */
240 if (ehci_set_async_schedule(ehcic, 1)) return 1;
241
242 /* wait for result */
243 result = wait_for_tds(head);
244
245 /* disable async schedule */
246 ehci_set_async_schedule(ehcic, 0);
247
248 return result;
249}
250
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000251static int ehci_bulk (endpoint_t *ep, int size, u8 *data, int finalize)
252{
253 int result = 0;
254 int endp = ep->endpoint & 0xf;
255 int pid = (ep->direction==IN)?EHCI_IN:EHCI_OUT;
256
Nico Huber1ab60752012-05-23 09:21:54 +0200257 int hubaddr = 0, hubport = 0;
258 if (ep->dev->speed < 2) {
259 /* we need a split transaction */
260 if (closest_usb2_hub(ep->dev, &hubaddr, &hubport))
261 return 1;
262 }
263
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000264 qtd_t *head = memalign(32, sizeof(qtd_t));
265 qtd_t *cur = head;
266 while (1) {
267 memset(cur, 0, sizeof(qtd_t));
Patrick Georgi8fa27872011-11-24 13:19:57 +0100268 cur->token = QTD_ACTIVE |
269 (pid << QTD_PID_SHIFT) |
270 (0 << QTD_CERR_SHIFT);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000271 u32 chunk = fill_td(cur, data, size);
272 size -= chunk;
273 data += chunk;
274
Patrick Georgi8fa27872011-11-24 13:19:57 +0100275 cur->alt_next_qtd = QTD_TERMINATE;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000276 if (size == 0) {
Patrick Georgi8fa27872011-11-24 13:19:57 +0100277 cur->next_qtd = virt_to_phys(0) | QTD_TERMINATE;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000278 break;
279 } else {
280 qtd_t *next = memalign(32, sizeof(qtd_t));
281 cur->next_qtd = virt_to_phys(next);
282 cur = next;
283 }
284 }
285
286 /* create QH */
287 ehci_qh_t *qh = memalign(32, sizeof(ehci_qh_t));
288 memset(qh, 0, sizeof(ehci_qh_t));
Patrick Georgi8fa27872011-11-24 13:19:57 +0100289 qh->horiz_link_ptr = virt_to_phys(qh) | QH_QH;
290 qh->epchar = ep->dev->address |
291 (endp << QH_EP_SHIFT) |
292 (ep->dev->speed << QH_EPS_SHIFT) |
293 (0 << QH_DTC_SHIFT) |
294 (1 << QH_RECLAIM_HEAD_SHIFT) |
295 (ep->maxpacketsize << QH_MPS_SHIFT) |
296 (0 << QH_NAK_CNT_SHIFT);
Nico Huber1ab60752012-05-23 09:21:54 +0200297 qh->epcaps = (3 << QH_PIPE_MULTIPLIER_SHIFT) |
298 (hubport << QH_PORT_NUMBER_SHIFT) |
299 (hubaddr << QH_HUB_ADDRESS_SHIFT);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000300
301 qh->td.next_qtd = virt_to_phys(head);
Patrick Georgi8fa27872011-11-24 13:19:57 +0100302 qh->td.token |= (ep->toggle?QTD_TOGGLE_DATA1:0);
303 head->token |= (ep->toggle?QTD_TOGGLE_DATA1:0);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000304
Nico Huber0421dc82012-05-21 14:53:43 +0200305 result = ehci_process_async_schedule(
306 EHCI_INST(ep->dev->controller), qh, head);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000307
Patrick Georgi8fa27872011-11-24 13:19:57 +0100308 ep->toggle = (cur->token & QTD_TOGGLE_MASK) >> QTD_TOGGLE_SHIFT;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000309
310 free_qh_and_tds(qh, head);
311 return result;
312}
313
314
315/* FIXME: Handle control transfers as 3 QHs, so the 2nd stage can be >0x4000 bytes */
316static int ehci_control (usbdev_t *dev, direction_t dir, int drlen, void *devreq,
317 int dalen, u8 *data)
318{
319 int endp = 0; // this is control. always 0 (for now)
320 int toggle = 0;
321 int mlen = dev->endpoints[0].maxpacketsize;
322 int result = 0;
323
Nico Huber1ab60752012-05-23 09:21:54 +0200324 int hubaddr = 0, hubport = 0, non_hs_ctrl_ep = 0;
325 if (dev->speed < 2) {
326 /* we need a split transaction */
327 if (closest_usb2_hub(dev, &hubaddr, &hubport))
328 return 1;
329 non_hs_ctrl_ep = 1;
330 }
331
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000332 /* create qTDs */
333 qtd_t *head = memalign(32, sizeof(qtd_t));
334 qtd_t *cur = head;
335 memset(cur, 0, sizeof(qtd_t));
Patrick Georgi8fa27872011-11-24 13:19:57 +0100336 cur->token = QTD_ACTIVE |
337 (toggle?QTD_TOGGLE_DATA1:0) |
338 (EHCI_SETUP << QTD_PID_SHIFT) |
339 (3 << QTD_CERR_SHIFT);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000340 if (fill_td(cur, devreq, drlen) != drlen) {
341 printf("ERROR: couldn't send the entire device request\n");
342 }
343 qtd_t *next = memalign(32, sizeof(qtd_t));
344 cur->next_qtd = virt_to_phys(next);
Patrick Georgi8fa27872011-11-24 13:19:57 +0100345 cur->alt_next_qtd = QTD_TERMINATE;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000346
347 /* FIXME: We're limited to 16-20K (depending on alignment) for payload for now.
348 * Figure out, how toggle can be set sensibly in this scenario */
349 if (dalen > 0) {
350 toggle ^= 1;
351 cur = next;
352 memset(cur, 0, sizeof(qtd_t));
Patrick Georgi8fa27872011-11-24 13:19:57 +0100353 cur->token = QTD_ACTIVE |
354 (toggle?QTD_TOGGLE_DATA1:0) |
355 (((dir == OUT)?EHCI_OUT:EHCI_IN) << QTD_PID_SHIFT) |
356 (3 << QTD_CERR_SHIFT);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000357 if (fill_td(cur, data, dalen) != dalen) {
358 printf("ERROR: couldn't send the entire control payload\n");
359 }
360 next = memalign(32, sizeof(qtd_t));
361 cur->next_qtd = virt_to_phys(next);
Patrick Georgi8fa27872011-11-24 13:19:57 +0100362 cur->alt_next_qtd = QTD_TERMINATE;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000363 }
364
365 toggle = 1;
366 cur = next;
367 memset(cur, 0, sizeof(qtd_t));
Patrick Georgi8fa27872011-11-24 13:19:57 +0100368 cur->token = QTD_ACTIVE |
369 (toggle?QTD_TOGGLE_DATA1:QTD_TOGGLE_DATA0) |
370 ((dir == OUT)?EHCI_IN:EHCI_OUT) << QTD_PID_SHIFT |
371 (0 << QTD_CERR_SHIFT);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000372 fill_td(cur, NULL, 0);
Patrick Georgi8fa27872011-11-24 13:19:57 +0100373 cur->next_qtd = virt_to_phys(0) | QTD_TERMINATE;
374 cur->alt_next_qtd = QTD_TERMINATE;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000375
376 /* create QH */
377 ehci_qh_t *qh = memalign(32, sizeof(ehci_qh_t));
378 memset(qh, 0, sizeof(ehci_qh_t));
Patrick Georgi8fa27872011-11-24 13:19:57 +0100379 qh->horiz_link_ptr = virt_to_phys(qh) | QH_QH;
380 qh->epchar = dev->address |
381 (endp << QH_EP_SHIFT) |
382 (dev->speed << QH_EPS_SHIFT) |
383 (1 << QH_DTC_SHIFT) | /* ctrl transfers are special: take toggle bit from TD */
384 (1 << QH_RECLAIM_HEAD_SHIFT) |
385 (mlen << QH_MPS_SHIFT) |
Nico Huber1ab60752012-05-23 09:21:54 +0200386 (non_hs_ctrl_ep << QH_NON_HS_CTRL_EP_SHIFT) |
Patrick Georgi8fa27872011-11-24 13:19:57 +0100387 (0 << QH_NAK_CNT_SHIFT);
Nico Huber1ab60752012-05-23 09:21:54 +0200388 qh->epcaps = (3 << QH_PIPE_MULTIPLIER_SHIFT) |
389 (hubport << QH_PORT_NUMBER_SHIFT) |
390 (hubaddr << QH_HUB_ADDRESS_SHIFT);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000391 qh->td.next_qtd = virt_to_phys(head);
392
Nico Huber0421dc82012-05-21 14:53:43 +0200393 result = ehci_process_async_schedule(
394 EHCI_INST(dev->controller), qh, head);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000395
396 free_qh_and_tds(qh, head);
397 return result;
398}
399
Nico Huber62eb5b32012-05-25 10:09:13 +0200400
401typedef struct _intr_qtd_t intr_qtd_t;
402
403struct _intr_qtd_t {
404 volatile qtd_t td;
405 u8 *data;
406 intr_qtd_t *next;
407};
408
409typedef struct {
410 volatile ehci_qh_t qh;
411 intr_qtd_t *head;
412 intr_qtd_t *tail;
413 u8 *data;
414 endpoint_t *endp;
415 int reqsize;
416} intr_queue_t;
417
418static void fill_intr_queue_td(
419 intr_queue_t *const intrq,
420 intr_qtd_t *const intr_qtd,
421 u8 *const data)
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000422{
Nico Huber62eb5b32012-05-25 10:09:13 +0200423 const int pid = (intrq->endp->direction == IN) ? EHCI_IN
424 : (intrq->endp->direction == OUT) ? EHCI_OUT
425 : EHCI_SETUP;
426 const int cerr = (intrq->endp->dev->speed < 2) ? 1 : 0;
427
428 memset(intr_qtd, 0, sizeof(*intr_qtd));
429 intr_qtd->td.next_qtd = QTD_TERMINATE;
430 intr_qtd->td.alt_next_qtd = QTD_TERMINATE;
431 intr_qtd->td.token = QTD_ACTIVE |
432 (pid << QTD_PID_SHIFT) |
433 (cerr << QTD_CERR_SHIFT) |
434 ((intrq->endp->toggle & 1) << QTD_TOGGLE_SHIFT);
435 fill_td(&intr_qtd->td, data, intrq->reqsize);
436 intr_qtd->data = data;
437 intr_qtd->next = NULL;
438
439 intrq->endp->toggle ^= 1;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000440}
441
Nico Huber62eb5b32012-05-25 10:09:13 +0200442static void ehci_destroy_intr_queue(endpoint_t *const, void *const);
443
444static void *ehci_create_intr_queue(
445 endpoint_t *const ep,
446 const int reqsize,
447 int reqcount,
448 const int reqtiming)
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000449{
Nico Huber62eb5b32012-05-25 10:09:13 +0200450 int i;
451
452 if ((reqsize > (4 * 4096 + 1)) || /* the maximum for arbitrary aligned
453 data in five 4096 byte pages */
454 (reqtiming > 1024))
455 return NULL;
456 if (reqcount < 2) /* we need at least 2:
457 one for processing, one for the hc to advance to */
458 reqcount = 2;
459
460 int hubaddr = 0, hubport = 0;
461 if (ep->dev->speed < 2) {
462 /* we need a split transaction */
463 if (closest_usb2_hub(ep->dev, &hubaddr, &hubport))
464 return NULL;
465 }
466
467 intr_queue_t *const intrq =
468 (intr_queue_t *)memalign(32, sizeof(intr_queue_t));
469 u8 *data = (u8 *)malloc(reqsize * reqcount);
470 if (!intrq || !data)
471 fatal("Not enough memory to create USB interrupt queue.\n");
472 intrq->data = data;
473 intrq->endp = ep;
474 intrq->reqsize = reqsize;
475
476 /* create #reqcount transfer descriptors (qTDs) */
477 intrq->head = (intr_qtd_t *)memalign(32, sizeof(intr_qtd_t));
478 intr_qtd_t *cur_td = intrq->head;
479 for (i = 0; i < reqcount; ++i) {
480 fill_intr_queue_td(intrq, cur_td, data);
481 data += reqsize;
482 if (i < reqcount - 1) {
483 /* create one more qTD */
484 intr_qtd_t *const next_td =
485 (intr_qtd_t *)memalign(32, sizeof(intr_qtd_t));
486 cur_td->td.next_qtd = virt_to_phys(&next_td->td);
487 cur_td->next = next_td;
488 cur_td = next_td;
489 }
490 }
491 intrq->tail = cur_td;
492
493 /* initialize QH */
494 const int endp = ep->endpoint & 0xf;
495 memset(&intrq->qh, 0, sizeof(intrq->qh));
496 intrq->qh.horiz_link_ptr = PS_TERMINATE;
497 intrq->qh.epchar = ep->dev->address |
498 (endp << QH_EP_SHIFT) |
499 (ep->dev->speed << QH_EPS_SHIFT) |
500 (1 << QH_DTC_SHIFT) |
501 (0 << QH_RECLAIM_HEAD_SHIFT) |
502 (ep->maxpacketsize << QH_MPS_SHIFT) |
503 (0 << QH_NAK_CNT_SHIFT);
504 intrq->qh.epcaps = (1 << QH_PIPE_MULTIPLIER_SHIFT) |
505 (hubport << QH_PORT_NUMBER_SHIFT) |
506 (hubaddr << QH_HUB_ADDRESS_SHIFT) |
507 (0xfe << QH_UFRAME_CMASK_SHIFT) |
508 1 /* uFrame S-mask */;
509 intrq->qh.td.next_qtd = virt_to_phys(&intrq->head->td);
510
511 /* insert QH into periodic schedule */
512 int nothing_placed = 1;
513 u32 *const ps = (u32 *)phys_to_virt(EHCI_INST(ep->dev->controller)
514 ->operation->periodiclistbase);
515 for (i = 0; i < 1024; i += reqtiming) {
516 /* advance to the next free position */
517 while ((i < 1024) && !(ps[i] & PS_TERMINATE)) ++i;
518 if (i < 1024) {
519 ps[i] = virt_to_phys(&intrq->qh) | PS_TYPE_QH;
520 nothing_placed = 0;
521 }
522 }
523 if (nothing_placed) {
524 printf("Error: Failed to place ehci interrupt queue head "
525 "into periodic schedule: no space left\n");
526 ehci_destroy_intr_queue(ep, intrq);
527 return NULL;
528 }
529
530 return intrq;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000531}
532
Nico Huber62eb5b32012-05-25 10:09:13 +0200533static void ehci_destroy_intr_queue(endpoint_t *const ep, void *const queue)
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000534{
Nico Huber62eb5b32012-05-25 10:09:13 +0200535 intr_queue_t *const intrq = (intr_queue_t *)queue;
536
537 /* remove QH from periodic schedule */
538 int i;
539 u32 *const ps = (u32 *)phys_to_virt(EHCI_INST(
540 ep->dev->controller)->operation->periodiclistbase);
541 for (i = 0; i < 1024; ++i) {
542 if ((ps[i] & PS_PTR_MASK) == virt_to_phys(&intrq->qh))
543 ps[i] = PS_TERMINATE;
544 }
545
546 /* wait 1ms for frame to end */
547 mdelay(1);
548
549 while (intrq->head) {
550 /* disable qTD and destroy list */
551 intrq->head->td.next_qtd = QTD_TERMINATE;
552 intrq->head->td.token &= ~QTD_ACTIVE;
553
554 /* save and advance head ptr */
555 intr_qtd_t *const to_free = intrq->head;
556 intrq->head = intrq->head->next;
557
558 /* free current interrupt qTD */
559 free(to_free);
560 }
561 free(intrq->data);
562 free(intrq);
563}
564
565static u8 *ehci_poll_intr_queue(void *const queue)
566{
567 intr_queue_t *const intrq = (intr_queue_t *)queue;
568
569 u8 *ret = NULL;
570
571 /* process if head qTD is inactive AND QH has been moved forward */
572 if (!(intrq->head->td.token & QTD_ACTIVE) &&
573 (intrq->qh.current_td_ptr !=
574 virt_to_phys(&intrq->head->td))) {
575 if (!(intrq->head->td.token & QTD_STATUS_MASK))
576 ret = intrq->head->data;
577 else
578 debug("ehci_poll_intr_queue: transfer failed, "
579 "status == 0x%02x\n",
580 intrq->head->td.token & QTD_STATUS_MASK);
581
582 /* save and advance our head ptr */
583 intr_qtd_t *const new_td = intrq->head;
584 intrq->head = intrq->head->next;
585
586 /* reuse executed qTD */
587 fill_intr_queue_td(intrq, new_td, new_td->data);
588
589 /* at last insert reused qTD at the
590 * end and advance our tail ptr */
591 intrq->tail->td.next_qtd = virt_to_phys(&new_td->td);
592 intrq->tail->next = new_td;
593 intrq->tail = intrq->tail->next;
594 }
595 return ret;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000596}
597
598hci_t *
599ehci_init (pcidev_t addr)
600{
601 int i;
602 hci_t *controller = new_controller ();
603
604 if (!controller)
Patrick Georgi2e768e72011-11-04 11:50:03 +0100605 fatal("Could not create USB controller instance.\n");
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000606
607 controller->instance = malloc (sizeof (ehci_t));
608 if(!controller->instance)
Patrick Georgi2e768e72011-11-04 11:50:03 +0100609 fatal("Not enough memory creating USB controller instance.\n");
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000610
611#define PCI_COMMAND 4
612#define PCI_COMMAND_IO 1
613#define PCI_COMMAND_MEMORY 2
614#define PCI_COMMAND_MASTER 4
615
616 u32 pci_command = pci_read_config32(addr, PCI_COMMAND);
617 pci_command = (pci_command | PCI_COMMAND_MEMORY) & ~PCI_COMMAND_IO ;
618 pci_write_config32(addr, PCI_COMMAND, pci_command);
619
620 controller->start = ehci_start;
621 controller->stop = ehci_stop;
622 controller->reset = ehci_reset;
623 controller->shutdown = ehci_shutdown;
624 controller->bulk = ehci_bulk;
625 controller->control = ehci_control;
626 controller->create_intr_queue = ehci_create_intr_queue;
627 controller->destroy_intr_queue = ehci_destroy_intr_queue;
628 controller->poll_intr_queue = ehci_poll_intr_queue;
Steven A. Falco9229af92011-07-13 21:01:26 -0400629 controller->bus_address = addr;
Anton Kochkov2e33a652012-06-20 04:03:37 +0400630 controller->reg_base = pci_read_config32 (controller->bus_address, USBBASE);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000631 for (i = 0; i < 128; i++) {
632 controller->devices[i] = 0;
633 }
634 init_device_entry (controller, 0);
635
Anton Kochkov2e33a652012-06-20 04:03:37 +0400636 EHCI_INST(controller)->capabilities = phys_to_virt(controller->reg_base);
637 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 +0000638
639 /* default value for frame length adjust */
640 pci_write_config8(addr, FLADJ, FLADJ_framelength(60000));
641
642 /* Enable operation of controller */
643 controller->start(controller);
644
645 /* take over all ports. USB1 should be blind now */
646 EHCI_INST(controller)->operation->configflag = 1;
647
Nico Huber62eb5b32012-05-25 10:09:13 +0200648 /* Initialize periodic frame list */
649 /* 1024 32-bit pointers, 4kb aligned */
650 u32 *const periodic_list = (u32 *)memalign(4096, 1024 * sizeof(u32));
651 if (!periodic_list)
652 fatal("Not enough memory creating EHCI periodic frame list.\n");
653 for (i = 0; i < 1024; ++i)
654 periodic_list[i] = PS_TERMINATE;
655
656 /* Make sure periodic schedule is disabled */
657 ehci_set_periodic_schedule(EHCI_INST(controller), 0);
658 /* Set periodic frame list pointer */
659 EHCI_INST(controller)->operation->periodiclistbase =
660 virt_to_phys(periodic_list);
661 /* Enable use of periodic schedule */
662 ehci_set_periodic_schedule(EHCI_INST(controller), 1);
663
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000664 /* TODO lots of stuff missing */
665
666 controller->devices[0]->controller = controller;
667 controller->devices[0]->init = ehci_rh_init;
668 controller->devices[0]->init (controller->devices[0]);
669
670 return controller;
671}