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