]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/EhciPei/EhcPeim.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / EhciPei / EhcPeim.c
1 /** @file
2 PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid
3 which is used to enable recovery function from USB Drivers.
4
5 Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include "EhcPeim.h"
12
13 //
14 // Two arrays used to translate the EHCI port state (change)
15 // to the UEFI protocol's port state (change).
16 //
17 USB_PORT_STATE_MAP mUsbPortStateMap[] = {
18 {PORTSC_CONN, USB_PORT_STAT_CONNECTION},
19 {PORTSC_ENABLED, USB_PORT_STAT_ENABLE},
20 {PORTSC_SUSPEND, USB_PORT_STAT_SUSPEND},
21 {PORTSC_OVERCUR, USB_PORT_STAT_OVERCURRENT},
22 {PORTSC_RESET, USB_PORT_STAT_RESET},
23 {PORTSC_POWER, USB_PORT_STAT_POWER},
24 {PORTSC_OWNER, USB_PORT_STAT_OWNER}
25 };
26
27 USB_PORT_STATE_MAP mUsbPortChangeMap[] = {
28 {PORTSC_CONN_CHANGE, USB_PORT_STAT_C_CONNECTION},
29 {PORTSC_ENABLE_CHANGE, USB_PORT_STAT_C_ENABLE},
30 {PORTSC_OVERCUR_CHANGE, USB_PORT_STAT_C_OVERCURRENT}
31 };
32
33 /**
34 Read Ehc Operation register.
35
36 @param Ehc The EHCI device.
37 @param Offset The operation register offset.
38
39 @retval the register content read.
40
41 **/
42 UINT32
43 EhcReadOpReg (
44 IN PEI_USB2_HC_DEV *Ehc,
45 IN UINT32 Offset
46 )
47 {
48 UINT32 Data;
49
50 ASSERT (Ehc->CapLen != 0);
51
52 Data = MmioRead32 (Ehc->UsbHostControllerBaseAddress + Ehc->CapLen + Offset);
53
54 return Data;
55 }
56
57 /**
58 Write the data to the EHCI operation register.
59
60 @param Ehc The EHCI device.
61 @param Offset EHCI operation register offset.
62 @param Data The data to write.
63
64 **/
65 VOID
66 EhcWriteOpReg (
67 IN PEI_USB2_HC_DEV *Ehc,
68 IN UINT32 Offset,
69 IN UINT32 Data
70 )
71 {
72
73 ASSERT (Ehc->CapLen != 0);
74
75 MmioWrite32(Ehc->UsbHostControllerBaseAddress + Ehc->CapLen + Offset, Data);
76
77 }
78
79 /**
80 Set one bit of the operational register while keeping other bits.
81
82 @param Ehc The EHCI device.
83 @param Offset The offset of the operational register.
84 @param Bit The bit mask of the register to set.
85
86 **/
87 VOID
88 EhcSetOpRegBit (
89 IN PEI_USB2_HC_DEV *Ehc,
90 IN UINT32 Offset,
91 IN UINT32 Bit
92 )
93 {
94 UINT32 Data;
95
96 Data = EhcReadOpReg (Ehc, Offset);
97 Data |= Bit;
98 EhcWriteOpReg (Ehc, Offset, Data);
99 }
100
101 /**
102 Clear one bit of the operational register while keeping other bits.
103
104 @param Ehc The EHCI device.
105 @param Offset The offset of the operational register.
106 @param Bit The bit mask of the register to clear.
107
108 **/
109 VOID
110 EhcClearOpRegBit (
111 IN PEI_USB2_HC_DEV *Ehc,
112 IN UINT32 Offset,
113 IN UINT32 Bit
114 )
115 {
116 UINT32 Data;
117
118 Data = EhcReadOpReg (Ehc, Offset);
119 Data &= ~Bit;
120 EhcWriteOpReg (Ehc, Offset, Data);
121 }
122
123 /**
124 Wait the operation register's bit as specified by Bit
125 to become set (or clear).
126
127 @param Ehc The EHCI device.
128 @param Offset The offset of the operational register.
129 @param Bit The bit mask of the register to wait for.
130 @param WaitToSet Wait the bit to set or clear.
131 @param Timeout The time to wait before abort (in millisecond).
132
133 @retval EFI_SUCCESS The bit successfully changed by host controller.
134 @retval EFI_TIMEOUT The time out occurred.
135
136 **/
137 EFI_STATUS
138 EhcWaitOpRegBit (
139 IN PEI_USB2_HC_DEV *Ehc,
140 IN UINT32 Offset,
141 IN UINT32 Bit,
142 IN BOOLEAN WaitToSet,
143 IN UINT32 Timeout
144 )
145 {
146 UINT32 Index;
147
148 for (Index = 0; Index < Timeout / EHC_SYNC_POLL_INTERVAL + 1; Index++) {
149 if (EHC_REG_BIT_IS_SET (Ehc, Offset, Bit) == WaitToSet) {
150 return EFI_SUCCESS;
151 }
152
153 MicroSecondDelay (EHC_SYNC_POLL_INTERVAL);
154 }
155
156 return EFI_TIMEOUT;
157 }
158
159 /**
160 Read EHCI capability register.
161
162 @param Ehc The EHCI device.
163 @param Offset Capability register address.
164
165 @retval the register content read.
166
167 **/
168 UINT32
169 EhcReadCapRegister (
170 IN PEI_USB2_HC_DEV *Ehc,
171 IN UINT32 Offset
172 )
173 {
174 UINT32 Data;
175
176 Data = MmioRead32(Ehc->UsbHostControllerBaseAddress + Offset);
177
178 return Data;
179 }
180
181 /**
182 Set door bell and wait it to be ACKed by host controller.
183 This function is used to synchronize with the hardware.
184
185 @param Ehc The EHCI device.
186 @param Timeout The time to wait before abort (in millisecond, ms).
187
188 @retval EFI_TIMEOUT Time out happened while waiting door bell to set.
189 @retval EFI_SUCCESS Synchronized with the hardware.
190
191 **/
192 EFI_STATUS
193 EhcSetAndWaitDoorBell (
194 IN PEI_USB2_HC_DEV *Ehc,
195 IN UINT32 Timeout
196 )
197 {
198 EFI_STATUS Status;
199 UINT32 Data;
200
201 EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_IAAD);
202
203 Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_IAA, TRUE, Timeout);
204
205 //
206 // ACK the IAA bit in USBSTS register. Make sure other
207 // interrupt bits are not ACKed. These bits are WC (Write Clean).
208 //
209 Data = EhcReadOpReg (Ehc, EHC_USBSTS_OFFSET);
210 Data &= ~USBSTS_INTACK_MASK;
211 Data |= USBSTS_IAA;
212
213 EhcWriteOpReg (Ehc, EHC_USBSTS_OFFSET, Data);
214
215 return Status;
216 }
217
218 /**
219 Clear all the interrutp status bits, these bits
220 are Write-Clean.
221
222 @param Ehc The EHCI device.
223
224 **/
225 VOID
226 EhcAckAllInterrupt (
227 IN PEI_USB2_HC_DEV *Ehc
228 )
229 {
230 EhcWriteOpReg (Ehc, EHC_USBSTS_OFFSET, USBSTS_INTACK_MASK);
231 }
232
233 /**
234 Enable the periodic schedule then wait EHC to
235 actually enable it.
236
237 @param Ehc The EHCI device.
238 @param Timeout The time to wait before abort (in millisecond, ms).
239
240 @retval EFI_TIMEOUT Time out happened while enabling periodic schedule.
241 @retval EFI_SUCCESS The periodical schedule is enabled.
242
243 **/
244 EFI_STATUS
245 EhcEnablePeriodSchd (
246 IN PEI_USB2_HC_DEV *Ehc,
247 IN UINT32 Timeout
248 )
249 {
250 EFI_STATUS Status;
251
252 EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_PERIOD);
253
254 Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_PERIOD_ENABLED, TRUE, Timeout);
255 return Status;
256 }
257
258 /**
259 Enable asynchrounous schedule.
260
261 @param Ehc The EHCI device.
262 @param Timeout Time to wait before abort.
263
264 @retval EFI_SUCCESS The EHCI asynchronous schedule is enabled.
265 @retval Others Failed to enable the asynchronous scheudle.
266
267 **/
268 EFI_STATUS
269 EhcEnableAsyncSchd (
270 IN PEI_USB2_HC_DEV *Ehc,
271 IN UINT32 Timeout
272 )
273 {
274 EFI_STATUS Status;
275
276 EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_ASYNC);
277
278 Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_ASYNC_ENABLED, TRUE, Timeout);
279 return Status;
280 }
281
282 /**
283 Check whether Ehc is halted.
284
285 @param Ehc The EHCI device.
286
287 @retval TRUE The controller is halted.
288 @retval FALSE The controller isn't halted.
289
290 **/
291 BOOLEAN
292 EhcIsHalt (
293 IN PEI_USB2_HC_DEV *Ehc
294 )
295 {
296 return EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT);
297 }
298
299 /**
300 Check whether system error occurred.
301
302 @param Ehc The EHCI device.
303
304 @retval TRUE System error happened.
305 @retval FALSE No system error.
306
307 **/
308 BOOLEAN
309 EhcIsSysError (
310 IN PEI_USB2_HC_DEV *Ehc
311 )
312 {
313 return EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_SYS_ERROR);
314 }
315
316 /**
317 Reset the host controller.
318
319 @param Ehc The EHCI device.
320 @param Timeout Time to wait before abort (in millisecond, ms).
321
322 @retval EFI_TIMEOUT The transfer failed due to time out.
323 @retval Others Failed to reset the host.
324
325 **/
326 EFI_STATUS
327 EhcResetHC (
328 IN PEI_USB2_HC_DEV *Ehc,
329 IN UINT32 Timeout
330 )
331 {
332 EFI_STATUS Status;
333
334 //
335 // Host can only be reset when it is halt. If not so, halt it
336 //
337 if (!EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) {
338 Status = EhcHaltHC (Ehc, Timeout);
339
340 if (EFI_ERROR (Status)) {
341 return Status;
342 }
343 }
344
345 EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RESET);
346 Status = EhcWaitOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RESET, FALSE, Timeout);
347 return Status;
348 }
349
350 /**
351 Halt the host controller.
352
353 @param Ehc The EHCI device.
354 @param Timeout Time to wait before abort.
355
356 @retval EFI_TIMEOUT Failed to halt the controller before Timeout.
357 @retval EFI_SUCCESS The EHCI is halt.
358
359 **/
360 EFI_STATUS
361 EhcHaltHC (
362 IN PEI_USB2_HC_DEV *Ehc,
363 IN UINT32 Timeout
364 )
365 {
366 EFI_STATUS Status;
367
368 EhcClearOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);
369 Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT, TRUE, Timeout);
370 return Status;
371 }
372
373 /**
374 Set the EHCI to run.
375
376 @param Ehc The EHCI device.
377 @param Timeout Time to wait before abort.
378
379 @retval EFI_SUCCESS The EHCI is running.
380 @retval Others Failed to set the EHCI to run.
381
382 **/
383 EFI_STATUS
384 EhcRunHC (
385 IN PEI_USB2_HC_DEV *Ehc,
386 IN UINT32 Timeout
387 )
388 {
389 EFI_STATUS Status;
390
391 EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);
392 Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT, FALSE, Timeout);
393 return Status;
394 }
395
396 /**
397 Power On All EHCI Ports.
398
399 @param Ehc The EHCI device.
400
401 **/
402 VOID
403 EhcPowerOnAllPorts (
404 IN PEI_USB2_HC_DEV *Ehc
405 )
406 {
407 UINT8 PortNumber;
408 UINT8 Index;
409 UINT32 RegVal;
410
411 PortNumber = (UINT8)(Ehc->HcStructParams & HCSP_NPORTS);
412 for (Index = 0; Index < PortNumber; Index++) {
413 //
414 // Do not clear port status bits on initialization. Otherwise devices will
415 // not enumerate properly at startup.
416 //
417 RegVal = EhcReadOpReg(Ehc, EHC_PORT_STAT_OFFSET + 4 * Index);
418 RegVal &= ~PORTSC_CHANGE_MASK;
419 RegVal |= PORTSC_POWER;
420 EhcWriteOpReg (Ehc, EHC_PORT_STAT_OFFSET + 4 * Index, RegVal);
421 }
422 }
423
424 /**
425 Initialize the HC hardware.
426 EHCI spec lists the five things to do to initialize the hardware.
427 1. Program CTRLDSSEGMENT.
428 2. Set USBINTR to enable interrupts.
429 3. Set periodic list base.
430 4. Set USBCMD, interrupt threshold, frame list size etc.
431 5. Write 1 to CONFIGFLAG to route all ports to EHCI.
432
433 @param Ehc The EHCI device.
434
435 @retval EFI_SUCCESS The EHCI has come out of halt state.
436 @retval EFI_TIMEOUT Time out happened.
437
438 **/
439 EFI_STATUS
440 EhcInitHC (
441 IN PEI_USB2_HC_DEV *Ehc
442 )
443 {
444 EFI_STATUS Status;
445 EFI_PHYSICAL_ADDRESS TempPtr;
446 UINTN PageNumber;
447
448 ASSERT (EhcIsHalt (Ehc));
449
450 //
451 // Allocate the periodic frame and associated memeory
452 // management facilities if not already done.
453 //
454 if (Ehc->PeriodFrame != NULL) {
455 EhcFreeSched (Ehc);
456 }
457 PageNumber = sizeof(PEI_URB)/PAGESIZE +1;
458 Status = PeiServicesAllocatePages (
459 EfiBootServicesCode,
460 PageNumber,
461 &TempPtr
462 );
463 Ehc->Urb = (PEI_URB *) ((UINTN) TempPtr);
464 if (Ehc->Urb == NULL) {
465 return Status;
466 }
467
468 EhcPowerOnAllPorts (Ehc);
469 MicroSecondDelay (EHC_ROOT_PORT_RECOVERY_STALL);
470
471 Status = EhcInitSched (Ehc);
472
473 if (EFI_ERROR (Status)) {
474 return Status;
475 }
476 //
477 // 1. Program the CTRLDSSEGMENT register with the high 32 bit addr
478 //
479 EhcWriteOpReg (Ehc, EHC_CTRLDSSEG_OFFSET, Ehc->High32bitAddr);
480
481 //
482 // 2. Clear USBINTR to disable all the interrupt. UEFI works by polling
483 //
484 EhcWriteOpReg (Ehc, EHC_USBINTR_OFFSET, 0);
485
486 //
487 // 3. Program periodic frame list, already done in EhcInitSched
488 // 4. Start the Host Controller
489 //
490 EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);
491
492 //
493 // 5. Set all ports routing to EHC
494 //
495 EhcSetOpRegBit (Ehc, EHC_CONFIG_FLAG_OFFSET, CONFIGFLAG_ROUTE_EHC);
496
497 //
498 // Wait roothub port power stable
499 //
500 MicroSecondDelay (EHC_ROOT_PORT_RECOVERY_STALL);
501
502 Status = EhcEnablePeriodSchd (Ehc, EHC_GENERIC_TIMEOUT);
503
504 if (EFI_ERROR (Status)) {
505 return Status;
506 }
507
508 Status = EhcEnableAsyncSchd (Ehc, EHC_GENERIC_TIMEOUT);
509
510 if (EFI_ERROR (Status)) {
511 return Status;
512 }
513
514 return EFI_SUCCESS;
515 }
516
517 /**
518 Submits bulk transfer to a bulk endpoint of a USB device.
519
520 @param PeiServices The pointer of EFI_PEI_SERVICES.
521 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
522 @param DeviceAddress Target device address.
523 @param EndPointAddress Endpoint number and its direction in bit 7.
524 @param DeviceSpeed Device speed, Low speed device doesn't support
525 bulk transfer.
526 @param MaximumPacketLength Maximum packet size the endpoint is capable of
527 sending or receiving.
528 @param Data Array of pointers to the buffers of data to transmit
529 from or receive into.
530 @param DataLength The lenght of the data buffer.
531 @param DataToggle On input, the initial data toggle for the transfer;
532 On output, it is updated to to next data toggle to use of
533 the subsequent bulk transfer.
534 @param TimeOut Indicates the maximum time, in millisecond, which the
535 transfer is allowed to complete.
536 If Timeout is 0, then the caller must wait for the function
537 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
538 @param Translator A pointr to the transaction translator data.
539 @param TransferResult A pointer to the detailed result information of the
540 bulk transfer.
541
542 @retval EFI_SUCCESS The transfer was completed successfully.
543 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
544 @retval EFI_INVALID_PARAMETER Parameters are invalid.
545 @retval EFI_TIMEOUT The transfer failed due to timeout.
546 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
547
548 **/
549 EFI_STATUS
550 EFIAPI
551 EhcBulkTransfer (
552 IN EFI_PEI_SERVICES **PeiServices,
553 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
554 IN UINT8 DeviceAddress,
555 IN UINT8 EndPointAddress,
556 IN UINT8 DeviceSpeed,
557 IN UINTN MaximumPacketLength,
558 IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
559 IN OUT UINTN *DataLength,
560 IN OUT UINT8 *DataToggle,
561 IN UINTN TimeOut,
562 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
563 OUT UINT32 *TransferResult
564 )
565 {
566 PEI_USB2_HC_DEV *Ehc;
567 PEI_URB *Urb;
568 EFI_STATUS Status;
569
570 //
571 // Validate the parameters
572 //
573 if ((DataLength == NULL) || (*DataLength == 0) ||
574 (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL)) {
575 return EFI_INVALID_PARAMETER;
576 }
577
578 if ((*DataToggle != 0) && (*DataToggle != 1)) {
579 return EFI_INVALID_PARAMETER;
580 }
581
582 if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||
583 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
584 ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512))) {
585 return EFI_INVALID_PARAMETER;
586 }
587
588 Ehc =PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS(This);
589 *TransferResult = EFI_USB_ERR_SYSTEM;
590 Status = EFI_DEVICE_ERROR;
591
592 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
593 EhcAckAllInterrupt (Ehc);
594 goto ON_EXIT;
595 }
596
597 EhcAckAllInterrupt (Ehc);
598
599 //
600 // Create a new URB, insert it into the asynchronous
601 // schedule list, then poll the execution status.
602 //
603 Urb = EhcCreateUrb (
604 Ehc,
605 DeviceAddress,
606 EndPointAddress,
607 DeviceSpeed,
608 *DataToggle,
609 MaximumPacketLength,
610 Translator,
611 EHC_BULK_TRANSFER,
612 NULL,
613 Data[0],
614 *DataLength,
615 NULL,
616 NULL,
617 1
618 );
619
620 if (Urb == NULL) {
621 Status = EFI_OUT_OF_RESOURCES;
622 goto ON_EXIT;
623 }
624
625 EhcLinkQhToAsync (Ehc, Urb->Qh);
626 Status = EhcExecTransfer (Ehc, Urb, TimeOut);
627 EhcUnlinkQhFromAsync (Ehc, Urb->Qh);
628
629 *TransferResult = Urb->Result;
630 *DataLength = Urb->Completed;
631 *DataToggle = Urb->DataToggle;
632
633 if (*TransferResult == EFI_USB_NOERROR) {
634 Status = EFI_SUCCESS;
635 }
636
637 EhcAckAllInterrupt (Ehc);
638 EhcFreeUrb (Ehc, Urb);
639
640 ON_EXIT:
641 return Status;
642 }
643
644 /**
645 Retrieves the number of root hub ports.
646
647 @param[in] PeiServices The pointer to the PEI Services Table.
648 @param[in] This The pointer to this instance of the
649 PEI_USB2_HOST_CONTROLLER_PPI.
650 @param[out] PortNumber The pointer to the number of the root hub ports.
651
652 @retval EFI_SUCCESS The port number was retrieved successfully.
653 @retval EFI_INVALID_PARAMETER PortNumber is NULL.
654
655 **/
656 EFI_STATUS
657 EFIAPI
658 EhcGetRootHubPortNumber (
659 IN EFI_PEI_SERVICES **PeiServices,
660 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
661 OUT UINT8 *PortNumber
662 )
663 {
664
665 PEI_USB2_HC_DEV *EhcDev;
666 EhcDev = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);
667
668 if (PortNumber == NULL) {
669 return EFI_INVALID_PARAMETER;
670 }
671
672 *PortNumber = (UINT8)(EhcDev->HcStructParams & HCSP_NPORTS);
673 return EFI_SUCCESS;
674
675 }
676
677 /**
678 Clears a feature for the specified root hub port.
679
680 @param PeiServices The pointer of EFI_PEI_SERVICES.
681 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
682 @param PortNumber Specifies the root hub port whose feature
683 is requested to be cleared.
684 @param PortFeature Indicates the feature selector associated with the
685 feature clear request.
686
687 @retval EFI_SUCCESS The feature specified by PortFeature was cleared
688 for the USB root hub port specified by PortNumber.
689 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
690
691 **/
692 EFI_STATUS
693 EFIAPI
694 EhcClearRootHubPortFeature (
695 IN EFI_PEI_SERVICES **PeiServices,
696 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
697 IN UINT8 PortNumber,
698 IN EFI_USB_PORT_FEATURE PortFeature
699 )
700 {
701 PEI_USB2_HC_DEV *Ehc;
702 UINT32 Offset;
703 UINT32 State;
704 UINT32 TotalPort;
705 EFI_STATUS Status;
706
707 Ehc = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);
708 Status = EFI_SUCCESS;
709
710 TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);
711
712 if (PortNumber >= TotalPort) {
713 Status = EFI_INVALID_PARAMETER;
714 goto ON_EXIT;
715 }
716
717 Offset = EHC_PORT_STAT_OFFSET + (4 * PortNumber);
718 State = EhcReadOpReg (Ehc, Offset);
719 State &= ~PORTSC_CHANGE_MASK;
720
721 switch (PortFeature) {
722 case EfiUsbPortEnable:
723 //
724 // Clear PORT_ENABLE feature means disable port.
725 //
726 State &= ~PORTSC_ENABLED;
727 EhcWriteOpReg (Ehc, Offset, State);
728 break;
729
730 case EfiUsbPortSuspend:
731 //
732 // A write of zero to this bit is ignored by the host
733 // controller. The host controller will unconditionally
734 // set this bit to a zero when:
735 // 1. software sets the Forct Port Resume bit to a zero from a one.
736 // 2. software sets the Port Reset bit to a one frome a zero.
737 //
738 State &= ~PORSTSC_RESUME;
739 EhcWriteOpReg (Ehc, Offset, State);
740 break;
741
742 case EfiUsbPortReset:
743 //
744 // Clear PORT_RESET means clear the reset signal.
745 //
746 State &= ~PORTSC_RESET;
747 EhcWriteOpReg (Ehc, Offset, State);
748 break;
749
750 case EfiUsbPortOwner:
751 //
752 // Clear port owner means this port owned by EHC
753 //
754 State &= ~PORTSC_OWNER;
755 EhcWriteOpReg (Ehc, Offset, State);
756 break;
757
758 case EfiUsbPortConnectChange:
759 //
760 // Clear connect status change
761 //
762 State |= PORTSC_CONN_CHANGE;
763 EhcWriteOpReg (Ehc, Offset, State);
764 break;
765
766 case EfiUsbPortEnableChange:
767 //
768 // Clear enable status change
769 //
770 State |= PORTSC_ENABLE_CHANGE;
771 EhcWriteOpReg (Ehc, Offset, State);
772 break;
773
774 case EfiUsbPortOverCurrentChange:
775 //
776 // Clear PortOverCurrent change
777 //
778 State |= PORTSC_OVERCUR_CHANGE;
779 EhcWriteOpReg (Ehc, Offset, State);
780 break;
781
782 case EfiUsbPortPower:
783 case EfiUsbPortSuspendChange:
784 case EfiUsbPortResetChange:
785 //
786 // Not supported or not related operation
787 //
788 break;
789
790 default:
791 Status = EFI_INVALID_PARAMETER;
792 break;
793 }
794
795 ON_EXIT:
796 return Status;
797 }
798
799 /**
800 Sets a feature for the specified root hub port.
801
802 @param PeiServices The pointer of EFI_PEI_SERVICES
803 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI
804 @param PortNumber Root hub port to set.
805 @param PortFeature Feature to set.
806
807 @retval EFI_SUCCESS The feature specified by PortFeature was set.
808 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
809 @retval EFI_TIMEOUT The time out occurred.
810
811 **/
812 EFI_STATUS
813 EFIAPI
814 EhcSetRootHubPortFeature (
815 IN EFI_PEI_SERVICES **PeiServices,
816 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
817 IN UINT8 PortNumber,
818 IN EFI_USB_PORT_FEATURE PortFeature
819 )
820 {
821 PEI_USB2_HC_DEV *Ehc;
822 UINT32 Offset;
823 UINT32 State;
824 UINT32 TotalPort;
825 EFI_STATUS Status;
826
827 Ehc = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);
828 Status = EFI_SUCCESS;
829
830 TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);
831
832 if (PortNumber >= TotalPort) {
833 Status = EFI_INVALID_PARAMETER;
834 goto ON_EXIT;
835 }
836
837 Offset = (UINT32) (EHC_PORT_STAT_OFFSET + (4 * PortNumber));
838 State = EhcReadOpReg (Ehc, Offset);
839
840 //
841 // Mask off the port status change bits, these bits are
842 // write clean bit
843 //
844 State &= ~PORTSC_CHANGE_MASK;
845
846 switch (PortFeature) {
847 case EfiUsbPortEnable:
848 //
849 // Sofeware can't set this bit, Port can only be enable by
850 // EHCI as a part of the reset and enable
851 //
852 State |= PORTSC_ENABLED;
853 EhcWriteOpReg (Ehc, Offset, State);
854 break;
855
856 case EfiUsbPortSuspend:
857 State |= PORTSC_SUSPEND;
858 EhcWriteOpReg (Ehc, Offset, State);
859 break;
860
861 case EfiUsbPortReset:
862 //
863 // Make sure Host Controller not halt before reset it
864 //
865 if (EhcIsHalt (Ehc)) {
866 Status = EhcRunHC (Ehc, EHC_GENERIC_TIMEOUT);
867
868 if (EFI_ERROR (Status)) {
869 break;
870 }
871 }
872
873 //
874 // Set one to PortReset bit must also set zero to PortEnable bit
875 //
876 State |= PORTSC_RESET;
877 State &= ~PORTSC_ENABLED;
878 EhcWriteOpReg (Ehc, Offset, State);
879 break;
880
881 case EfiUsbPortPower:
882 //
883 // Not supported, ignore the operation
884 //
885 Status = EFI_SUCCESS;
886 break;
887
888 case EfiUsbPortOwner:
889 State |= PORTSC_OWNER;
890 EhcWriteOpReg (Ehc, Offset, State);
891 break;
892
893 default:
894 Status = EFI_INVALID_PARAMETER;
895 }
896
897 ON_EXIT:
898 return Status;
899 }
900
901 /**
902 Retrieves the current status of a USB root hub port.
903
904 @param PeiServices The pointer of EFI_PEI_SERVICES.
905 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
906 @param PortNumber The root hub port to retrieve the state from.
907 @param PortStatus Variable to receive the port state.
908
909 @retval EFI_SUCCESS The status of the USB root hub port specified.
910 by PortNumber was returned in PortStatus.
911 @retval EFI_INVALID_PARAMETER PortNumber is invalid.
912
913 **/
914 EFI_STATUS
915 EFIAPI
916 EhcGetRootHubPortStatus (
917 IN EFI_PEI_SERVICES **PeiServices,
918 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
919 IN UINT8 PortNumber,
920 OUT EFI_USB_PORT_STATUS *PortStatus
921 )
922 {
923 PEI_USB2_HC_DEV *Ehc;
924 UINT32 Offset;
925 UINT32 State;
926 UINT32 TotalPort;
927 UINTN Index;
928 UINTN MapSize;
929 EFI_STATUS Status;
930
931 if (PortStatus == NULL) {
932 return EFI_INVALID_PARAMETER;
933 }
934
935 Ehc = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS(This);
936 Status = EFI_SUCCESS;
937
938 TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);
939
940 if (PortNumber >= TotalPort) {
941 Status = EFI_INVALID_PARAMETER;
942 goto ON_EXIT;
943 }
944
945 Offset = (UINT32) (EHC_PORT_STAT_OFFSET + (4 * PortNumber));
946 PortStatus->PortStatus = 0;
947 PortStatus->PortChangeStatus = 0;
948
949 State = EhcReadOpReg (Ehc, Offset);
950
951 //
952 // Identify device speed. If in K state, it is low speed.
953 // If the port is enabled after reset, the device is of
954 // high speed. The USB bus driver should retrieve the actual
955 // port speed after reset.
956 //
957 if (EHC_BIT_IS_SET (State, PORTSC_LINESTATE_K)) {
958 PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
959
960 } else if (EHC_BIT_IS_SET (State, PORTSC_ENABLED)) {
961 PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;
962 }
963
964 //
965 // Convert the EHCI port/port change state to UEFI status
966 //
967 MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);
968
969 for (Index = 0; Index < MapSize; Index++) {
970 if (EHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {
971 PortStatus->PortStatus = (UINT16) (PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);
972 }
973 }
974
975 MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
976
977 for (Index = 0; Index < MapSize; Index++) {
978 if (EHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {
979 PortStatus->PortChangeStatus = (UINT16) (PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);
980 }
981 }
982
983 ON_EXIT:
984 return Status;
985 }
986
987 /**
988 Submits control transfer to a target USB device.
989
990 @param PeiServices The pointer of EFI_PEI_SERVICES.
991 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
992 @param DeviceAddress The target device address.
993 @param DeviceSpeed Target device speed.
994 @param MaximumPacketLength Maximum packet size the default control transfer
995 endpoint is capable of sending or receiving.
996 @param Request USB device request to send.
997 @param TransferDirection Specifies the data direction for the data stage.
998 @param Data Data buffer to be transmitted or received from USB device.
999 @param DataLength The size (in bytes) of the data buffer.
1000 @param TimeOut Indicates the maximum timeout, in millisecond.
1001 If Timeout is 0, then the caller must wait for the function
1002 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
1003 @param Translator Transaction translator to be used by this device.
1004 @param TransferResult Return the result of this control transfer.
1005
1006 @retval EFI_SUCCESS Transfer was completed successfully.
1007 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
1008 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
1009 @retval EFI_TIMEOUT Transfer failed due to timeout.
1010 @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
1011
1012 **/
1013 EFI_STATUS
1014 EFIAPI
1015 EhcControlTransfer (
1016 IN EFI_PEI_SERVICES **PeiServices,
1017 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
1018 IN UINT8 DeviceAddress,
1019 IN UINT8 DeviceSpeed,
1020 IN UINTN MaximumPacketLength,
1021 IN EFI_USB_DEVICE_REQUEST *Request,
1022 IN EFI_USB_DATA_DIRECTION TransferDirection,
1023 IN OUT VOID *Data,
1024 IN OUT UINTN *DataLength,
1025 IN UINTN TimeOut,
1026 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1027 OUT UINT32 *TransferResult
1028 )
1029 {
1030 PEI_USB2_HC_DEV *Ehc;
1031 PEI_URB *Urb;
1032 UINT8 Endpoint;
1033 EFI_STATUS Status;
1034
1035 //
1036 // Validate parameters
1037 //
1038 if ((Request == NULL) || (TransferResult == NULL)) {
1039 return EFI_INVALID_PARAMETER;
1040 }
1041
1042 if ((TransferDirection != EfiUsbDataIn) &&
1043 (TransferDirection != EfiUsbDataOut) &&
1044 (TransferDirection != EfiUsbNoData)) {
1045 return EFI_INVALID_PARAMETER;
1046 }
1047
1048 if ((TransferDirection == EfiUsbNoData) &&
1049 ((Data != NULL) || (*DataLength != 0))) {
1050 return EFI_INVALID_PARAMETER;
1051 }
1052
1053 if ((TransferDirection != EfiUsbNoData) &&
1054 ((Data == NULL) || (*DataLength == 0))) {
1055 return EFI_INVALID_PARAMETER;
1056 }
1057
1058 if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&
1059 (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) {
1060 return EFI_INVALID_PARAMETER;
1061 }
1062
1063
1064 if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||
1065 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
1066 ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512))) {
1067 return EFI_INVALID_PARAMETER;
1068 }
1069
1070 Ehc = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);
1071
1072 Status = EFI_DEVICE_ERROR;
1073 *TransferResult = EFI_USB_ERR_SYSTEM;
1074
1075 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
1076 EhcAckAllInterrupt (Ehc);
1077 goto ON_EXIT;
1078 }
1079
1080 EhcAckAllInterrupt (Ehc);
1081
1082 //
1083 // Create a new URB, insert it into the asynchronous
1084 // schedule list, then poll the execution status.
1085 //
1086 //
1087 // Encode the direction in address, although default control
1088 // endpoint is bidirectional. EhcCreateUrb expects this
1089 // combination of Ep addr and its direction.
1090 //
1091 Endpoint = (UINT8) (0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));
1092 Urb = EhcCreateUrb (
1093 Ehc,
1094 DeviceAddress,
1095 Endpoint,
1096 DeviceSpeed,
1097 0,
1098 MaximumPacketLength,
1099 Translator,
1100 EHC_CTRL_TRANSFER,
1101 Request,
1102 Data,
1103 *DataLength,
1104 NULL,
1105 NULL,
1106 1
1107 );
1108
1109 if (Urb == NULL) {
1110 Status = EFI_OUT_OF_RESOURCES;
1111 goto ON_EXIT;
1112 }
1113
1114 EhcLinkQhToAsync (Ehc, Urb->Qh);
1115 Status = EhcExecTransfer (Ehc, Urb, TimeOut);
1116 EhcUnlinkQhFromAsync (Ehc, Urb->Qh);
1117
1118 //
1119 // Get the status from URB. The result is updated in EhcCheckUrbResult
1120 // which is called by EhcExecTransfer
1121 //
1122 *TransferResult = Urb->Result;
1123 *DataLength = Urb->Completed;
1124
1125 if (*TransferResult == EFI_USB_NOERROR) {
1126 Status = EFI_SUCCESS;
1127 }
1128
1129 EhcAckAllInterrupt (Ehc);
1130 EhcFreeUrb (Ehc, Urb);
1131
1132 ON_EXIT:
1133 return Status;
1134 }
1135
1136 /**
1137 One notified function to stop the Host Controller at the end of PEI
1138
1139 @param[in] PeiServices Pointer to PEI Services Table.
1140 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification event that
1141 caused this function to execute.
1142 @param[in] Ppi Pointer to the PPI data associated with this function.
1143
1144 @retval EFI_SUCCESS The function completes successfully
1145 @retval others
1146 **/
1147 EFI_STATUS
1148 EFIAPI
1149 EhcEndOfPei (
1150 IN EFI_PEI_SERVICES **PeiServices,
1151 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
1152 IN VOID *Ppi
1153 )
1154 {
1155 PEI_USB2_HC_DEV *Ehc;
1156
1157 Ehc = PEI_RECOVERY_USB_EHC_DEV_FROM_THIS_NOTIFY (NotifyDescriptor);
1158
1159 EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);
1160
1161 EhcFreeSched (Ehc);
1162
1163 return EFI_SUCCESS;
1164 }
1165
1166 /**
1167 @param FileHandle Handle of the file being invoked.
1168 @param PeiServices Describes the list of possible PEI Services.
1169
1170 @retval EFI_SUCCESS PPI successfully installed.
1171
1172 **/
1173 EFI_STATUS
1174 EFIAPI
1175 EhcPeimEntry (
1176 IN EFI_PEI_FILE_HANDLE FileHandle,
1177 IN CONST EFI_PEI_SERVICES **PeiServices
1178 )
1179 {
1180 PEI_USB_CONTROLLER_PPI *ChipSetUsbControllerPpi;
1181 EFI_STATUS Status;
1182 UINT8 Index;
1183 UINTN ControllerType;
1184 UINTN BaseAddress;
1185 UINTN MemPages;
1186 PEI_USB2_HC_DEV *EhcDev;
1187 EFI_PHYSICAL_ADDRESS TempPtr;
1188
1189 //
1190 // Shadow this PEIM to run from memory
1191 //
1192 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
1193 return EFI_SUCCESS;
1194 }
1195
1196 Status = PeiServicesLocatePpi (
1197 &gPeiUsbControllerPpiGuid,
1198 0,
1199 NULL,
1200 (VOID **) &ChipSetUsbControllerPpi
1201 );
1202 if (EFI_ERROR (Status)) {
1203 return EFI_UNSUPPORTED;
1204 }
1205
1206 Index = 0;
1207 while (TRUE) {
1208 Status = ChipSetUsbControllerPpi->GetUsbController (
1209 (EFI_PEI_SERVICES **) PeiServices,
1210 ChipSetUsbControllerPpi,
1211 Index,
1212 &ControllerType,
1213 &BaseAddress
1214 );
1215 //
1216 // When status is error, meant no controller is found
1217 //
1218 if (EFI_ERROR (Status)) {
1219 break;
1220 }
1221
1222 //
1223 // This PEIM is for UHC type controller.
1224 //
1225 if (ControllerType != PEI_EHCI_CONTROLLER) {
1226 Index++;
1227 continue;
1228 }
1229
1230 MemPages = sizeof (PEI_USB2_HC_DEV) / PAGESIZE + 1;
1231 Status = PeiServicesAllocatePages (
1232 EfiBootServicesCode,
1233 MemPages,
1234 &TempPtr
1235 );
1236 if (EFI_ERROR (Status)) {
1237 return EFI_OUT_OF_RESOURCES;
1238 }
1239
1240 ZeroMem((VOID *)(UINTN)TempPtr, MemPages*PAGESIZE);
1241 EhcDev = (PEI_USB2_HC_DEV *) ((UINTN) TempPtr);
1242
1243 EhcDev->Signature = USB2_HC_DEV_SIGNATURE;
1244
1245 IoMmuInit (&EhcDev->IoMmu);
1246
1247 EhcDev->UsbHostControllerBaseAddress = (UINT32) BaseAddress;
1248
1249
1250 EhcDev->HcStructParams = EhcReadCapRegister (EhcDev, EHC_HCSPARAMS_OFFSET);
1251 EhcDev->HcCapParams = EhcReadCapRegister (EhcDev, EHC_HCCPARAMS_OFFSET);
1252 EhcDev->CapLen = EhcReadCapRegister (EhcDev, EHC_CAPLENGTH_OFFSET) & 0x0FF;
1253 //
1254 // Initialize Uhc's hardware
1255 //
1256 Status = InitializeUsbHC (EhcDev);
1257 if (EFI_ERROR (Status)) {
1258 return Status;
1259 }
1260
1261 EhcDev->Usb2HostControllerPpi.ControlTransfer = EhcControlTransfer;
1262 EhcDev->Usb2HostControllerPpi.BulkTransfer = EhcBulkTransfer;
1263 EhcDev->Usb2HostControllerPpi.GetRootHubPortNumber = EhcGetRootHubPortNumber;
1264 EhcDev->Usb2HostControllerPpi.GetRootHubPortStatus = EhcGetRootHubPortStatus;
1265 EhcDev->Usb2HostControllerPpi.SetRootHubPortFeature = EhcSetRootHubPortFeature;
1266 EhcDev->Usb2HostControllerPpi.ClearRootHubPortFeature = EhcClearRootHubPortFeature;
1267
1268 EhcDev->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
1269 EhcDev->PpiDescriptor.Guid = &gPeiUsb2HostControllerPpiGuid;
1270 EhcDev->PpiDescriptor.Ppi = &EhcDev->Usb2HostControllerPpi;
1271
1272 Status = PeiServicesInstallPpi (&EhcDev->PpiDescriptor);
1273 if (EFI_ERROR (Status)) {
1274 Index++;
1275 continue;
1276 }
1277
1278 EhcDev->EndOfPeiNotifyList.Flags = (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
1279 EhcDev->EndOfPeiNotifyList.Guid = &gEfiEndOfPeiSignalPpiGuid;
1280 EhcDev->EndOfPeiNotifyList.Notify = EhcEndOfPei;
1281
1282 PeiServicesNotifyPpi (&EhcDev->EndOfPeiNotifyList);
1283
1284 Index++;
1285 }
1286
1287 return EFI_SUCCESS;
1288 }
1289
1290 /**
1291 @param EhcDev EHCI Device.
1292
1293 @retval EFI_SUCCESS EHCI successfully initialized.
1294 @retval EFI_ABORTED EHCI was failed to be initialized.
1295
1296 **/
1297 EFI_STATUS
1298 InitializeUsbHC (
1299 IN PEI_USB2_HC_DEV *EhcDev
1300 )
1301 {
1302 EFI_STATUS Status;
1303
1304
1305 EhcResetHC (EhcDev, EHC_RESET_TIMEOUT);
1306
1307 Status = EhcInitHC (EhcDev);
1308
1309 if (EFI_ERROR (Status)) {
1310 return EFI_ABORTED;
1311 }
1312
1313 return EFI_SUCCESS;
1314 }