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