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