]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/EhciDxe/EhciReg.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / EhciDxe / EhciReg.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }