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