1 /** @file
2 
3   The EHCI register operation routines.
4 
5 Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 
8 **/
9 
10 
11 #include "Ehci.h"
12 
13 
14 /**
15   Read EHCI capability register.
16 
17   @param  Ehc          The EHCI device.
18   @param  Offset       Capability register address.
19 
20   @return The register content read.
21   @retval If err, return 0xffff.
22 
23 **/
24 UINT32
EhcReadCapRegister(IN USB2_HC_DEV * Ehc,IN UINT32 Offset)25 EhcReadCapRegister (
26   IN  USB2_HC_DEV         *Ehc,
27   IN  UINT32              Offset
28   )
29 {
30   UINT32                  Data;
31   EFI_STATUS              Status;
32 
33   Status = Ehc->PciIo->Mem.Read (
34                              Ehc->PciIo,
35                              EfiPciIoWidthUint32,
36                              EHC_BAR_INDEX,
37                              (UINT64) Offset,
38                              1,
39                              &Data
40                              );
41 
42   if (EFI_ERROR (Status)) {
43     DEBUG ((EFI_D_ERROR, "EhcReadCapRegister: Pci Io read error - %r at %d\n", Status, Offset));
44     Data = 0xFFFF;
45   }
46 
47   return Data;
48 }
49 
50 /**
51   Read EHCI debug port register.
52 
53   @param  Ehc          The EHCI device.
54   @param  Offset       Debug port register offset.
55 
56   @return The register content read.
57   @retval If err, return 0xffff.
58 
59 **/
60 UINT32
EhcReadDbgRegister(IN CONST USB2_HC_DEV * Ehc,IN UINT32 Offset)61 EhcReadDbgRegister (
62   IN  CONST USB2_HC_DEV   *Ehc,
63   IN  UINT32              Offset
64   )
65 {
66   UINT32                  Data;
67   EFI_STATUS              Status;
68 
69   Status = Ehc->PciIo->Mem.Read (
70                              Ehc->PciIo,
71                              EfiPciIoWidthUint32,
72                              Ehc->DebugPortBarNum,
73                              Ehc->DebugPortOffset + Offset,
74                              1,
75                              &Data
76                              );
77 
78   if (EFI_ERROR (Status)) {
79     DEBUG ((EFI_D_ERROR, "EhcReadDbgRegister: Pci Io read error - %r at %d\n", Status, Offset));
80     Data = 0xFFFF;
81   }
82 
83   return Data;
84 }
85 
86 
87 /**
88   Check whether the host controller has an in-use debug port.
89 
90   @param[in] Ehc         The Enhanced Host Controller to query.
91 
92   @param[in] PortNumber  If PortNumber is not NULL, then query whether
93                          PortNumber is an in-use debug port on Ehc. (PortNumber
94                          is taken in UEFI notation, i.e., zero-based.)
95                          Otherwise, query whether Ehc has any in-use debug
96                          port.
97 
98   @retval TRUE   PortNumber is an in-use debug port on Ehc (if PortNumber is
99                  not NULL), or some port on Ehc is an in-use debug port
100                  (otherwise).
101 
102   @retval FALSE  PortNumber is not an in-use debug port on Ehc (if PortNumber
103                  is not NULL), or no port on Ehc is an in-use debug port
104                  (otherwise).
105 **/
106 BOOLEAN
EhcIsDebugPortInUse(IN CONST USB2_HC_DEV * Ehc,IN CONST UINT8 * PortNumber OPTIONAL)107 EhcIsDebugPortInUse (
108   IN CONST USB2_HC_DEV *Ehc,
109   IN CONST UINT8       *PortNumber OPTIONAL
110   )
111 {
112   UINT32 State;
113 
114   if (Ehc->DebugPortNum == 0) {
115     //
116     // The host controller has no debug port.
117     //
118     return FALSE;
119   }
120 
121   //
122   // The Debug Port Number field in HCSPARAMS is one-based.
123   //
124   if (PortNumber != NULL && *PortNumber != Ehc->DebugPortNum - 1) {
125     //
126     // The caller specified a port, but it's not the debug port of the host
127     // controller.
128     //
129     return FALSE;
130   }
131 
132   //
133   // Deduce usage from the Control Register.
134   //
135   State = EhcReadDbgRegister(Ehc, 0);
136   return (State & USB_DEBUG_PORT_IN_USE_MASK) == USB_DEBUG_PORT_IN_USE_MASK;
137 }
138 
139 
140 /**
141   Read EHCI Operation register.
142 
143   @param  Ehc          The EHCI device.
144   @param  Offset       The operation register offset.
145 
146   @return The register content read.
147   @retval If err, return 0xffff.
148 
149 **/
150 UINT32
EhcReadOpReg(IN USB2_HC_DEV * Ehc,IN UINT32 Offset)151 EhcReadOpReg (
152   IN  USB2_HC_DEV         *Ehc,
153   IN  UINT32              Offset
154   )
155 {
156   UINT32                  Data;
157   EFI_STATUS              Status;
158 
159   ASSERT (Ehc->CapLen != 0);
160 
161   Status = Ehc->PciIo->Mem.Read (
162                              Ehc->PciIo,
163                              EfiPciIoWidthUint32,
164                              EHC_BAR_INDEX,
165                              Ehc->CapLen + Offset,
166                              1,
167                              &Data
168                              );
169 
170   if (EFI_ERROR (Status)) {
171     DEBUG ((EFI_D_ERROR, "EhcReadOpReg: Pci Io Read error - %r at %d\n", Status, Offset));
172     Data = 0xFFFF;
173   }
174 
175   return Data;
176 }
177 
178 
179 /**
180   Write  the data to the EHCI operation register.
181 
182   @param  Ehc          The EHCI device.
183   @param  Offset       EHCI operation register offset.
184   @param  Data         The data to write.
185 
186 **/
187 VOID
EhcWriteOpReg(IN USB2_HC_DEV * Ehc,IN UINT32 Offset,IN UINT32 Data)188 EhcWriteOpReg (
189   IN USB2_HC_DEV          *Ehc,
190   IN UINT32               Offset,
191   IN UINT32               Data
192   )
193 {
194   EFI_STATUS              Status;
195 
196   ASSERT (Ehc->CapLen != 0);
197 
198   Status = Ehc->PciIo->Mem.Write (
199                              Ehc->PciIo,
200                              EfiPciIoWidthUint32,
201                              EHC_BAR_INDEX,
202                              Ehc->CapLen + Offset,
203                              1,
204                              &Data
205                              );
206 
207   if (EFI_ERROR (Status)) {
208     DEBUG ((EFI_D_ERROR, "EhcWriteOpReg: Pci Io Write error: %r at %d\n", Status, Offset));
209   }
210 }
211 
212 
213 /**
214   Set one bit of the operational register while keeping other bits.
215 
216   @param  Ehc          The EHCI device.
217   @param  Offset       The offset of the operational register.
218   @param  Bit          The bit mask of the register to set.
219 
220 **/
221 VOID
EhcSetOpRegBit(IN USB2_HC_DEV * Ehc,IN UINT32 Offset,IN UINT32 Bit)222 EhcSetOpRegBit (
223   IN USB2_HC_DEV          *Ehc,
224   IN UINT32               Offset,
225   IN UINT32               Bit
226   )
227 {
228   UINT32                  Data;
229 
230   Data  = EhcReadOpReg (Ehc, Offset);
231   Data |= Bit;
232   EhcWriteOpReg (Ehc, Offset, Data);
233 }
234 
235 
236 /**
237   Clear one bit of the operational register while keeping other bits.
238 
239   @param  Ehc          The EHCI device.
240   @param  Offset       The offset of the operational register.
241   @param  Bit          The bit mask of the register to clear.
242 
243 **/
244 VOID
EhcClearOpRegBit(IN USB2_HC_DEV * Ehc,IN UINT32 Offset,IN UINT32 Bit)245 EhcClearOpRegBit (
246   IN USB2_HC_DEV          *Ehc,
247   IN UINT32               Offset,
248   IN UINT32               Bit
249   )
250 {
251   UINT32                  Data;
252 
253   Data  = EhcReadOpReg (Ehc, Offset);
254   Data &= ~Bit;
255   EhcWriteOpReg (Ehc, Offset, Data);
256 }
257 
258 
259 /**
260   Wait the operation register's bit as specified by Bit
261   to become set (or clear).
262 
263   @param  Ehc          The EHCI device.
264   @param  Offset       The offset of the operation register.
265   @param  Bit          The bit of the register to wait for.
266   @param  WaitToSet    Wait the bit to set or clear.
267   @param  Timeout      The time to wait before abort (in millisecond).
268 
269   @retval EFI_SUCCESS  The bit successfully changed by host controller.
270   @retval EFI_TIMEOUT  The time out occurred.
271 
272 **/
273 EFI_STATUS
EhcWaitOpRegBit(IN USB2_HC_DEV * Ehc,IN UINT32 Offset,IN UINT32 Bit,IN BOOLEAN WaitToSet,IN UINT32 Timeout)274 EhcWaitOpRegBit (
275   IN USB2_HC_DEV          *Ehc,
276   IN UINT32               Offset,
277   IN UINT32               Bit,
278   IN BOOLEAN              WaitToSet,
279   IN UINT32               Timeout
280   )
281 {
282   UINT32                  Index;
283 
284   for (Index = 0; Index < Timeout / EHC_SYNC_POLL_INTERVAL + 1; Index++) {
285     if (EHC_REG_BIT_IS_SET (Ehc, Offset, Bit) == WaitToSet) {
286       return EFI_SUCCESS;
287     }
288 
289     gBS->Stall (EHC_SYNC_POLL_INTERVAL);
290   }
291 
292   return EFI_TIMEOUT;
293 }
294 
295 
296 /**
297   Add support for UEFI Over Legacy (UoL) feature, stop
298   the legacy USB SMI support.
299 
300   @param  Ehc          The EHCI device.
301 
302 **/
303 VOID
EhcClearLegacySupport(IN USB2_HC_DEV * Ehc)304 EhcClearLegacySupport (
305   IN USB2_HC_DEV          *Ehc
306   )
307 {
308   UINT32                    ExtendCap;
309   EFI_PCI_IO_PROTOCOL       *PciIo;
310   UINT32                    Value;
311   UINT32                    TimeOut;
312 
313   DEBUG ((EFI_D_INFO, "EhcClearLegacySupport: called to clear legacy support\n"));
314 
315   PciIo     = Ehc->PciIo;
316   ExtendCap = (Ehc->HcCapParams >> 8) & 0xFF;
317 
318   PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value);
319   PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap + 0x4, 1, &Value);
320 
321   PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value);
322   Value |= (0x1 << 24);
323   PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value);
324 
325   TimeOut = 40;
326   while (TimeOut-- != 0) {
327     gBS->Stall (500);
328 
329     PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value);
330 
331     if ((Value & 0x01010000) == 0x01000000) {
332       break;
333     }
334   }
335 
336   PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value);
337   PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap + 0x4, 1, &Value);
338 }
339 
340 
341 
342 /**
343   Set door bell and wait it to be ACKed by host controller.
344   This function is used to synchronize with the hardware.
345 
346   @param  Ehc          The EHCI device.
347   @param  Timeout      The time to wait before abort (in millisecond, ms).
348 
349   @retval EFI_SUCCESS  Synchronized with the hardware.
350   @retval EFI_TIMEOUT  Time out happened while waiting door bell to set.
351 
352 **/
353 EFI_STATUS
EhcSetAndWaitDoorBell(IN USB2_HC_DEV * Ehc,IN UINT32 Timeout)354 EhcSetAndWaitDoorBell (
355   IN  USB2_HC_DEV         *Ehc,
356   IN  UINT32              Timeout
357   )
358 {
359   EFI_STATUS              Status;
360   UINT32                  Data;
361 
362   EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_IAAD);
363 
364   Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_IAA, TRUE, Timeout);
365 
366   //
367   // ACK the IAA bit in USBSTS register. Make sure other
368   // interrupt bits are not ACKed. These bits are WC (Write Clean).
369   //
370   Data  = EhcReadOpReg (Ehc, EHC_USBSTS_OFFSET);
371   Data &= ~USBSTS_INTACK_MASK;
372   Data |= USBSTS_IAA;
373 
374   EhcWriteOpReg (Ehc, EHC_USBSTS_OFFSET, Data);
375 
376   return Status;
377 }
378 
379 
380 /**
381   Clear all the interrutp status bits, these bits
382   are Write-Clean.
383 
384   @param  Ehc          The EHCI device.
385 
386 **/
387 VOID
EhcAckAllInterrupt(IN USB2_HC_DEV * Ehc)388 EhcAckAllInterrupt (
389   IN  USB2_HC_DEV         *Ehc
390   )
391 {
392   EhcWriteOpReg (Ehc, EHC_USBSTS_OFFSET, USBSTS_INTACK_MASK);
393 }
394 
395 
396 /**
397   Enable the periodic schedule then wait EHC to
398   actually enable it.
399 
400   @param  Ehc          The EHCI device.
401   @param  Timeout      The time to wait before abort (in millisecond, ms).
402 
403   @retval EFI_SUCCESS  The periodical schedule is enabled.
404   @retval EFI_TIMEOUT  Time out happened while enabling periodic schedule.
405 
406 **/
407 EFI_STATUS
EhcEnablePeriodSchd(IN USB2_HC_DEV * Ehc,IN UINT32 Timeout)408 EhcEnablePeriodSchd (
409   IN USB2_HC_DEV          *Ehc,
410   IN UINT32               Timeout
411   )
412 {
413   EFI_STATUS              Status;
414 
415   EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_PERIOD);
416 
417   Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_PERIOD_ENABLED, TRUE, Timeout);
418   return Status;
419 }
420 
421 
422 
423 
424 
425 
426 /**
427   Enable asynchrounous schedule.
428 
429   @param  Ehc          The EHCI device.
430   @param  Timeout      Time to wait before abort.
431 
432   @retval EFI_SUCCESS  The EHCI asynchronous schedule is enabled.
433   @return Others       Failed to enable the asynchronous scheudle.
434 
435 **/
436 EFI_STATUS
EhcEnableAsyncSchd(IN USB2_HC_DEV * Ehc,IN UINT32 Timeout)437 EhcEnableAsyncSchd (
438   IN USB2_HC_DEV          *Ehc,
439   IN UINT32               Timeout
440   )
441 {
442   EFI_STATUS              Status;
443 
444   EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_ASYNC);
445 
446   Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_ASYNC_ENABLED, TRUE, Timeout);
447   return Status;
448 }
449 
450 
451 
452 
453 
454 
455 
456 /**
457   Whether Ehc is halted.
458 
459   @param  Ehc          The EHCI device.
460 
461   @retval TRUE         The controller is halted.
462   @retval FALSE        It isn't halted.
463 
464 **/
465 BOOLEAN
EhcIsHalt(IN USB2_HC_DEV * Ehc)466 EhcIsHalt (
467   IN USB2_HC_DEV          *Ehc
468   )
469 {
470   return EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT);
471 }
472 
473 
474 /**
475   Whether system error occurred.
476 
477   @param  Ehc          The EHCI device.
478 
479   @return TRUE         System error happened.
480   @return FALSE        No system error.
481 
482 **/
483 BOOLEAN
EhcIsSysError(IN USB2_HC_DEV * Ehc)484 EhcIsSysError (
485   IN USB2_HC_DEV          *Ehc
486   )
487 {
488   return EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_SYS_ERROR);
489 }
490 
491 
492 /**
493   Reset the host controller.
494 
495   @param  Ehc          The EHCI device.
496   @param  Timeout      Time to wait before abort (in millisecond, ms).
497 
498   @retval EFI_SUCCESS  The host controller is reset.
499   @return Others       Failed to reset the host.
500 
501 **/
502 EFI_STATUS
EhcResetHC(IN USB2_HC_DEV * Ehc,IN UINT32 Timeout)503 EhcResetHC (
504   IN USB2_HC_DEV          *Ehc,
505   IN UINT32               Timeout
506   )
507 {
508   EFI_STATUS              Status;
509 
510   //
511   // Host can only be reset when it is halt. If not so, halt it
512   //
513   if (!EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) {
514     Status = EhcHaltHC (Ehc, Timeout);
515 
516     if (EFI_ERROR (Status)) {
517       return Status;
518     }
519   }
520 
521   EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RESET);
522   Status = EhcWaitOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RESET, FALSE, Timeout);
523   return Status;
524 }
525 
526 
527 /**
528   Halt the host controller.
529 
530   @param  Ehc          The EHCI device.
531   @param  Timeout      Time to wait before abort.
532 
533   @retval EFI_SUCCESS  The EHCI is halt.
534   @retval EFI_TIMEOUT  Failed to halt the controller before Timeout.
535 
536 **/
537 EFI_STATUS
EhcHaltHC(IN USB2_HC_DEV * Ehc,IN UINT32 Timeout)538 EhcHaltHC (
539   IN USB2_HC_DEV         *Ehc,
540   IN UINT32              Timeout
541   )
542 {
543   EFI_STATUS              Status;
544 
545   EhcClearOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);
546   Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT, TRUE, Timeout);
547   return Status;
548 }
549 
550 
551 /**
552   Set the EHCI to run.
553 
554   @param  Ehc          The EHCI device.
555   @param  Timeout      Time to wait before abort.
556 
557   @retval EFI_SUCCESS  The EHCI is running.
558   @return Others       Failed to set the EHCI to run.
559 
560 **/
561 EFI_STATUS
EhcRunHC(IN USB2_HC_DEV * Ehc,IN UINT32 Timeout)562 EhcRunHC (
563   IN USB2_HC_DEV          *Ehc,
564   IN UINT32               Timeout
565   )
566 {
567   EFI_STATUS              Status;
568 
569   EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);
570   Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT, FALSE, Timeout);
571   return Status;
572 }
573 
574 
575 /**
576   Initialize the HC hardware.
577   EHCI spec lists the five things to do to initialize the hardware:
578   1. Program CTRLDSSEGMENT
579   2. Set USBINTR to enable interrupts
580   3. Set periodic list base
581   4. Set USBCMD, interrupt threshold, frame list size etc
582   5. Write 1 to CONFIGFLAG to route all ports to EHCI
583 
584   @param  Ehc          The EHCI device.
585 
586   @return EFI_SUCCESS  The EHCI has come out of halt state.
587   @return EFI_TIMEOUT  Time out happened.
588 
589 **/
590 EFI_STATUS
EhcInitHC(IN USB2_HC_DEV * Ehc)591 EhcInitHC (
592   IN USB2_HC_DEV          *Ehc
593   )
594 {
595   EFI_STATUS              Status;
596   UINT32                  Index;
597   UINT32                  RegVal;
598 
599   // This ASSERT crashes the BeagleBoard. There is some issue in the USB stack.
600   // This ASSERT needs to be removed so the BeagleBoard will boot. When we fix
601   // the USB stack we can put this ASSERT back in
602   // ASSERT (EhcIsHalt (Ehc));
603 
604   //
605   // Allocate the periodic frame and associated memeory
606   // management facilities if not already done.
607   //
608   if (Ehc->PeriodFrame != NULL) {
609     EhcFreeSched (Ehc);
610   }
611 
612   Status = EhcInitSched (Ehc);
613 
614   if (EFI_ERROR (Status)) {
615     return Status;
616   }
617 
618   //
619   // 1. Clear USBINTR to disable all the interrupt. UEFI works by polling
620   //
621   EhcWriteOpReg (Ehc, EHC_USBINTR_OFFSET, 0);
622 
623   //
624   // 2. Start the Host Controller
625   //
626   EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);
627 
628   //
629   // 3. Power up all ports if EHCI has Port Power Control (PPC) support
630   //
631   if (Ehc->HcStructParams & HCSP_PPC) {
632     for (Index = 0; Index < (UINT8) (Ehc->HcStructParams & HCSP_NPORTS); Index++) {
633       //
634       // Do not clear port status bits on initialization.  Otherwise devices will
635       // not enumerate properly at startup.
636       //
637       RegVal  = EhcReadOpReg(Ehc, (UINT32)(EHC_PORT_STAT_OFFSET + (4 * Index)));
638       RegVal &= ~PORTSC_CHANGE_MASK;
639       RegVal |= PORTSC_POWER;
640       EhcWriteOpReg (Ehc, (UINT32) (EHC_PORT_STAT_OFFSET + (4 * Index)), RegVal);
641     }
642   }
643 
644   //
645   // Wait roothub port power stable
646   //
647   gBS->Stall (EHC_ROOT_PORT_RECOVERY_STALL);
648 
649   //
650   // 4. Set all ports routing to EHC
651   //
652   EhcSetOpRegBit (Ehc, EHC_CONFIG_FLAG_OFFSET, CONFIGFLAG_ROUTE_EHC);
653 
654   Status = EhcEnablePeriodSchd (Ehc, EHC_GENERIC_TIMEOUT);
655 
656   if (EFI_ERROR (Status)) {
657     DEBUG ((EFI_D_ERROR, "EhcInitHC: failed to enable period schedule\n"));
658     return Status;
659   }
660 
661   Status = EhcEnableAsyncSchd (Ehc, EHC_GENERIC_TIMEOUT);
662 
663   if (EFI_ERROR (Status)) {
664     DEBUG ((EFI_D_ERROR, "EhcInitHC: failed to enable async schedule\n"));
665     return Status;
666   }
667 
668   return EFI_SUCCESS;
669 }
670