blob: 2a8bcb448e75920bbf61b14a15c666a7962c08eb [file] [log] [blame]
Patrick Georgi6615ef32010-08-13 09:18:58 +00001/*
2 * This file is part of the libpayload project.
3 *
4 * Copyright (C) 2010 Patrick Georgi
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#define USB_DEBUG
31
32#include <arch/virtual.h>
33#include "xhci.h"
34#include "xhci_private.h"
35
36static void xhci_start (hci_t *controller);
37static void xhci_stop (hci_t *controller);
38static void xhci_reset (hci_t *controller);
39static void xhci_shutdown (hci_t *controller);
40static int xhci_bulk (endpoint_t *ep, int size, u8 *data, int finalize);
41static int xhci_control (usbdev_t *dev, direction_t dir, int drlen, void *devreq,
42 int dalen, u8 *data);
43static void* xhci_create_intr_queue (endpoint_t *ep, int reqsize, int reqcount, int reqtiming);
44static void xhci_destroy_intr_queue (endpoint_t *ep, void *queue);
45static u8* xhci_poll_intr_queue (void *queue);
46
47static void
48xhci_reset (hci_t *controller)
49{
50}
51
Nico Huber6e711c62012-11-12 16:20:32 +010052static void
53xhci_reinit (hci_t *controller)
54{
55}
56
Patrick Georgi6615ef32010-08-13 09:18:58 +000057hci_t *
58xhci_init (pcidev_t addr)
59{
60 int i;
61
62 hci_t *controller = new_controller ();
63
64 if (!controller)
Patrick Georgi2e768e72011-11-04 11:50:03 +010065 fatal("Could not create USB controller instance.\n");
Patrick Georgi6615ef32010-08-13 09:18:58 +000066
67 controller->instance = malloc (sizeof (xhci_t));
68 if(!controller->instance)
Patrick Georgi2e768e72011-11-04 11:50:03 +010069 fatal("Not enough memory creating USB controller instance.\n");
Patrick Georgi6615ef32010-08-13 09:18:58 +000070
Anton Kochkov1c36ead2012-06-28 08:30:15 +040071 controller->type = XHCI;
72
Patrick Georgi6615ef32010-08-13 09:18:58 +000073 controller->start = xhci_start;
74 controller->stop = xhci_stop;
75 controller->reset = xhci_reset;
Nico Huber6e711c62012-11-12 16:20:32 +010076 controller->init = xhci_reinit;
Patrick Georgi6615ef32010-08-13 09:18:58 +000077 controller->shutdown = xhci_shutdown;
78 controller->bulk = xhci_bulk;
79 controller->control = xhci_control;
80 controller->create_intr_queue = xhci_create_intr_queue;
81 controller->destroy_intr_queue = xhci_destroy_intr_queue;
82 controller->poll_intr_queue = xhci_poll_intr_queue;
83 for (i = 0; i < 128; i++) {
84 controller->devices[i] = 0;
85 }
86 init_device_entry (controller, 0);
87 XHCI_INST (controller)->roothub = controller->devices[0];
88
89 controller->bus_address = addr;
90 controller->reg_base = (u32)phys_to_virt(pci_read_config32 (controller->bus_address, 0x10) & ~0xf);
91 //controller->reg_base = pci_read_config32 (controller->bus_address, 0x14) & ~0xf;
92 if (pci_read_config32 (controller->bus_address, 0x14) > 0) {
Patrick Georgi2e768e72011-11-04 11:50:03 +010093 fatal("We don't do 64bit addressing.\n");
Patrick Georgi6615ef32010-08-13 09:18:58 +000094 }
Gabe Black93ded592012-11-01 15:44:10 -070095 usb_debug("regbase: %lx\n", controller->reg_base);
Patrick Georgi6615ef32010-08-13 09:18:58 +000096
97 XHCI_INST (controller)->capreg = (void*)controller->reg_base;
98 XHCI_INST (controller)->opreg = (void*)(controller->reg_base + XHCI_INST (controller)->capreg->caplength);
99 XHCI_INST (controller)->hcrreg = (void*)(controller->reg_base + XHCI_INST (controller)->capreg->rtsoff);
100 XHCI_INST (controller)->dbreg = (void*)(controller->reg_base + XHCI_INST (controller)->capreg->dboff);
Gabe Black93ded592012-11-01 15:44:10 -0700101 usb_debug("caplen: %lx\nrtsoff: %lx\ndboff: %lx\n", XHCI_INST (controller)->capreg->caplength, XHCI_INST (controller)->capreg->rtsoff, XHCI_INST (controller)->capreg->dboff);
102 usb_debug("caplength: %x\n", XHCI_INST (controller)->capreg->caplength);
103 usb_debug("hciversion: %x.%x\n", XHCI_INST (controller)->capreg->hciver_hi, XHCI_INST (controller)->capreg->hciver_lo);
Patrick Georgi6615ef32010-08-13 09:18:58 +0000104 if ((XHCI_INST (controller)->capreg->hciversion < 0x96) || (XHCI_INST (controller)->capreg->hciversion > 0x100)) {
Patrick Georgi2e768e72011-11-04 11:50:03 +0100105 fatal("Unsupported xHCI version\n");
Patrick Georgi6615ef32010-08-13 09:18:58 +0000106 }
Gabe Black93ded592012-11-01 15:44:10 -0700107 usb_debug("maxslots: %x\n", XHCI_INST (controller)->capreg->MaxSlots);
108 usb_debug("maxports: %x\n", XHCI_INST (controller)->capreg->MaxPorts);
Patrick Georgi6615ef32010-08-13 09:18:58 +0000109 int pagesize = XHCI_INST (controller)->opreg->pagesize << 12;
Gabe Black93ded592012-11-01 15:44:10 -0700110 usb_debug("pagesize: %x\n", pagesize);
Patrick Georgi6615ef32010-08-13 09:18:58 +0000111
112 XHCI_INST (controller)->dcbaa = memalign(64, (XHCI_INST (controller)->capreg->MaxSlots+1)*sizeof(devctxp_t));
113 memset((void*)XHCI_INST (controller)->dcbaa, 0, (XHCI_INST (controller)->capreg->MaxSlots+1)*sizeof(devctxp_t));
114
Gabe Black93ded592012-11-01 15:44:10 -0700115 usb_debug("max scratchpad bufs: %x\n", XHCI_INST (controller)->capreg->Max_Scratchpad_Bufs);
Patrick Georgi6615ef32010-08-13 09:18:58 +0000116 if (XHCI_INST (controller)->capreg->Max_Scratchpad_Bufs > 0) {
117 XHCI_INST (controller)->dcbaa->ptr = memalign(64, XHCI_INST (controller)->capreg->Max_Scratchpad_Bufs * 8);
118 }
119
120 XHCI_INST (controller)->opreg->dcbaap_lo = virt_to_phys(XHCI_INST (controller)->dcbaa);
121 XHCI_INST (controller)->opreg->dcbaap_hi = 0;
122
123 printf("waiting for controller to be ready - ");
124 while ((XHCI_INST (controller)->opreg->usbsts & USBSTS_CNR) != 0) mdelay(1);
125 printf("ok.\n");
126
Gabe Black93ded592012-11-01 15:44:10 -0700127 usb_debug("ERST Max: %lx -> %lx entries\n", XHCI_INST (controller)->capreg->ERST_Max, 1<<(XHCI_INST (controller)->capreg->ERST_Max));
Patrick Georgi6615ef32010-08-13 09:18:58 +0000128
129 // enable all available slots
130 XHCI_INST (controller)->opreg->config = XHCI_INST (controller)->capreg->MaxSlots & CONFIG_MASK_MaxSlotsEn;
131
132 XHCI_INST (controller)->cmd_ring = memalign(64, 16*sizeof(trb_t)); /* TODO: make sure not to cross 64k page boundary */
133 memset((void*)XHCI_INST (controller)->cmd_ring, 0, 16*sizeof(trb_t));
134
135 XHCI_INST (controller)->ev_ring = memalign(64, 16*sizeof(trb_t)); /* TODO: make sure not to cross 64k page boundary */
136 memset((void*)XHCI_INST (controller)->ev_ring, 0, 16*sizeof(trb_t));
137
138 XHCI_INST (controller)->ev_ring_table = memalign(64, sizeof(erst_entry_t));
139 memset((void*)XHCI_INST (controller)->ev_ring_table, 0, sizeof(erst_entry_t));
140 XHCI_INST (controller)->ev_ring_table[0].seg_base_lo = virt_to_phys(XHCI_INST (controller)->ev_ring);
141 XHCI_INST (controller)->ev_ring_table[0].seg_base_hi = 0;
142 XHCI_INST (controller)->ev_ring_table[0].seg_size = 16;
143
144 // init command ring
145 XHCI_INST (controller)->opreg->crcr_lo = virt_to_phys(XHCI_INST (controller)->cmd_ring) | CRCR_RCS;
146 XHCI_INST (controller)->opreg->crcr_hi = 0;
147 XHCI_INST (controller)->cmd_ccs = 1;
148 XHCI_INST (controller)->ev_ccs = 1;
149
150 // init primary interrupter
151 XHCI_INST (controller)->hcrreg->intrrs[0].erstsz = 1;
152 XHCI_INST (controller)->hcrreg->intrrs[0].erdp_lo = virt_to_phys(XHCI_INST (controller)->ev_ring);
153 XHCI_INST (controller)->hcrreg->intrrs[0].erdp_hi = 0;
154 XHCI_INST (controller)->hcrreg->intrrs[0].erstba_lo = virt_to_phys(XHCI_INST (controller)->ev_ring_table);
155 XHCI_INST (controller)->hcrreg->intrrs[0].erstba_hi = 0;
156
157 XHCI_INST (controller)->opreg->usbcmd |= USBCMD_RS; /* start USB controller */
158 XHCI_INST (controller)->dbreg[0] = 0; // and tell controller to consume commands
159
160 /* TODO: TEST */
161 // setup noop command
162 trb_t *cmd = &XHCI_INST (controller)->cmd_ring[0];
163 ((u32*)cmd)[3] = 1-XHCI_INST (controller)->cmd_ccs; // disable command descriptor
164 ((u32*)cmd)[0] = 0;
165 ((u32*)cmd)[1] = 0;
166 ((u32*)cmd)[2] = 0;
167 cmd->cmd_No_Op.TRB_Type = TRB_CMD_NOOP;
168
169 // ring the HC doorbell
Gabe Black93ded592012-11-01 15:44:10 -0700170 usb_debug("Posting command at %lx\n", virt_to_phys(cmd));
Patrick Georgi6615ef32010-08-13 09:18:58 +0000171 cmd->cmd_No_Op.C = XHCI_INST (controller)->cmd_ccs; // enable command
172 XHCI_INST (controller)->dbreg[0] = 0; // and tell controller to consume commands
173
174 // wait for result in event ring
175 trb_t *ev = &XHCI_INST (controller)->ev_ring[0];
176 trb_t *ev1 = &XHCI_INST (controller)->ev_ring[1];
177 while (ev->event_cmd_cmpl.C != XHCI_INST (controller)->ev_ccs) {
Gabe Black93ded592012-11-01 15:44:10 -0700178 usb_debug("CRCR: %lx, USBSTS: %lx\n", XHCI_INST (controller)->opreg->crcr_lo, XHCI_INST (controller)->opreg->usbsts);
179 usb_debug("ev0.C %x, ev1.C %x\n", ev->event_cmd_cmpl.C, ev1->event_cmd_cmpl.C);
Patrick Georgi6615ef32010-08-13 09:18:58 +0000180 mdelay(100);
181 }
Gabe Black93ded592012-11-01 15:44:10 -0700182 usb_debug("command ring is %srunning\n", (XHCI_INST (controller)->opreg->crcr_lo & CRCR_CRR)?"":"not ");
Patrick Georgi6615ef32010-08-13 09:18:58 +0000183 switch (ev->event_cmd_cmpl.TRB_Type) {
184 case TRB_EV_CMD_CMPL:
Gabe Black93ded592012-11-01 15:44:10 -0700185 usb_debug("Completed command TRB at %lx. Code: %d\n",
Patrick Georgi6615ef32010-08-13 09:18:58 +0000186 ev->event_cmd_cmpl.Cmd_TRB_Pointer_lo, ev->event_cmd_cmpl.Completion_Code);
187 break;
188 case TRB_EV_PORTSC:
Gabe Black93ded592012-11-01 15:44:10 -0700189 usb_debug("Port Status Change Event. Completion Code: %d\n Port: %d. Ignoring.\n",
Patrick Georgi6615ef32010-08-13 09:18:58 +0000190 ev->event_cmd_cmpl.Completion_Code, ev->event_portsc.Port);
191 // we ignore the event as we look for the PORTSC registers instead, at a time when it suits _us_
192 break;
193 default:
Gabe Black93ded592012-11-01 15:44:10 -0700194 usb_debug("Unknown event: %d, Completion Code: %d\n", ev->event_cmd_cmpl.TRB_Type, ev->event_cmd_cmpl.Completion_Code);
Patrick Georgi6615ef32010-08-13 09:18:58 +0000195 break;
196 }
Gabe Black93ded592012-11-01 15:44:10 -0700197 usb_debug("CRCR: %lx, USBSTS: %lx\n", XHCI_INST (controller)->opreg->crcr_lo, XHCI_INST (controller)->opreg->usbsts);
198 usb_debug("ev0.C %x, ev1.C %x, ev1.CC %d\n", ev->event_cmd_cmpl.C, ev1->event_cmd_cmpl.C, ev1->event_cmd_cmpl.Completion_Code);
Patrick Georgi6615ef32010-08-13 09:18:58 +0000199
200 controller->devices[0]->controller = controller;
201 controller->devices[0]->init = xhci_rh_init;
202 controller->devices[0]->init (controller->devices[0]);
203
Patrick Georgi6615ef32010-08-13 09:18:58 +0000204 return controller;
205}
206
207static void
208xhci_shutdown (hci_t *controller)
209{
210 if (controller == 0)
211 return;
212 detach_controller (controller);
213 XHCI_INST (controller)->roothub->destroy (XHCI_INST (controller)->
214 roothub);
215 /* TODO: stop hardware, kill data structures */
216 free (XHCI_INST (controller));
217 free (controller);
218}
219
220static void
221xhci_start (hci_t *controller)
222{
223}
224
225static void
226xhci_stop (hci_t *controller)
227{
228}
229
230static int
231xhci_control (usbdev_t *dev, direction_t dir, int drlen, void *devreq, int dalen,
232 unsigned char *data)
233{
234 return 1;
235}
236
237/* finalize == 1: if data is of packet aligned size, add a zero length packet */
238static int
239xhci_bulk (endpoint_t *ep, int size, u8 *data, int finalize)
240{
241 int maxpsize = ep->maxpacketsize;
242 if (maxpsize == 0)
Patrick Georgi2e768e72011-11-04 11:50:03 +0100243 fatal("MaxPacketSize == 0!!!");
Patrick Georgi6615ef32010-08-13 09:18:58 +0000244 return 1;
245}
246
247/* create and hook-up an intr queue into device schedule */
248static void*
249xhci_create_intr_queue (endpoint_t *ep, int reqsize, int reqcount, int reqtiming)
250{
251 return NULL;
252}
253
254/* remove queue from device schedule, dropping all data that came in */
255static void
256xhci_destroy_intr_queue (endpoint_t *ep, void *q_)
257{
258 //free(q);
259}
260
261/* read one intr-packet from queue, if available. extend the queue for new input.
262 return NULL if nothing new available.
263 Recommended use: while (data=poll_intr_queue(q)) process(data);
264 */
265static u8*
266xhci_poll_intr_queue (void *q_)
267{
268 return NULL;
269}