1/** @file
2
3  The EHCI register operation routines.
4
5Copyright (c) 2007 - 2012, Intel Corporation. All rights reserved.<BR>
6This program and the accompanying materials
7are licensed and made available under the terms and conditions of the BSD License
8which accompanies this distribution.  The full text of the license may be found at
9http://opensource.org/licenses/bsd-license.php
10
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12WITHOUT 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**/
30UINT32
31EhcReadCapRegister (
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**/
66UINT32
67EhcReadDbgRegister (
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**/
103UINT32
104EhcReadOpReg (
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**/
140VOID
141EhcWriteOpReg (
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**/
174VOID
175EhcSetOpRegBit (
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**/
197VOID
198EhcClearOpRegBit (
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**/
226EFI_STATUS
227EhcWaitOpRegBit (
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**/
256VOID
257EhcClearLegacySupport (
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**/
306EFI_STATUS
307EhcSetAndWaitDoorBell (
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**/
340VOID
341EhcAckAllInterrupt (
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**/
360EFI_STATUS
361EhcEnablePeriodSchd (
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**/
385EFI_STATUS
386EhcDisablePeriodSchd (
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**/
411EFI_STATUS
412EhcEnableAsyncSchd (
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**/
437EFI_STATUS
438EhcDisableAsyncSchd (
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**/
462BOOLEAN
463EhcIsHalt (
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**/
480BOOLEAN
481EhcIsSysError (
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**/
499EFI_STATUS
500EhcResetHC (
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**/
534EFI_STATUS
535EhcHaltHC (
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**/
558EFI_STATUS
559EhcRunHC (
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**/
587EFI_STATUS
588EhcInitHC (
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