blob: c8f469e60662cad4b0c988004d1a2e8d0502abaa [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
57static void ehci_shutdown (hci_t *controller)
58{
Patrick Georgi01178bb2011-11-04 11:57:46 +010059 EHCI_INST(controller)->operation->configflag = 0;
Patrick Georgi7f43dc12010-09-25 17:01:13 +000060}
61
62enum { EHCI_OUT=0, EHCI_IN=1, EHCI_SETUP=2 };
63
Nico Huber1ab60752012-05-23 09:21:54 +020064/*
65 * returns the address of the closest USB2.0 hub, which is responsible for
66 * split transactions, along with the number of the used downstream port
67 */
68static int closest_usb2_hub(const usbdev_t *dev, int *const addr, int *const port)
69{
70 const usbdev_t *usb1dev;
71 do {
72 usb1dev = dev;
73 if ((dev->hub > 0) && (dev->hub < 128))
74 dev = dev->controller->devices[dev->hub];
75 else
76 dev = NULL;
77 } while (dev && (dev->speed < 2));
78 if (dev) {
79 *addr = usb1dev->hub;
80 *port = usb1dev->port;
81 return 0;
82 } else {
83 debug("ehci: Couldn't find closest USB2.0 hub.\n");
84 return 1;
85 }
86}
87
Patrick Georgi8fa27872011-11-24 13:19:57 +010088/* returns handled bytes. assumes that the fields it writes are empty on entry */
89static int fill_td(qtd_t *td, void* data, int datalen)
Stefan Reinauer528b43d2011-04-14 19:52:04 +000090{
Patrick Georgi7f43dc12010-09-25 17:01:13 +000091 u32 total_len = 0;
Patrick Georgi8fa27872011-11-24 13:19:57 +010092 u32 page_no = 0;
Patrick Georgi7f43dc12010-09-25 17:01:13 +000093
94 u32 start = virt_to_phys(data);
95 u32 page = start & ~4095;
96 u32 offset = start & 4095;
97 u32 page_len = 4096 - offset;
98
Patrick Georgi8fa27872011-11-24 13:19:57 +010099 td->token |= 0 << QTD_CPAGE_SHIFT;
100 td->bufptrs[page_no++] = start;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000101
102 if (datalen <= page_len) {
103 total_len = datalen;
104 } else {
105 datalen -= page_len;
106 total_len += page_len;
107
Patrick Georgi8fa27872011-11-24 13:19:57 +0100108 while (page_no < 5) {
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000109 /* we have a continguous mapping between virtual and physical memory */
110 page += 4096;
111
Patrick Georgi8fa27872011-11-24 13:19:57 +0100112 td->bufptrs[page_no++] = page;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000113 if (datalen <= 4096) {
114 total_len += datalen;
115 break;
116 }
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000117 datalen -= 4096;
118 total_len += 4096;
Patrick Georgi8fa27872011-11-24 13:19:57 +0100119 }
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000120 }
Patrick Georgi8fa27872011-11-24 13:19:57 +0100121 td->token |= total_len << QTD_TOTAL_LEN_SHIFT;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000122 return total_len;
123}
124
125/* free up data structures */
Patrick Georgi8fa27872011-11-24 13:19:57 +0100126static void free_qh_and_tds(ehci_qh_t *qh, qtd_t *cur)
Stefan Reinauer528b43d2011-04-14 19:52:04 +0000127{
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000128 qtd_t *next;
129 while (cur) {
130 next = (qtd_t*)phys_to_virt(cur->next_qtd & ~31);
131 free(cur);
132 cur = next;
133 }
134 free(qh);
135}
136
Patrick Georgi8fa27872011-11-24 13:19:57 +0100137static int wait_for_tds(qtd_t *head)
Stefan Reinauer528b43d2011-04-14 19:52:04 +0000138{
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000139 int result = 0;
140 qtd_t *cur = head;
141 while (1) {
142 if (0) dump_td(virt_to_phys(cur));
Patrick Georgi8fa27872011-11-24 13:19:57 +0100143 while ((cur->token & QTD_ACTIVE) && !(cur->token & QTD_HALTED)) udelay(60);
144 if (cur->token & QTD_HALTED) {
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000145 printf("ERROR with packet\n");
146 dump_td(virt_to_phys(cur));
Mathias Krausec4716b42011-06-08 15:36:55 +0200147 debug("-----------------\n");
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000148 return 1;
149 }
150 if (cur->next_qtd & 1) {
151 return 0;
152 }
153 if (0) dump_td(virt_to_phys(cur));
154 /* helps debugging the TD chain */
Mathias Krausec4716b42011-06-08 15:36:55 +0200155 if (0) debug("\nmoving from %x to %x\n", cur, phys_to_virt(cur->next_qtd));
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000156 cur = phys_to_virt(cur->next_qtd);
157 }
158 return result;
159}
160
161static int ehci_bulk (endpoint_t *ep, int size, u8 *data, int finalize)
162{
163 int result = 0;
164 int endp = ep->endpoint & 0xf;
165 int pid = (ep->direction==IN)?EHCI_IN:EHCI_OUT;
166
Nico Huber1ab60752012-05-23 09:21:54 +0200167 int hubaddr = 0, hubport = 0;
168 if (ep->dev->speed < 2) {
169 /* we need a split transaction */
170 if (closest_usb2_hub(ep->dev, &hubaddr, &hubport))
171 return 1;
172 }
173
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000174 qtd_t *head = memalign(32, sizeof(qtd_t));
175 qtd_t *cur = head;
176 while (1) {
177 memset(cur, 0, sizeof(qtd_t));
Patrick Georgi8fa27872011-11-24 13:19:57 +0100178 cur->token = QTD_ACTIVE |
179 (pid << QTD_PID_SHIFT) |
180 (0 << QTD_CERR_SHIFT);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000181 u32 chunk = fill_td(cur, data, size);
182 size -= chunk;
183 data += chunk;
184
Patrick Georgi8fa27872011-11-24 13:19:57 +0100185 cur->alt_next_qtd = QTD_TERMINATE;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000186 if (size == 0) {
Patrick Georgi8fa27872011-11-24 13:19:57 +0100187 cur->next_qtd = virt_to_phys(0) | QTD_TERMINATE;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000188 break;
189 } else {
190 qtd_t *next = memalign(32, sizeof(qtd_t));
191 cur->next_qtd = virt_to_phys(next);
192 cur = next;
193 }
194 }
195
196 /* create QH */
197 ehci_qh_t *qh = memalign(32, sizeof(ehci_qh_t));
198 memset(qh, 0, sizeof(ehci_qh_t));
Patrick Georgi8fa27872011-11-24 13:19:57 +0100199 qh->horiz_link_ptr = virt_to_phys(qh) | QH_QH;
200 qh->epchar = ep->dev->address |
201 (endp << QH_EP_SHIFT) |
202 (ep->dev->speed << QH_EPS_SHIFT) |
203 (0 << QH_DTC_SHIFT) |
204 (1 << QH_RECLAIM_HEAD_SHIFT) |
205 (ep->maxpacketsize << QH_MPS_SHIFT) |
206 (0 << QH_NAK_CNT_SHIFT);
Nico Huber1ab60752012-05-23 09:21:54 +0200207 qh->epcaps = (3 << QH_PIPE_MULTIPLIER_SHIFT) |
208 (hubport << QH_PORT_NUMBER_SHIFT) |
209 (hubaddr << QH_HUB_ADDRESS_SHIFT);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000210
211 qh->td.next_qtd = virt_to_phys(head);
Patrick Georgi8fa27872011-11-24 13:19:57 +0100212 qh->td.token |= (ep->toggle?QTD_TOGGLE_DATA1:0);
213 head->token |= (ep->toggle?QTD_TOGGLE_DATA1:0);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000214
215 /* hook up QH */
216 EHCI_INST(ep->dev->controller)->operation->asynclistaddr = virt_to_phys(qh);
217
218 /* start async schedule */
Patrick Georgi8fa27872011-11-24 13:19:57 +0100219 EHCI_INST(ep->dev->controller)->operation->usbcmd |= HC_OP_ASYNC_SCHED_EN;
220 while (!(EHCI_INST(ep->dev->controller)->operation->usbsts & HC_OP_ASYNC_SCHED_STAT)) ; /* wait */
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000221
222 /* wait for result */
223 result = wait_for_tds(head);
224
225 /* disable async schedule */
Patrick Georgi8fa27872011-11-24 13:19:57 +0100226 EHCI_INST(ep->dev->controller)->operation->usbcmd &= ~HC_OP_ASYNC_SCHED_EN;
227 while (EHCI_INST(ep->dev->controller)->operation->usbsts & HC_OP_ASYNC_SCHED_STAT) ; /* wait */
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000228
Patrick Georgi8fa27872011-11-24 13:19:57 +0100229 ep->toggle = (cur->token & QTD_TOGGLE_MASK) >> QTD_TOGGLE_SHIFT;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000230
231 free_qh_and_tds(qh, head);
232 return result;
233}
234
235
236/* FIXME: Handle control transfers as 3 QHs, so the 2nd stage can be >0x4000 bytes */
237static int ehci_control (usbdev_t *dev, direction_t dir, int drlen, void *devreq,
238 int dalen, u8 *data)
239{
240 int endp = 0; // this is control. always 0 (for now)
241 int toggle = 0;
242 int mlen = dev->endpoints[0].maxpacketsize;
243 int result = 0;
244
Nico Huber1ab60752012-05-23 09:21:54 +0200245 int hubaddr = 0, hubport = 0, non_hs_ctrl_ep = 0;
246 if (dev->speed < 2) {
247 /* we need a split transaction */
248 if (closest_usb2_hub(dev, &hubaddr, &hubport))
249 return 1;
250 non_hs_ctrl_ep = 1;
251 }
252
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000253 /* create qTDs */
254 qtd_t *head = memalign(32, sizeof(qtd_t));
255 qtd_t *cur = head;
256 memset(cur, 0, sizeof(qtd_t));
Patrick Georgi8fa27872011-11-24 13:19:57 +0100257 cur->token = QTD_ACTIVE |
258 (toggle?QTD_TOGGLE_DATA1:0) |
259 (EHCI_SETUP << QTD_PID_SHIFT) |
260 (3 << QTD_CERR_SHIFT);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000261 if (fill_td(cur, devreq, drlen) != drlen) {
262 printf("ERROR: couldn't send the entire device request\n");
263 }
264 qtd_t *next = memalign(32, sizeof(qtd_t));
265 cur->next_qtd = virt_to_phys(next);
Patrick Georgi8fa27872011-11-24 13:19:57 +0100266 cur->alt_next_qtd = QTD_TERMINATE;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000267
268 /* FIXME: We're limited to 16-20K (depending on alignment) for payload for now.
269 * Figure out, how toggle can be set sensibly in this scenario */
270 if (dalen > 0) {
271 toggle ^= 1;
272 cur = next;
273 memset(cur, 0, sizeof(qtd_t));
Patrick Georgi8fa27872011-11-24 13:19:57 +0100274 cur->token = QTD_ACTIVE |
275 (toggle?QTD_TOGGLE_DATA1:0) |
276 (((dir == OUT)?EHCI_OUT:EHCI_IN) << QTD_PID_SHIFT) |
277 (3 << QTD_CERR_SHIFT);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000278 if (fill_td(cur, data, dalen) != dalen) {
279 printf("ERROR: couldn't send the entire control payload\n");
280 }
281 next = memalign(32, sizeof(qtd_t));
282 cur->next_qtd = virt_to_phys(next);
Patrick Georgi8fa27872011-11-24 13:19:57 +0100283 cur->alt_next_qtd = QTD_TERMINATE;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000284 }
285
286 toggle = 1;
287 cur = next;
288 memset(cur, 0, sizeof(qtd_t));
Patrick Georgi8fa27872011-11-24 13:19:57 +0100289 cur->token = QTD_ACTIVE |
290 (toggle?QTD_TOGGLE_DATA1:QTD_TOGGLE_DATA0) |
291 ((dir == OUT)?EHCI_IN:EHCI_OUT) << QTD_PID_SHIFT |
292 (0 << QTD_CERR_SHIFT);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000293 fill_td(cur, NULL, 0);
Patrick Georgi8fa27872011-11-24 13:19:57 +0100294 cur->next_qtd = virt_to_phys(0) | QTD_TERMINATE;
295 cur->alt_next_qtd = QTD_TERMINATE;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000296
297 /* create QH */
298 ehci_qh_t *qh = memalign(32, sizeof(ehci_qh_t));
299 memset(qh, 0, sizeof(ehci_qh_t));
Patrick Georgi8fa27872011-11-24 13:19:57 +0100300 qh->horiz_link_ptr = virt_to_phys(qh) | QH_QH;
301 qh->epchar = dev->address |
302 (endp << QH_EP_SHIFT) |
303 (dev->speed << QH_EPS_SHIFT) |
304 (1 << QH_DTC_SHIFT) | /* ctrl transfers are special: take toggle bit from TD */
305 (1 << QH_RECLAIM_HEAD_SHIFT) |
306 (mlen << QH_MPS_SHIFT) |
Nico Huber1ab60752012-05-23 09:21:54 +0200307 (non_hs_ctrl_ep << QH_NON_HS_CTRL_EP_SHIFT) |
Patrick Georgi8fa27872011-11-24 13:19:57 +0100308 (0 << QH_NAK_CNT_SHIFT);
Nico Huber1ab60752012-05-23 09:21:54 +0200309 qh->epcaps = (3 << QH_PIPE_MULTIPLIER_SHIFT) |
310 (hubport << QH_PORT_NUMBER_SHIFT) |
311 (hubaddr << QH_HUB_ADDRESS_SHIFT);
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000312 qh->td.next_qtd = virt_to_phys(head);
313
314 /* hook up QH */
315 EHCI_INST(dev->controller)->operation->asynclistaddr = virt_to_phys(qh);
316
317 /* start async schedule */
Patrick Georgi8fa27872011-11-24 13:19:57 +0100318 EHCI_INST(dev->controller)->operation->usbcmd |= HC_OP_ASYNC_SCHED_EN;
319 while (!(EHCI_INST(dev->controller)->operation->usbsts & HC_OP_ASYNC_SCHED_STAT)) ; /* wait */
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000320
321 result = wait_for_tds(head);
322
323 /* disable async schedule */
Patrick Georgi8fa27872011-11-24 13:19:57 +0100324 EHCI_INST(dev->controller)->operation->usbcmd &= ~HC_OP_ASYNC_SCHED_EN;
325 while (EHCI_INST(dev->controller)->operation->usbsts & HC_OP_ASYNC_SCHED_STAT) ; /* wait */
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000326
327 free_qh_and_tds(qh, head);
328 return result;
329}
330
331static void* ehci_create_intr_queue (endpoint_t *ep, int reqsize, int reqcount, int reqtiming)
332{
333 return NULL;
334}
335
336static void ehci_destroy_intr_queue (endpoint_t *ep, void *queue)
337{
338}
339
340static u8* ehci_poll_intr_queue (void *queue)
341{
342 return NULL;
343}
344
345hci_t *
346ehci_init (pcidev_t addr)
347{
348 int i;
349 hci_t *controller = new_controller ();
350
351 if (!controller)
Patrick Georgi2e768e72011-11-04 11:50:03 +0100352 fatal("Could not create USB controller instance.\n");
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000353
354 controller->instance = malloc (sizeof (ehci_t));
355 if(!controller->instance)
Patrick Georgi2e768e72011-11-04 11:50:03 +0100356 fatal("Not enough memory creating USB controller instance.\n");
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000357
358#define PCI_COMMAND 4
359#define PCI_COMMAND_IO 1
360#define PCI_COMMAND_MEMORY 2
361#define PCI_COMMAND_MASTER 4
362
363 u32 pci_command = pci_read_config32(addr, PCI_COMMAND);
364 pci_command = (pci_command | PCI_COMMAND_MEMORY) & ~PCI_COMMAND_IO ;
365 pci_write_config32(addr, PCI_COMMAND, pci_command);
366
367 controller->start = ehci_start;
368 controller->stop = ehci_stop;
369 controller->reset = ehci_reset;
370 controller->shutdown = ehci_shutdown;
371 controller->bulk = ehci_bulk;
372 controller->control = ehci_control;
373 controller->create_intr_queue = ehci_create_intr_queue;
374 controller->destroy_intr_queue = ehci_destroy_intr_queue;
375 controller->poll_intr_queue = ehci_poll_intr_queue;
Steven A. Falco9229af92011-07-13 21:01:26 -0400376 controller->bus_address = addr;
Patrick Georgi7f43dc12010-09-25 17:01:13 +0000377 for (i = 0; i < 128; i++) {
378 controller->devices[i] = 0;
379 }
380 init_device_entry (controller, 0);
381
382 EHCI_INST(controller)->capabilities = phys_to_virt(pci_read_config32(addr, USBBASE));
383 EHCI_INST(controller)->operation = (hc_op_t *)(phys_to_virt(pci_read_config32(addr, USBBASE)) + EHCI_INST(controller)->capabilities->caplength);
384
385 /* default value for frame length adjust */
386 pci_write_config8(addr, FLADJ, FLADJ_framelength(60000));
387
388 /* Enable operation of controller */
389 controller->start(controller);
390
391 /* take over all ports. USB1 should be blind now */
392 EHCI_INST(controller)->operation->configflag = 1;
393
394 /* TODO lots of stuff missing */
395
396 controller->devices[0]->controller = controller;
397 controller->devices[0]->init = ehci_rh_init;
398 controller->devices[0]->init (controller->devices[0]);
399
400 return controller;
401}