OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
ReleaseUsbOwnership.c
Go to the documentation of this file.
1
15#include <Uefi.h>
16
17#include <IndustryStandard/Pci.h>
18
19#include <Protocol/PciIo.h>
20
21#include <Library/BaseMemoryLib.h>
22#include <Library/DebugLib.h>
23#include <Library/IoLib.h>
24#include <Library/UefiBootServicesTableLib.h>
26
27#include "PciExtInternal.h"
28
37STATIC
38EFI_STATUS
40 IN EFI_PCI_IO_PROTOCOL *PciIo
41 )
42{
43 EFI_STATUS Status;
44
45 UINT32 HcCapParams;
46 UINT32 ExtendCap;
47 UINT32 Value;
48 INT32 TimeOut;
49
50 //
51 // XHCI controller, then disable legacy support, if enabled.
52 //
53
54 Status = PciIo->Mem.Read (
55 PciIo,
56 EfiPciIoWidthUint32,
59 1,
60 &HcCapParams
61 );
62
63 ExtendCap = EFI_ERROR (Status) ? 0 : ((HcCapParams >> 14U) & 0x3FFFCU);
64
65 while (ExtendCap) {
66 Status = PciIo->Mem.Read (
67 PciIo,
68 EfiPciIoWidthUint32,
70 ExtendCap,
71 1,
72 &Value
73 );
74
75 if (EFI_ERROR (Status)) {
76 break;
77 }
78
79 if ((Value & XHC_CAPABILITY_ID_MASK) == 1) {
80 //
81 // Do nothing if BIOS ownership is cleared.
82 //
83 if (!(Value & BIT16)) {
84 break;
85 }
86
87 Value |= BIT24;
88
89 PciIo->Mem.Write (
90 PciIo,
91 EfiPciIoWidthUint32,
93 ExtendCap,
94 1,
95 &Value
96 );
97
98 TimeOut = 40;
99 while (TimeOut--) {
100 gBS->Stall (500);
101
102 Status = PciIo->Mem.Read (
103 PciIo,
104 EfiPciIoWidthUint32,
106 ExtendCap,
107 1,
108 &Value
109 );
110
111 if (EFI_ERROR (Status) || !(Value & BIT16)) {
112 break;
113 }
114 }
115
116 //
117 // Disable all SMI in USBLEGCTLSTS
118 //
119 Status = PciIo->Mem.Read (
120 PciIo,
121 EfiPciIoWidthUint32,
123 ExtendCap + 4,
124 1,
125 &Value
126 );
127
128 if (EFI_ERROR (Status)) {
129 break;
130 }
131
132 Value &= 0x1F1FEEU;
133 Value |= 0xE0000000U;
134
135 PciIo->Mem.Write (
136 PciIo,
137 EfiPciIoWidthUint32,
139 ExtendCap + 4,
140 1,
141 &Value
142 );
143
144 //
145 // Clear all ownership
146 //
147 Status = PciIo->Mem.Read (
148 PciIo,
149 EfiPciIoWidthUint32,
151 ExtendCap,
152 1,
153 &Value
154 );
155
156 if (EFI_ERROR (Status)) {
157 break;
158 }
159
160 Value &= ~(BIT24 | BIT16);
161 PciIo->Mem.Write (
162 PciIo,
163 EfiPciIoWidthUint32,
165 ExtendCap,
166 1,
167 &Value
168 );
169
170 break;
171 }
172
173 if (!(Value & XHC_NEXT_CAPABILITY_MASK)) {
174 break;
175 }
176
177 ExtendCap += ((Value >> 6U) & 0x3FCU);
178 }
179
180 return Status;
181}
182
191STATIC
192EFI_STATUS
194 IN EFI_PCI_IO_PROTOCOL *PciIo
195 )
196{
197 EFI_STATUS Status;
198 UINT32 Value;
199 UINT32 Base;
200 UINT32 OpAddr;
201 UINT32 ExtendCap;
202 UINT32 UsbCmd;
203 UINT32 UsbLegSup;
204 UINT32 UsbLegCtlSts;
205 UINTN IsOsOwned;
206 UINTN IsBiosOwned;
207 BOOLEAN IsOwnershipConflict;
208 UINT32 HcCapParams;
209 INT32 TimeOut;
210
211 Value = 0x0002;
212 Status = EFI_SUCCESS;
213
214 PciIo->Pci.Write (
215 PciIo,
216 EfiPciIoWidthUint16,
217 0x04,
218 1,
219 &Value
220 );
221
222 Base = 0;
223
224 PciIo->Pci.Read (
225 PciIo,
226 EfiPciIoWidthUint32,
227 0x10,
228 1,
229 &Base
230 );
231
232 if (MmioRead8 (Base) < 0x0C) {
233 //
234 // Config space too small: no legacy implementation.
235 //
236 return EFI_NOT_FOUND;
237 }
238
239 //
240 // Operational Registers = capaddr + offset (8bit CAPLENGTH in Capability Registers + offset 0).
241 //
242 OpAddr = Base + MmioRead8 (Base);
243
244 PciIo->Mem.Read (
245 PciIo,
246 EfiPciIoWidthUint32,
249 1,
250 &HcCapParams
251 );
252
253 ExtendCap = (HcCapParams >> 8U) & 0xFFU;
254
255 //
256 // Read PCI Config 32bit USBLEGSUP (eecp+0).
257 //
258 PciIo->Pci.Read (
259 PciIo,
260 EfiPciIoWidthUint32,
261 ExtendCap,
262 1,
263 &UsbLegSup
264 );
265
266 IsBiosOwned = (UsbLegSup & BIT16) != 0;
267 if (!IsBiosOwned) {
268 //
269 // No BIOS ownership, ignore.
270 //
271 return EFI_NOT_FOUND;
272 }
273
274 //
275 // Read PCI Config 32bit USBLEGCTLSTS (eecp+4).
276 //
277 PciIo->Pci.Read (
278 PciIo,
279 EfiPciIoWidthUint32,
280 ExtendCap + 0x4,
281 1,
282 &UsbLegCtlSts
283 );
284
285 //
286 // Disable the SMI in USBLEGCTLSTS firstly.
287 //
288 UsbLegCtlSts &= 0xFFFF0000U;
289 PciIo->Pci.Write (
290 PciIo,
291 EfiPciIoWidthUint32,
292 ExtendCap + 0x4,
293 1,
294 &UsbLegCtlSts
295 );
296
297 UsbCmd = MmioRead32 (OpAddr + EHC_USBCMD_OFFSET);
298
299 //
300 // Clear registers to default.
301 //
302 UsbCmd = UsbCmd & 0xFFFFFF00U;
303 MmioWrite32 (OpAddr + EHC_USBCMD_OFFSET, UsbCmd);
304 MmioWrite32 (OpAddr + EHC_USBINT_OFFSET, 0);
305 MmioWrite32 (OpAddr + EHC_USBSTS_OFFSET, 0x1000);
306
307 Value = 1;
308 PciIo->Pci.Write (
309 PciIo,
310 EfiPciIoWidthUint32,
311 ExtendCap,
312 1,
313 &Value
314 );
315
316 //
317 // Read 32bit USBLEGSUP (eecp+0).
318 //
319 PciIo->Pci.Read (
320 PciIo,
321 EfiPciIoWidthUint32,
322 ExtendCap,
323 1,
324 &UsbLegSup
325 );
326
327 IsBiosOwned = (UsbLegSup & BIT16) != 0;
328 IsOsOwned = (UsbLegSup & BIT24) != 0;
329
330 //
331 // Read 32bit USBLEGCTLSTS (eecp+4).
332 //
333 PciIo->Pci.Read (
334 PciIo,
335 EfiPciIoWidthUint32,
336 ExtendCap + 0x4,
337 1,
338 &UsbLegCtlSts
339 );
340
341 //
342 // Get EHCI Ownership from legacy bios.
343 //
344 PciIo->Pci.Read (
345 PciIo,
346 EfiPciIoWidthUint32,
347 ExtendCap,
348 1,
349 &UsbLegSup
350 );
351
352 IsOwnershipConflict = IsBiosOwned && IsOsOwned;
353
354 if (IsOwnershipConflict) {
355 //
356 // EHCI - Ownership conflict - attempting soft reset.
357 //
358 Value = 0;
359 PciIo->Pci.Write (
360 PciIo,
361 EfiPciIoWidthUint8,
362 ExtendCap + 3,
363 1,
364 &Value
365 );
366
367 TimeOut = 40;
368 while (TimeOut--) {
369 gBS->Stall (500);
370
371 PciIo->Pci.Read (
372 PciIo,
373 EfiPciIoWidthUint32,
374 ExtendCap,
375 1,
376 &Value
377 );
378
379 if ((Value & BIT24) == 0x0) {
380 break;
381 }
382 }
383 }
384
385 PciIo->Pci.Read (
386 PciIo,
387 EfiPciIoWidthUint32,
388 ExtendCap,
389 1,
390 &Value
391 );
392
393 Value |= BIT24;
394 PciIo->Pci.Write (
395 PciIo,
396 EfiPciIoWidthUint32,
397 ExtendCap,
398 1,
399 &Value
400 );
401
402 TimeOut = 40;
403 while (TimeOut--) {
404 gBS->Stall (500);
405
406 PciIo->Pci.Read (
407 PciIo,
408 EfiPciIoWidthUint32,
409 ExtendCap,
410 1,
411 &Value
412 );
413
414 if ((Value & BIT16) == 0x0) {
415 break;
416 }
417 }
418
419 IsOwnershipConflict = (Value & BIT16) != 0x0;
420 if (IsOwnershipConflict) {
421 //
422 // Soft reset has failed. Assume SMI being ignored and do hard reset.
423 //
424 Value = 0;
425 PciIo->Pci.Write (
426 PciIo,
427 EfiPciIoWidthUint8,
428 ExtendCap + 2,
429 1,
430 &Value
431 );
432
433 TimeOut = 40;
434 while (TimeOut--) {
435 gBS->Stall (500);
436
437 PciIo->Pci.Read (
438 PciIo,
439 EfiPciIoWidthUint32,
440 ExtendCap,
441 1,
442 &Value
443 );
444
445 if ((Value & BIT16) == 0x0) {
446 break;
447 }
448 }
449
450 //
451 // Disable further SMI events.
452 //
453 PciIo->Pci.Read (
454 PciIo,
455 EfiPciIoWidthUint32,
456 ExtendCap + 0x4,
457 1,
458 &UsbLegCtlSts
459 );
460
461 UsbLegCtlSts &= 0xFFFF0000U;
462 PciIo->Pci.Write (
463 PciIo,
464 EfiPciIoWidthUint32,
465 ExtendCap + 0x4,
466 1,
467 &UsbLegCtlSts
468 );
469 }
470
471 if (Value & BIT16) {
472 //
473 // EHCI controller unable to take control from BIOS.
474 //
475 Status = EFI_NOT_FOUND;
476 }
477
478 return Status;
479}
480
489STATIC
490EFI_STATUS
492 IN EFI_PCI_IO_PROTOCOL *PciIo
493 )
494{
495 EFI_STATUS Status;
496 UINT32 Base;
497 UINT32 PortBase;
498 UINT16 Command;
499
500 Base = 0;
501
502 PciIo->Pci.Read (
503 PciIo,
504 EfiPciIoWidthUint32,
505 0x20,
506 1,
507 &Base
508 );
509
510 PortBase = (Base >> 5) & 0x07ff;
511
512 Command = 0x8f00;
513
514 Status = PciIo->Pci.Write (
515 PciIo,
516 EfiPciIoWidthUint16,
517 0xC0,
518 1,
519 &Command
520 );
521
522 if ((PortBase != 0) && ((PortBase & BIT0) == 0)) {
523 IoWrite16 (PortBase, 0x0002);
524 gBS->Stall (500);
525 IoWrite16 (PortBase + 4, 0);
526 gBS->Stall (500);
527 IoWrite16 (PortBase, 0);
528 }
529
530 return Status;
531}
532
533EFI_STATUS
535 VOID
536 )
537{
538 EFI_STATUS Result;
539 EFI_STATUS Status;
540 EFI_HANDLE *HandleArray;
541 UINTN HandleArrayCount;
542 UINTN Index;
543 EFI_PCI_IO_PROTOCOL *PciIo;
544 PCI_TYPE00 Pci;
545
546 Status = gBS->LocateHandleBuffer (
547 ByProtocol,
548 &gEfiPciIoProtocolGuid,
549 NULL,
550 &HandleArrayCount,
551 &HandleArray
552 );
553
554 if (EFI_ERROR (Status)) {
555 return Status;
556 }
557
558 Result = EFI_UNSUPPORTED;
559
560 for (Index = 0; Index < HandleArrayCount; ++Index) {
561 Status = gBS->HandleProtocol (
562 HandleArray[Index],
563 &gEfiPciIoProtocolGuid,
564 (VOID **)&PciIo
565 );
566
567 if (EFI_ERROR (Status)) {
568 continue;
569 }
570
571 Status = PciIo->Pci.Read (
572 PciIo,
573 EfiPciIoWidthUint32,
574 0,
575 sizeof (Pci) / sizeof (UINT32),
576 &Pci
577 );
578
579 if ( EFI_ERROR (Status)
580 || (Pci.Hdr.ClassCode[1] != PCI_CLASS_SERIAL_USB)
581 || (Pci.Hdr.ClassCode[2] != PCI_CLASS_SERIAL))
582 {
583 continue;
584 }
585
586 if (Pci.Hdr.ClassCode[0] == PCI_IF_XHCI) {
587 Result = XhciReleaseOwnership (PciIo);
588 } else if (Pci.Hdr.ClassCode[0] == PCI_IF_EHCI) {
589 Result = EhciReleaseOwnership (PciIo);
590 } else if (Pci.Hdr.ClassCode[0] == PCI_IF_UHCI) {
591 Result = UhciReleaseOwnership (PciIo);
592 }
593 }
594
595 gBS->FreePool (HandleArray);
596 return Result;
597}
UINT8 Command[7]
Actual command for the Command Page.
Definition AppleNec.h:74
EFI_BOOT_SERVICES * gBS
#define EHC_USBINT_OFFSET
USB Interrupt Enable Register.
#define XHC_NEXT_CAPABILITY_MASK
#define XHC_CAPABILITY_ID_MASK
#define EHC_HCCPARAMS_OFFSET
#define EHC_BAR_INDEX
#define XHC_USBCMD_OFFSET
USB Command Register Offset.
#define EHC_USBSTS_OFFSET
USB Status Register Offset.
#define XHC_HCCPARAMS_OFFSET
#define EHC_USBCMD_OFFSET
USB Command Register Offset.
STATIC EFI_STATUS XhciReleaseOwnership(IN EFI_PCI_IO_PROTOCOL *PciIo)
STATIC EFI_STATUS UhciReleaseOwnership(IN EFI_PCI_IO_PROTOCOL *PciIo)
STATIC EFI_STATUS EhciReleaseOwnership(IN EFI_PCI_IO_PROTOCOL *PciIo)
EFI_STATUS ReleaseUsbOwnership(VOID)
UINT8 EFIAPI MmioRead8(IN UINTN Address)
Definition UserMisc.c:632
UINT32 EFIAPI MmioRead32(IN UINTN Address)
Definition UserMisc.c:623
UINT32 EFIAPI MmioWrite32(IN UINTN Address, IN UINT32 Value)
Definition UserMisc.c:651