]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/EhciPei/EhcPeim.c
Refine the save action for the BdsDxe.
[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 - 2013, 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
417 PortNumber = (UINT8)(Ehc->HcStructParams & HCSP_NPORTS);
418 for (Index = 0; Index < PortNumber; Index++) {
419 EhcSetOpRegBit (Ehc, EHC_PORT_STAT_OFFSET + 4 * Index, PORTSC_POWER);
420 }
421 }
422
423 /**
424 Initialize the HC hardware.
425 EHCI spec lists the five things to do to initialize the hardware.
426 1. Program CTRLDSSEGMENT.
427 2. Set USBINTR to enable interrupts.
428 3. Set periodic list base.
429 4. Set USBCMD, interrupt threshold, frame list size etc.
430 5. Write 1 to CONFIGFLAG to route all ports to EHCI.
431
432 @param Ehc The EHCI device.
433
434 @retval EFI_SUCCESS The EHCI has come out of halt state.
435 @retval EFI_TIMEOUT Time out happened.
436
437 **/
438 EFI_STATUS
439 EhcInitHC (
440 IN PEI_USB2_HC_DEV *Ehc
441 )
442 {
443 EFI_STATUS Status;
444 EFI_PHYSICAL_ADDRESS TempPtr;
445 UINTN PageNumber;
446
447 ASSERT (EhcIsHalt (Ehc));
448
449 //
450 // Allocate the periodic frame and associated memeory
451 // management facilities if not already done.
452 //
453 if (Ehc->PeriodFrame != NULL) {
454 EhcFreeSched (Ehc);
455 }
456 PageNumber = sizeof(PEI_URB)/PAGESIZE +1;
457 Status = PeiServicesAllocatePages (
458 EfiBootServicesCode,
459 PageNumber,
460 &TempPtr
461 );
462 Ehc->Urb = (PEI_URB *) ((UINTN) TempPtr);
463 if (Ehc->Urb == NULL) {
464 return Status;
465 }
466
467 EhcPowerOnAllPorts (Ehc);
468 MicroSecondDelay (EHC_ROOT_PORT_RECOVERY_STALL);
469
470 Status = EhcInitSched (Ehc);
471
472 if (EFI_ERROR (Status)) {
473 return Status;
474 }
475 //
476 // 1. Program the CTRLDSSEGMENT register with the high 32 bit addr
477 //
478 EhcWriteOpReg (Ehc, EHC_CTRLDSSEG_OFFSET, Ehc->High32bitAddr);
479
480 //
481 // 2. Clear USBINTR to disable all the interrupt. UEFI works by polling
482 //
483 EhcWriteOpReg (Ehc, EHC_USBINTR_OFFSET, 0);
484
485 //
486 // 3. Program periodic frame list, already done in EhcInitSched
487 // 4. Start the Host Controller
488 //
489 EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);
490
491 //
492 // 5. Set all ports routing to EHC
493 //
494 EhcSetOpRegBit (Ehc, EHC_CONFIG_FLAG_OFFSET, CONFIGFLAG_ROUTE_EHC);
495
496 //
497 // Wait roothub port power stable
498 //
499 MicroSecondDelay (EHC_ROOT_PORT_RECOVERY_STALL);
500
501 Status = EhcEnablePeriodSchd (Ehc, EHC_GENERIC_TIMEOUT);
502
503 if (EFI_ERROR (Status)) {
504 return Status;
505 }
506
507 Status = EhcEnableAsyncSchd (Ehc, EHC_GENERIC_TIMEOUT);
508
509 if (EFI_ERROR (Status)) {
510 return Status;
511 }
512
513 return EFI_SUCCESS;
514 }
515
516 /**
517 Submits bulk transfer to a bulk endpoint of a USB device.
518
519 @param PeiServices The pointer of EFI_PEI_SERVICES.
520 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
521 @param DeviceAddress Target device address.
522 @param EndPointAddress Endpoint number and its direction in bit 7.
523 @param DeviceSpeed Device speed, Low speed device doesn't support
524 bulk transfer.
525 @param MaximumPacketLength Maximum packet size the endpoint is capable of
526 sending or receiving.
527 @param Data Array of pointers to the buffers of data to transmit
528 from or receive into.
529 @param DataLength The lenght of the data buffer.
530 @param DataToggle On input, the initial data toggle for the transfer;
531 On output, it is updated to to next data toggle to use of
532 the subsequent bulk transfer.
533 @param TimeOut Indicates the maximum time, in millisecond, which the
534 transfer is allowed to complete.
535 If Timeout is 0, then the caller must wait for the function
536 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
537 @param Translator A pointr to the transaction translator data.
538 @param TransferResult A pointer to the detailed result information of the
539 bulk transfer.
540
541 @retval EFI_SUCCESS The transfer was completed successfully.
542 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
543 @retval EFI_INVALID_PARAMETER Parameters are invalid.
544 @retval EFI_TIMEOUT The transfer failed due to timeout.
545 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
546
547 **/
548 EFI_STATUS
549 EFIAPI
550 EhcBulkTransfer (
551 IN EFI_PEI_SERVICES **PeiServices,
552 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
553 IN UINT8 DeviceAddress,
554 IN UINT8 EndPointAddress,
555 IN UINT8 DeviceSpeed,
556 IN UINTN MaximumPacketLength,
557 IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
558 IN OUT UINTN *DataLength,
559 IN OUT UINT8 *DataToggle,
560 IN UINTN TimeOut,
561 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
562 OUT UINT32 *TransferResult
563 )
564 {
565 PEI_USB2_HC_DEV *Ehc;
566 PEI_URB *Urb;
567 EFI_STATUS Status;
568
569 //
570 // Validate the parameters
571 //
572 if ((DataLength == NULL) || (*DataLength == 0) ||
573 (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL)) {
574 return EFI_INVALID_PARAMETER;
575 }
576
577 if ((*DataToggle != 0) && (*DataToggle != 1)) {
578 return EFI_INVALID_PARAMETER;
579 }
580
581 if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||
582 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
583 ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512))) {
584 return EFI_INVALID_PARAMETER;
585 }
586
587 Ehc =PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS(This);
588 *TransferResult = EFI_USB_ERR_SYSTEM;
589 Status = EFI_DEVICE_ERROR;
590
591 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
592 EhcAckAllInterrupt (Ehc);
593 goto ON_EXIT;
594 }
595
596 EhcAckAllInterrupt (Ehc);
597
598 //
599 // Create a new URB, insert it into the asynchronous
600 // schedule list, then poll the execution status.
601 //
602 Urb = EhcCreateUrb (
603 Ehc,
604 DeviceAddress,
605 EndPointAddress,
606 DeviceSpeed,
607 *DataToggle,
608 MaximumPacketLength,
609 Translator,
610 EHC_BULK_TRANSFER,
611 NULL,
612 Data[0],
613 *DataLength,
614 NULL,
615 NULL,
616 1
617 );
618
619 if (Urb == NULL) {
620 Status = EFI_OUT_OF_RESOURCES;
621 goto ON_EXIT;
622 }
623
624 EhcLinkQhToAsync (Ehc, Urb->Qh);
625 Status = EhcExecTransfer (Ehc, Urb, TimeOut);
626 EhcUnlinkQhFromAsync (Ehc, Urb->Qh);
627
628 *TransferResult = Urb->Result;
629 *DataLength = Urb->Completed;
630 *DataToggle = Urb->DataToggle;
631
632 if (*TransferResult == EFI_USB_NOERROR) {
633 Status = EFI_SUCCESS;
634 }
635
636 EhcAckAllInterrupt (Ehc);
637 EhcFreeUrb (Ehc, Urb);
638
639 ON_EXIT:
640 return Status;
641 }
642
643 /**
644 Retrieves the number of root hub ports.
645
646 @param[in] PeiServices The pointer to the PEI Services Table.
647 @param[in] This The pointer to this instance of the
648 PEI_USB2_HOST_CONTROLLER_PPI.
649 @param[out] PortNumber The pointer to the number of the root hub ports.
650
651 @retval EFI_SUCCESS The port number was retrieved successfully.
652 @retval EFI_INVALID_PARAMETER PortNumber is NULL.
653
654 **/
655 EFI_STATUS
656 EFIAPI
657 EhcGetRootHubPortNumber (
658 IN EFI_PEI_SERVICES **PeiServices,
659 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
660 OUT UINT8 *PortNumber
661 )
662 {
663
664 PEI_USB2_HC_DEV *EhcDev;
665 EhcDev = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);
666
667 if (PortNumber == NULL) {
668 return EFI_INVALID_PARAMETER;
669 }
670
671 *PortNumber = (UINT8)(EhcDev->HcStructParams & HCSP_NPORTS);
672 return EFI_SUCCESS;
673
674 }
675
676 /**
677 Clears a feature for the specified root hub port.
678
679 @param PeiServices The pointer of EFI_PEI_SERVICES.
680 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
681 @param PortNumber Specifies the root hub port whose feature
682 is requested to be cleared.
683 @param PortFeature Indicates the feature selector associated with the
684 feature clear request.
685
686 @retval EFI_SUCCESS The feature specified by PortFeature was cleared
687 for the USB root hub port specified by PortNumber.
688 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
689
690 **/
691 EFI_STATUS
692 EFIAPI
693 EhcClearRootHubPortFeature (
694 IN EFI_PEI_SERVICES **PeiServices,
695 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
696 IN UINT8 PortNumber,
697 IN EFI_USB_PORT_FEATURE PortFeature
698 )
699 {
700 PEI_USB2_HC_DEV *Ehc;
701 UINT32 Offset;
702 UINT32 State;
703 UINT32 TotalPort;
704 EFI_STATUS Status;
705
706 Ehc = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);
707 Status = EFI_SUCCESS;
708
709 TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);
710
711 if (PortNumber >= TotalPort) {
712 Status = EFI_INVALID_PARAMETER;
713 goto ON_EXIT;
714 }
715
716 Offset = EHC_PORT_STAT_OFFSET + (4 * PortNumber);
717 State = EhcReadOpReg (Ehc, Offset);
718 State &= ~PORTSC_CHANGE_MASK;
719
720 switch (PortFeature) {
721 case EfiUsbPortEnable:
722 //
723 // Clear PORT_ENABLE feature means disable port.
724 //
725 State &= ~PORTSC_ENABLED;
726 EhcWriteOpReg (Ehc, Offset, State);
727 break;
728
729 case EfiUsbPortSuspend:
730 //
731 // A write of zero to this bit is ignored by the host
732 // controller. The host controller will unconditionally
733 // set this bit to a zero when:
734 // 1. software sets the Forct Port Resume bit to a zero from a one.
735 // 2. software sets the Port Reset bit to a one frome a zero.
736 //
737 State &= ~PORSTSC_RESUME;
738 EhcWriteOpReg (Ehc, Offset, State);
739 break;
740
741 case EfiUsbPortReset:
742 //
743 // Clear PORT_RESET means clear the reset signal.
744 //
745 State &= ~PORTSC_RESET;
746 EhcWriteOpReg (Ehc, Offset, State);
747 break;
748
749 case EfiUsbPortOwner:
750 //
751 // Clear port owner means this port owned by EHC
752 //
753 State &= ~PORTSC_OWNER;
754 EhcWriteOpReg (Ehc, Offset, State);
755 break;
756
757 case EfiUsbPortConnectChange:
758 //
759 // Clear connect status change
760 //
761 State |= PORTSC_CONN_CHANGE;
762 EhcWriteOpReg (Ehc, Offset, State);
763 break;
764
765 case EfiUsbPortEnableChange:
766 //
767 // Clear enable status change
768 //
769 State |= PORTSC_ENABLE_CHANGE;
770 EhcWriteOpReg (Ehc, Offset, State);
771 break;
772
773 case EfiUsbPortOverCurrentChange:
774 //
775 // Clear PortOverCurrent change
776 //
777 State |= PORTSC_OVERCUR_CHANGE;
778 EhcWriteOpReg (Ehc, Offset, State);
779 break;
780
781 case EfiUsbPortPower:
782 case EfiUsbPortSuspendChange:
783 case EfiUsbPortResetChange:
784 //
785 // Not supported or not related operation
786 //
787 break;
788
789 default:
790 Status = EFI_INVALID_PARAMETER;
791 break;
792 }
793
794 ON_EXIT:
795 return Status;
796 }
797
798 /**
799 Sets a feature for the specified root hub port.
800
801 @param PeiServices The pointer of EFI_PEI_SERVICES
802 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI
803 @param PortNumber Root hub port to set.
804 @param PortFeature Feature to set.
805
806 @retval EFI_SUCCESS The feature specified by PortFeature was set.
807 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
808 @retval EFI_TIMEOUT The time out occurred.
809
810 **/
811 EFI_STATUS
812 EFIAPI
813 EhcSetRootHubPortFeature (
814 IN EFI_PEI_SERVICES **PeiServices,
815 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
816 IN UINT8 PortNumber,
817 IN EFI_USB_PORT_FEATURE PortFeature
818 )
819 {
820 PEI_USB2_HC_DEV *Ehc;
821 UINT32 Offset;
822 UINT32 State;
823 UINT32 TotalPort;
824 EFI_STATUS Status;
825
826 Ehc = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);
827 Status = EFI_SUCCESS;
828
829 TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);
830
831 if (PortNumber >= TotalPort) {
832 Status = EFI_INVALID_PARAMETER;
833 goto ON_EXIT;
834 }
835
836 Offset = (UINT32) (EHC_PORT_STAT_OFFSET + (4 * PortNumber));
837 State = EhcReadOpReg (Ehc, Offset);
838
839 //
840 // Mask off the port status change bits, these bits are
841 // write clean bit
842 //
843 State &= ~PORTSC_CHANGE_MASK;
844
845 switch (PortFeature) {
846 case EfiUsbPortEnable:
847 //
848 // Sofeware can't set this bit, Port can only be enable by
849 // EHCI as a part of the reset and enable
850 //
851 State |= PORTSC_ENABLED;
852 EhcWriteOpReg (Ehc, Offset, State);
853 break;
854
855 case EfiUsbPortSuspend:
856 State |= PORTSC_SUSPEND;
857 EhcWriteOpReg (Ehc, Offset, State);
858 break;
859
860 case EfiUsbPortReset:
861 //
862 // Make sure Host Controller not halt before reset it
863 //
864 if (EhcIsHalt (Ehc)) {
865 Status = EhcRunHC (Ehc, EHC_GENERIC_TIMEOUT);
866
867 if (EFI_ERROR (Status)) {
868 break;
869 }
870 }
871
872 //
873 // Set one to PortReset bit must also set zero to PortEnable bit
874 //
875 State |= PORTSC_RESET;
876 State &= ~PORTSC_ENABLED;
877 EhcWriteOpReg (Ehc, Offset, State);
878 break;
879
880 case EfiUsbPortPower:
881 //
882 // Not supported, ignore the operation
883 //
884 Status = EFI_SUCCESS;
885 break;
886
887 case EfiUsbPortOwner:
888 State |= PORTSC_OWNER;
889 EhcWriteOpReg (Ehc, Offset, State);
890 break;
891
892 default:
893 Status = EFI_INVALID_PARAMETER;
894 }
895
896 ON_EXIT:
897 return Status;
898 }
899
900 /**
901 Retrieves the current status of a USB root hub port.
902
903 @param PeiServices The pointer of EFI_PEI_SERVICES.
904 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
905 @param PortNumber The root hub port to retrieve the state from.
906 @param PortStatus Variable to receive the port state.
907
908 @retval EFI_SUCCESS The status of the USB root hub port specified.
909 by PortNumber was returned in PortStatus.
910 @retval EFI_INVALID_PARAMETER PortNumber is invalid.
911
912 **/
913 EFI_STATUS
914 EFIAPI
915 EhcGetRootHubPortStatus (
916 IN EFI_PEI_SERVICES **PeiServices,
917 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
918 IN UINT8 PortNumber,
919 OUT EFI_USB_PORT_STATUS *PortStatus
920 )
921 {
922 PEI_USB2_HC_DEV *Ehc;
923 UINT32 Offset;
924 UINT32 State;
925 UINT32 TotalPort;
926 UINTN Index;
927 UINTN MapSize;
928 EFI_STATUS Status;
929
930 if (PortStatus == NULL) {
931 return EFI_INVALID_PARAMETER;
932 }
933
934 Ehc = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS(This);
935 Status = EFI_SUCCESS;
936
937 TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);
938
939 if (PortNumber >= TotalPort) {
940 Status = EFI_INVALID_PARAMETER;
941 goto ON_EXIT;
942 }
943
944 Offset = (UINT32) (EHC_PORT_STAT_OFFSET + (4 * PortNumber));
945 PortStatus->PortStatus = 0;
946 PortStatus->PortChangeStatus = 0;
947
948 State = EhcReadOpReg (Ehc, Offset);
949
950 //
951 // Identify device speed. If in K state, it is low speed.
952 // If the port is enabled after reset, the device is of
953 // high speed. The USB bus driver should retrieve the actual
954 // port speed after reset.
955 //
956 if (EHC_BIT_IS_SET (State, PORTSC_LINESTATE_K)) {
957 PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
958
959 } else if (EHC_BIT_IS_SET (State, PORTSC_ENABLED)) {
960 PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;
961 }
962
963 //
964 // Convert the EHCI port/port change state to UEFI status
965 //
966 MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);
967
968 for (Index = 0; Index < MapSize; Index++) {
969 if (EHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {
970 PortStatus->PortStatus = (UINT16) (PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);
971 }
972 }
973
974 MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
975
976 for (Index = 0; Index < MapSize; Index++) {
977 if (EHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {
978 PortStatus->PortChangeStatus = (UINT16) (PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);
979 }
980 }
981
982 ON_EXIT:
983 return Status;
984 }
985
986 /**
987 Submits control transfer to a target USB device.
988
989 @param PeiServices The pointer of EFI_PEI_SERVICES.
990 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
991 @param DeviceAddress The target device address.
992 @param DeviceSpeed Target device speed.
993 @param MaximumPacketLength Maximum packet size the default control transfer
994 endpoint is capable of sending or receiving.
995 @param Request USB device request to send.
996 @param TransferDirection Specifies the data direction for the data stage.
997 @param Data Data buffer to be transmitted or received from USB device.
998 @param DataLength The size (in bytes) of the data buffer.
999 @param TimeOut Indicates the maximum timeout, in millisecond.
1000 If Timeout is 0, then the caller must wait for the function
1001 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
1002 @param Translator Transaction translator to be used by this device.
1003 @param TransferResult Return the result of this control transfer.
1004
1005 @retval EFI_SUCCESS Transfer was completed successfully.
1006 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
1007 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
1008 @retval EFI_TIMEOUT Transfer failed due to timeout.
1009 @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
1010
1011 **/
1012 EFI_STATUS
1013 EFIAPI
1014 EhcControlTransfer (
1015 IN EFI_PEI_SERVICES **PeiServices,
1016 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
1017 IN UINT8 DeviceAddress,
1018 IN UINT8 DeviceSpeed,
1019 IN UINTN MaximumPacketLength,
1020 IN EFI_USB_DEVICE_REQUEST *Request,
1021 IN EFI_USB_DATA_DIRECTION TransferDirection,
1022 IN OUT VOID *Data,
1023 IN OUT UINTN *DataLength,
1024 IN UINTN TimeOut,
1025 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1026 OUT UINT32 *TransferResult
1027 )
1028 {
1029 PEI_USB2_HC_DEV *Ehc;
1030 PEI_URB *Urb;
1031 UINT8 Endpoint;
1032 EFI_STATUS Status;
1033
1034 //
1035 // Validate parameters
1036 //
1037 if ((Request == NULL) || (TransferResult == NULL)) {
1038 return EFI_INVALID_PARAMETER;
1039 }
1040
1041 if ((TransferDirection != EfiUsbDataIn) &&
1042 (TransferDirection != EfiUsbDataOut) &&
1043 (TransferDirection != EfiUsbNoData)) {
1044 return EFI_INVALID_PARAMETER;
1045 }
1046
1047 if ((TransferDirection == EfiUsbNoData) &&
1048 ((Data != NULL) || (*DataLength != 0))) {
1049 return EFI_INVALID_PARAMETER;
1050 }
1051
1052 if ((TransferDirection != EfiUsbNoData) &&
1053 ((Data == NULL) || (*DataLength == 0))) {
1054 return EFI_INVALID_PARAMETER;
1055 }
1056
1057 if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&
1058 (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) {
1059 return EFI_INVALID_PARAMETER;
1060 }
1061
1062
1063 if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||
1064 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
1065 ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512))) {
1066 return EFI_INVALID_PARAMETER;
1067 }
1068
1069 Ehc = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);
1070
1071 Status = EFI_DEVICE_ERROR;
1072 *TransferResult = EFI_USB_ERR_SYSTEM;
1073
1074 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
1075 EhcAckAllInterrupt (Ehc);
1076 goto ON_EXIT;
1077 }
1078
1079 EhcAckAllInterrupt (Ehc);
1080
1081 //
1082 // Create a new URB, insert it into the asynchronous
1083 // schedule list, then poll the execution status.
1084 //
1085 //
1086 // Encode the direction in address, although default control
1087 // endpoint is bidirectional. EhcCreateUrb expects this
1088 // combination of Ep addr and its direction.
1089 //
1090 Endpoint = (UINT8) (0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));
1091 Urb = EhcCreateUrb (
1092 Ehc,
1093 DeviceAddress,
1094 Endpoint,
1095 DeviceSpeed,
1096 0,
1097 MaximumPacketLength,
1098 Translator,
1099 EHC_CTRL_TRANSFER,
1100 Request,
1101 Data,
1102 *DataLength,
1103 NULL,
1104 NULL,
1105 1
1106 );
1107
1108 if (Urb == NULL) {
1109 Status = EFI_OUT_OF_RESOURCES;
1110 goto ON_EXIT;
1111 }
1112
1113 EhcLinkQhToAsync (Ehc, Urb->Qh);
1114 Status = EhcExecTransfer (Ehc, Urb, TimeOut);
1115 EhcUnlinkQhFromAsync (Ehc, Urb->Qh);
1116
1117 //
1118 // Get the status from URB. The result is updated in EhcCheckUrbResult
1119 // which is called by EhcExecTransfer
1120 //
1121 *TransferResult = Urb->Result;
1122 *DataLength = Urb->Completed;
1123
1124 if (*TransferResult == EFI_USB_NOERROR) {
1125 Status = EFI_SUCCESS;
1126 }
1127
1128 EhcAckAllInterrupt (Ehc);
1129 EhcFreeUrb (Ehc, Urb);
1130
1131 ON_EXIT:
1132 return Status;
1133 }
1134
1135 /**
1136 @param FileHandle Handle of the file being invoked.
1137 @param PeiServices Describes the list of possible PEI Services.
1138
1139 @retval EFI_SUCCESS PPI successfully installed.
1140
1141 **/
1142 EFI_STATUS
1143 EFIAPI
1144 EhcPeimEntry (
1145 IN EFI_PEI_FILE_HANDLE FileHandle,
1146 IN CONST EFI_PEI_SERVICES **PeiServices
1147 )
1148 {
1149 PEI_USB_CONTROLLER_PPI *ChipSetUsbControllerPpi;
1150 EFI_STATUS Status;
1151 UINT8 Index;
1152 UINTN ControllerType;
1153 UINTN BaseAddress;
1154 UINTN MemPages;
1155 PEI_USB2_HC_DEV *EhcDev;
1156 EFI_PHYSICAL_ADDRESS TempPtr;
1157
1158 //
1159 // Shadow this PEIM to run from memory
1160 //
1161 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
1162 return EFI_SUCCESS;
1163 }
1164
1165 Status = PeiServicesLocatePpi (
1166 &gPeiUsbControllerPpiGuid,
1167 0,
1168 NULL,
1169 (VOID **) &ChipSetUsbControllerPpi
1170 );
1171 if (EFI_ERROR (Status)) {
1172 return EFI_UNSUPPORTED;
1173 }
1174
1175 Index = 0;
1176 while (TRUE) {
1177 Status = ChipSetUsbControllerPpi->GetUsbController (
1178 (EFI_PEI_SERVICES **) PeiServices,
1179 ChipSetUsbControllerPpi,
1180 Index,
1181 &ControllerType,
1182 &BaseAddress
1183 );
1184 //
1185 // When status is error, meant no controller is found
1186 //
1187 if (EFI_ERROR (Status)) {
1188 break;
1189 }
1190
1191 //
1192 // This PEIM is for UHC type controller.
1193 //
1194 if (ControllerType != PEI_EHCI_CONTROLLER) {
1195 Index++;
1196 continue;
1197 }
1198
1199 MemPages = sizeof (PEI_USB2_HC_DEV) / PAGESIZE + 1;
1200 Status = PeiServicesAllocatePages (
1201 EfiBootServicesCode,
1202 MemPages,
1203 &TempPtr
1204 );
1205 if (EFI_ERROR (Status)) {
1206 return EFI_OUT_OF_RESOURCES;
1207 }
1208
1209 ZeroMem((VOID *)(UINTN)TempPtr, MemPages*PAGESIZE);
1210 EhcDev = (PEI_USB2_HC_DEV *) ((UINTN) TempPtr);
1211
1212 EhcDev->Signature = USB2_HC_DEV_SIGNATURE;
1213
1214 EhcDev->UsbHostControllerBaseAddress = (UINT32) BaseAddress;
1215
1216
1217 EhcDev->HcStructParams = EhcReadCapRegister (EhcDev, EHC_HCSPARAMS_OFFSET);
1218 EhcDev->HcCapParams = EhcReadCapRegister (EhcDev, EHC_HCCPARAMS_OFFSET);
1219 EhcDev->CapLen = EhcReadCapRegister (EhcDev, EHC_CAPLENGTH_OFFSET) & 0x0FF;
1220 //
1221 // Initialize Uhc's hardware
1222 //
1223 Status = InitializeUsbHC (EhcDev);
1224 if (EFI_ERROR (Status)) {
1225 return Status;
1226 }
1227
1228 EhcDev->Usb2HostControllerPpi.ControlTransfer = EhcControlTransfer;
1229 EhcDev->Usb2HostControllerPpi.BulkTransfer = EhcBulkTransfer;
1230 EhcDev->Usb2HostControllerPpi.GetRootHubPortNumber = EhcGetRootHubPortNumber;
1231 EhcDev->Usb2HostControllerPpi.GetRootHubPortStatus = EhcGetRootHubPortStatus;
1232 EhcDev->Usb2HostControllerPpi.SetRootHubPortFeature = EhcSetRootHubPortFeature;
1233 EhcDev->Usb2HostControllerPpi.ClearRootHubPortFeature = EhcClearRootHubPortFeature;
1234
1235 EhcDev->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
1236 EhcDev->PpiDescriptor.Guid = &gPeiUsb2HostControllerPpiGuid;
1237 EhcDev->PpiDescriptor.Ppi = &EhcDev->Usb2HostControllerPpi;
1238
1239 Status = PeiServicesInstallPpi (&EhcDev->PpiDescriptor);
1240 if (EFI_ERROR (Status)) {
1241 Index++;
1242 continue;
1243 }
1244
1245 Index++;
1246 }
1247
1248 return EFI_SUCCESS;
1249 }
1250
1251 /**
1252 @param EhcDev EHCI Device.
1253
1254 @retval EFI_SUCCESS EHCI successfully initialized.
1255 @retval EFI_ABORTED EHCI was failed to be initialized.
1256
1257 **/
1258 EFI_STATUS
1259 InitializeUsbHC (
1260 IN PEI_USB2_HC_DEV *EhcDev
1261 )
1262 {
1263 EFI_STATUS Status;
1264
1265
1266 EhcResetHC (EhcDev, EHC_RESET_TIMEOUT);
1267
1268 Status = EhcInitHC (EhcDev);
1269
1270 if (EFI_ERROR (Status)) {
1271 return EFI_ABORTED;
1272 }
1273
1274 return EFI_SUCCESS;
1275 }