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