xref: /aosp_15_r20/external/coreboot/payloads/libpayload/drivers/usb/xhci_devconf.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /*
2  *
3  * Copyright (C) 2013 secunet Security Networks AG
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 //#define XHCI_SPEW_DEBUG
30 
31 #include <arch/virtual.h>
32 #include <usb/usb.h>
33 #include "xhci_private.h"
34 
35 static u32
xhci_gen_route(xhci_t * const xhci,const int hubport,const int hubaddr)36 xhci_gen_route(xhci_t *const xhci, const int hubport, const int hubaddr)
37 {
38 	if (!hubaddr)
39 		return 0;
40 	u32 route_string = SC_GET(ROUTE, xhci->dev[hubaddr].ctx.slot);
41 	int i;
42 	for (i = 0; i < 20; i += 4) {
43 		if (!(route_string & (0xf << i))) {
44 			route_string |= (hubport & 0xf) << i;
45 			break;
46 		}
47 	}
48 	return route_string;
49 }
50 
51 static int
xhci_get_rh_port(xhci_t * const xhci,const int hubport,const int hubaddr)52 xhci_get_rh_port(xhci_t *const xhci, const int hubport, const int hubaddr)
53 {
54 	if (!hubaddr)
55 		return hubport;
56 	return SC_GET(RHPORT, xhci->dev[hubaddr].ctx.slot);
57 }
58 
59 static int
xhci_get_tt(xhci_t * const xhci,const usb_speed speed,const int hubport,const int hubaddr,int * const tt,int * const tt_port)60 xhci_get_tt(xhci_t *const xhci, const usb_speed speed,
61 	    const int hubport, const int hubaddr,
62 	    int *const tt, int *const tt_port)
63 {
64 	if (!hubaddr)
65 		return 0;
66 	const slotctx_t *const slot = xhci->dev[hubaddr].ctx.slot;
67 	if ((*tt = SC_GET(TTID, slot))) {
68 		*tt_port = SC_GET(TTPORT, slot);
69 	} else if (speed < HIGH_SPEED &&
70 			SC_GET(SPEED1, slot) - 1 == HIGH_SPEED) {
71 		*tt = hubaddr;
72 		*tt_port = hubport;
73 	}
74 	return *tt != 0;
75 }
76 
77 static void
xhci_reap_slots(xhci_t * const xhci,int skip_slot)78 xhci_reap_slots(xhci_t *const xhci, int skip_slot)
79 {
80 	int i;
81 
82 	xhci_debug("xHC resource shortage, trying to reap old slots...\n");
83 	for (i = 1; i <= xhci->max_slots_en; i++) {
84 		if (i == skip_slot)
85 			continue;	/* don't reap slot we were working on */
86 		if (xhci->dev[i].transfer_rings[1])
87 			continue;	/* slot still in use */
88 		if (!xhci->dev[i].ctx.raw)
89 			continue;	/* slot already disabled */
90 
91 		const int cc = xhci_cmd_disable_slot(xhci, i);
92 		if (cc != CC_SUCCESS)
93 			xhci_debug("Failed to disable slot %d: %d\n", i, cc);
94 		else
95 			xhci_spew("Successfully reaped slot %d\n", i);
96 		xhci->dcbaa[i] = 0;
97 		free(xhci->dev[i].ctx.raw);
98 		xhci->dev[i].ctx.raw = NULL;
99 	}
100 }
101 
102 static inputctx_t *
xhci_make_inputctx(const size_t ctxsize)103 xhci_make_inputctx(const size_t ctxsize)
104 {
105 	int i;
106 	const size_t size = (1 + NUM_EPS) * ctxsize;
107 	inputctx_t *const ic = malloc(sizeof(*ic));
108 	void *dma_buffer = dma_memalign(64, size);
109 
110 	if (!ic || !dma_buffer) {
111 		free(ic);
112 		free(dma_buffer);
113 		return NULL;
114 	}
115 
116 	memset(dma_buffer, 0, size);
117 	ic->drop = dma_buffer + 0;
118 	ic->add = dma_buffer + 4;
119 	dma_buffer += ctxsize;
120 	for (i = 0; i < NUM_EPS; i++, dma_buffer += ctxsize)
121 		ic->dev.ep[i] = dma_buffer;
122 
123 	return ic;
124 }
125 
126 usbdev_t *
xhci_set_address(hci_t * controller,usb_speed speed,int hubport,int hubaddr)127 xhci_set_address(hci_t *controller, usb_speed speed, int hubport, int hubaddr)
128 {
129 	xhci_t *const xhci = XHCI_INST(controller);
130 	const size_t ctxsize = CTXSIZE(xhci);
131 	devinfo_t *di = NULL;
132 	usbdev_t *dev = NULL;
133 	int i;
134 
135 	inputctx_t *const ic = xhci_make_inputctx(ctxsize);
136 	transfer_ring_t *const tr = malloc(sizeof(*tr));
137 	if (tr)
138 		tr->ring = xhci_align(16, TRANSFER_RING_SIZE * sizeof(trb_t));
139 	if (!ic || !tr || !tr->ring) {
140 		xhci_debug("Out of memory\n");
141 		goto _free_return;
142 	}
143 
144 	int slot_id;
145 	int cc = xhci_cmd_enable_slot(xhci, &slot_id);
146 	if (cc == CC_NO_SLOTS_AVAILABLE) {
147 		xhci_reap_slots(xhci, 0);
148 		cc = xhci_cmd_enable_slot(xhci, &slot_id);
149 	}
150 	if (cc != CC_SUCCESS) {
151 		xhci_debug("Enable slot failed: %d\n", cc);
152 		goto _free_return;
153 	} else {
154 		xhci_debug("Enabled slot %d\n", slot_id);
155 	}
156 
157 	di = &xhci->dev[slot_id];
158 	void *dma_buffer = dma_memalign(64, NUM_EPS * ctxsize);
159 	if (!dma_buffer)
160 		goto _disable_return;
161 	memset(dma_buffer, 0, NUM_EPS * ctxsize);
162 	for (i = 0; i < NUM_EPS; i++, dma_buffer += ctxsize)
163 		di->ctx.ep[i] = dma_buffer;
164 
165 	*ic->add = (1 << 0) /* Slot Context */ | (1 << 1) /* EP0 Context */;
166 
167 	SC_SET(ROUTE,	ic->dev.slot, xhci_gen_route(xhci, hubport, hubaddr));
168 	SC_SET(SPEED1,	ic->dev.slot, speed + 1);
169 	SC_SET(CTXENT,	ic->dev.slot, 1); /* the endpoint 0 context */
170 	SC_SET(RHPORT,	ic->dev.slot, xhci_get_rh_port(xhci, hubport, hubaddr));
171 
172 	int tt, tt_port;
173 	if (xhci_get_tt(xhci, speed, hubport, hubaddr, &tt, &tt_port)) {
174 		xhci_debug("TT for %d: %d[%d]\n", slot_id, tt, tt_port);
175 		SC_SET(MTT, ic->dev.slot, SC_GET(MTT, xhci->dev[tt].ctx.slot));
176 		SC_SET(TTID, ic->dev.slot, tt);
177 		SC_SET(TTPORT, ic->dev.slot, tt_port);
178 	}
179 
180 	di->transfer_rings[1] = tr;
181 	xhci_init_cycle_ring(tr, TRANSFER_RING_SIZE);
182 
183 	ic->dev.ep0->tr_dq_low	= virt_to_phys(tr->ring);
184 	ic->dev.ep0->tr_dq_high	= 0;
185 	EC_SET(TYPE,	ic->dev.ep0, EP_CONTROL);
186 	EC_SET(AVRTRB,	ic->dev.ep0, 8);
187 	EC_SET(MPS,	ic->dev.ep0, speed_to_default_mps(speed));
188 	EC_SET(CERR,	ic->dev.ep0, 3);
189 	EC_SET(DCS,	ic->dev.ep0, 1);
190 
191 	xhci->dcbaa[slot_id] = virt_to_phys(di->ctx.raw);
192 
193 	cc = xhci_cmd_address_device(xhci, slot_id, ic);
194 	if (cc == CC_RESOURCE_ERROR) {
195 		xhci_reap_slots(xhci, slot_id);
196 		cc = xhci_cmd_address_device(xhci, slot_id, ic);
197 	}
198 	if (cc != CC_SUCCESS) {
199 		xhci_debug("Address device failed: %d\n", cc);
200 		goto _disable_return;
201 	} else {
202 		xhci_debug("Addressed device %d (USB: %d)\n",
203 			  slot_id, SC_GET(UADDR, di->ctx.slot));
204 	}
205 	mdelay(SET_ADDRESS_MDELAY);
206 
207 	dev = init_device_entry(controller, slot_id);
208 	if (!dev)
209 		goto _disable_return;
210 
211 	dev->address = slot_id;
212 	dev->hub = hubaddr;
213 	dev->port = hubport;
214 	dev->speed = speed;
215 	dev->endpoints[0].dev = dev;
216 	dev->endpoints[0].endpoint = 0;
217 	dev->endpoints[0].toggle = 0;
218 	dev->endpoints[0].direction = SETUP;
219 	dev->endpoints[0].type = CONTROL;
220 
221 	u8 buf[8];
222 	if (get_descriptor(dev, gen_bmRequestType(device_to_host, standard_type,
223 		dev_recp), DT_DEV, 0, buf, sizeof(buf)) != sizeof(buf)) {
224 		usb_debug("first get_descriptor(DT_DEV) failed\n");
225 		goto _disable_return;
226 	}
227 
228 	dev->endpoints[0].maxpacketsize = usb_decode_mps0(speed, buf[7]);
229 	if (dev->endpoints[0].maxpacketsize != speed_to_default_mps(speed)) {
230 		memset((void *)ic->dev.ep0, 0x00, ctxsize);
231 		*ic->add = (1 << 1); /* EP0 Context */
232 		EC_SET(MPS, ic->dev.ep0, dev->endpoints[0].maxpacketsize);
233 		cc = xhci_cmd_evaluate_context(xhci, slot_id, ic);
234 		if (cc == CC_RESOURCE_ERROR) {
235 			xhci_reap_slots(xhci, slot_id);
236 			cc = xhci_cmd_evaluate_context(xhci, slot_id, ic);
237 		}
238 		if (cc != CC_SUCCESS) {
239 			xhci_debug("Context evaluation failed: %d\n", cc);
240 			goto _disable_return;
241 		}
242 	}
243 
244 	goto _free_ic_return;
245 
246 _disable_return:
247 	xhci_cmd_disable_slot(xhci, slot_id);
248 	xhci->dcbaa[slot_id] = 0;
249 	usb_detach_device(controller, slot_id);
250 	dev = NULL;
251 _free_return:
252 	if (tr)
253 		free((void *)tr->ring);
254 	free(tr);
255 	if (di) {
256 		free(di->ctx.raw);
257 		di->ctx.raw = 0;
258 	}
259 _free_ic_return:
260 	if (ic)
261 		free(ic->raw);
262 	free(ic);
263 	return dev;
264 }
265 
266 static int
xhci_finish_hub_config(usbdev_t * const dev,inputctx_t * const ic)267 xhci_finish_hub_config(usbdev_t *const dev, inputctx_t *const ic)
268 {
269 	int type = is_usb_speed_ss(dev->speed) ? 0x2a : 0x29; /* similar enough */
270 	hub_descriptor_t desc;
271 
272 	if (get_descriptor(dev, gen_bmRequestType(device_to_host, class_type,
273 		dev_recp), type, 0, &desc, sizeof(desc)) != sizeof(desc)) {
274 		xhci_debug("Failed to fetch hub descriptor\n");
275 		return COMMUNICATION_ERROR;
276 	}
277 
278 	SC_SET(HUB,	ic->dev.slot, 1);
279 	SC_SET(MTT,	ic->dev.slot, 0); /* No support for Multi-TT */
280 	SC_SET(NPORTS,	ic->dev.slot, desc.bNbrPorts);
281 	if (dev->speed == HIGH_SPEED)
282 		SC_SET(TTT, ic->dev.slot,
283 		       (desc.wHubCharacteristics >> 5) & 0x0003);
284 
285 	return 0;
286 }
287 
288 static size_t
xhci_bound_interval(const endpoint_t * const ep)289 xhci_bound_interval(const endpoint_t *const ep)
290 {
291 	if ((ep->dev->speed == LOW_SPEED &&
292 			(ep->type == ISOCHRONOUS ||
293 			 ep->type == INTERRUPT)) ||
294 		(ep->dev->speed == FULL_SPEED &&
295 			 ep->type == INTERRUPT))
296 	{
297 		if (ep->interval < 3)
298 			return 3;
299 		else if (ep->interval > 11)
300 			return 11;
301 		else
302 			return ep->interval;
303 	} else {
304 		if (ep->interval < 0)
305 			return 0;
306 		else if (ep->interval > 15)
307 			return 15;
308 		else
309 			return ep->interval;
310 	}
311 }
312 
313 static int
xhci_finish_ep_config(const endpoint_t * const ep,inputctx_t * const ic)314 xhci_finish_ep_config(const endpoint_t *const ep, inputctx_t *const ic)
315 {
316 	xhci_t *const xhci = XHCI_INST(ep->dev->controller);
317 	const int ep_id = xhci_ep_id(ep);
318 	xhci_debug("ep_id: %d\n", ep_id);
319 	if (ep_id <= 1 || 32 <= ep_id)
320 		return DRIVER_ERROR;
321 
322 	transfer_ring_t *const tr = malloc(sizeof(*tr));
323 	if (tr)
324 		tr->ring = xhci_align(16, TRANSFER_RING_SIZE * sizeof(trb_t));
325 	if (!tr || !tr->ring) {
326 		free(tr);
327 		xhci_debug("Out of memory\n");
328 		return OUT_OF_MEMORY;
329 	}
330 	xhci->dev[ep->dev->address].transfer_rings[ep_id] = tr;
331 	xhci_init_cycle_ring(tr, TRANSFER_RING_SIZE);
332 
333 	*ic->add |= (1 << ep_id);
334 	if (SC_GET(CTXENT, ic->dev.slot) < ep_id)
335 		SC_SET(CTXENT, ic->dev.slot, ep_id);
336 
337 	epctx_t *const epctx = ic->dev.ep[ep_id];
338 	xhci_debug("Filling epctx (@%p)\n", epctx);
339 	epctx->tr_dq_low	= virt_to_phys(tr->ring);
340 	epctx->tr_dq_high	= 0;
341 	EC_SET(INTVAL,	epctx, xhci_bound_interval(ep));
342 	EC_SET(CERR,	epctx, 3);
343 	EC_SET(TYPE,	epctx, ep->type | ((ep->direction != OUT) << 2));
344 	EC_SET(MPS,	epctx, ep->maxpacketsize);
345 	EC_SET(DCS,	epctx, 1);
346 	size_t avrtrb;
347 	switch (ep->type) {
348 		case BULK: case ISOCHRONOUS:	avrtrb = 3 * 1024; break;
349 		case INTERRUPT:			avrtrb =     1024; break;
350 		default:			avrtrb =        8; break;
351 	}
352 	EC_SET(AVRTRB,	epctx, avrtrb);
353 	EC_SET(MXESIT,  epctx, EC_GET(MPS, epctx) * EC_GET(MBS, epctx));
354 
355 	if (CONFIG(LP_USB_XHCI_MTK_QUIRK)) {
356 		/* The MTK xHCI defines some extra SW parameters which are
357 		 * put into reserved DWs in Slot and Endpoint Contexts for
358 		 * synchronous endpoints. But for non-isochronous transfers,
359 		 * it is enough to set the following two fields to 1, and others
360 		 * are set to 0.
361 		 */
362 		EC_SET(BPKTS, epctx, 1);
363 		EC_SET(BBM, epctx, 1);
364 	}
365 	return 0;
366 }
367 
368 int
xhci_finish_device_config(usbdev_t * const dev)369 xhci_finish_device_config(usbdev_t *const dev)
370 {
371 	xhci_t *const xhci = XHCI_INST(dev->controller);
372 	int slot_id = dev->address;
373 	devinfo_t *const di = &xhci->dev[slot_id];
374 
375 	int i, ret = 0;
376 
377 	inputctx_t *const ic = xhci_make_inputctx(CTXSIZE(xhci));
378 	if (!ic) {
379 		xhci_debug("Out of memory\n");
380 		return OUT_OF_MEMORY;
381 	}
382 
383 	*ic->add = (1 << 0); /* Slot Context */
384 
385 	xhci_dump_slotctx(di->ctx.slot);
386 	ic->dev.slot->f1 = di->ctx.slot->f1;
387 	ic->dev.slot->f2 = di->ctx.slot->f2;
388 	ic->dev.slot->f3 = di->ctx.slot->f3;
389 	/* f4 *must* be 0 in the Input Context... yeah, it's weird, I know. */
390 
391 	if (dev->descriptor->bDeviceClass == 0x09) {
392 		ret = xhci_finish_hub_config(dev, ic);
393 		if (ret)
394 			goto _free_return;
395 	}
396 
397 	for (i = 1; i < dev->num_endp; ++i) {
398 		ret = xhci_finish_ep_config(&dev->endpoints[i], ic);
399 		if (ret)
400 			goto _free_ep_ctx_return;
401 	}
402 
403 	xhci_dump_inputctx(ic);
404 
405 	const int config_id = dev->configuration->bConfigurationValue;
406 	xhci_debug("config_id: %d\n", config_id);
407 	int cc = xhci_cmd_configure_endpoint(xhci, slot_id, config_id, ic);
408 	if (cc == CC_RESOURCE_ERROR || cc == CC_BANDWIDTH_ERROR) {
409 		xhci_reap_slots(xhci, slot_id);
410 		cc = xhci_cmd_configure_endpoint(xhci, slot_id, config_id, ic);
411 	}
412 	if (cc != CC_SUCCESS) {
413 		xhci_debug("Configure endpoint failed: %d\n", cc);
414 		ret = CONTROLLER_ERROR;
415 		goto _free_ep_ctx_return;
416 	} else {
417 		xhci_debug("Endpoints configured\n");
418 	}
419 
420 	goto _free_return;
421 
422 _free_ep_ctx_return:
423 	for (i = 2; i < 31; ++i) {
424 		if (di->transfer_rings[i])
425 			free((void *)di->transfer_rings[i]->ring);
426 		free(di->transfer_rings[i]);
427 		di->transfer_rings[i] = NULL;
428 	}
429 _free_return:
430 	free(ic->raw);
431 	free(ic);
432 	return ret;
433 }
434 
435 void
xhci_destroy_dev(hci_t * const controller,const int slot_id)436 xhci_destroy_dev(hci_t *const controller, const int slot_id)
437 {
438 	xhci_t *const xhci = XHCI_INST(controller);
439 
440 	if (slot_id <= 0 || slot_id > xhci->max_slots_en)
441 		return;
442 
443 	inputctx_t *const ic = xhci_make_inputctx(CTXSIZE(xhci));
444 	if (!ic) {
445 		xhci_debug("Out of memory, leaking resources!\n");
446 		return;
447 	}
448 	const int num_eps = controller->devices[slot_id]->num_endp;
449 	*ic->add = 0;	/* Leave Slot/EP0 state as it is for now. */
450 	*ic->drop = (1 << num_eps) - 1;	/* Drop all endpoints we can. */
451 	*ic->drop &= ~(1 << 1 | 1 << 0); /* Not allowed to drop EP0 or Slot. */
452 	int cc = xhci_cmd_evaluate_context(xhci, slot_id, ic);
453 	free(ic);
454 	if (cc != CC_SUCCESS)
455 		xhci_debug("Failed to quiesce slot %d: %d\n", slot_id, cc);
456 	cc = xhci_cmd_stop_endpoint(xhci, slot_id, 1);
457 	if (cc != CC_SUCCESS)
458 		xhci_debug("Failed to stop EP0 on slot %d: %d\n", slot_id, cc);
459 
460 	int i;
461 	devinfo_t *const di = &xhci->dev[slot_id];
462 	for (i = 1; i < num_eps; ++i) {
463 		if (di->transfer_rings[i])
464 			free((void *)di->transfer_rings[i]->ring);
465 		free(di->transfer_rings[i]);
466 		free(di->interrupt_queues[i]);
467 	}
468 
469 	xhci_spew("Stopped slot %d, but not disabling it yet.\n", slot_id);
470 	di->transfer_rings[1] = NULL;
471 }
472