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