]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/EhciDxe/EhciReg.c
MdeModulePkg: Refine casting expression result to bigger size
[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 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 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
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 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
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 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
588 EhcInitHC (
589 IN USB2_HC_DEV *Ehc
590 )
591 {
592 EFI_STATUS Status;
593 UINT32 Index;
594 UINT32 RegVal;
595
596 // This ASSERT crashes the BeagleBoard. There is some issue in the USB stack.
597 // This ASSERT needs to be removed so the BeagleBoard will boot. When we fix
598 // the USB stack we can put this ASSERT back in
599 // ASSERT (EhcIsHalt (Ehc));
600
601 //
602 // Allocate the periodic frame and associated memeory
603 // management facilities if not already done.
604 //
605 if (Ehc->PeriodFrame != NULL) {
606 EhcFreeSched (Ehc);
607 }
608
609 Status = EhcInitSched (Ehc);
610
611 if (EFI_ERROR (Status)) {
612 return Status;
613 }
614
615 //
616 // 1. Clear USBINTR to disable all the interrupt. UEFI works by polling
617 //
618 EhcWriteOpReg (Ehc, EHC_USBINTR_OFFSET, 0);
619
620 //
621 // 2. Start the Host Controller
622 //
623 EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);
624
625 //
626 // 3. Power up all ports if EHCI has Port Power Control (PPC) support
627 //
628 if (Ehc->HcStructParams & HCSP_PPC) {
629 for (Index = 0; Index < (UINT8) (Ehc->HcStructParams & HCSP_NPORTS); Index++) {
630 //
631 // Do not clear port status bits on initialization. Otherwise devices will
632 // not enumerate properly at startup.
633 //
634 RegVal = EhcReadOpReg(Ehc, (UINT32)(EHC_PORT_STAT_OFFSET + (4 * Index)));
635 RegVal &= ~PORTSC_CHANGE_MASK;
636 RegVal |= PORTSC_POWER;
637 EhcWriteOpReg (Ehc, (UINT32) (EHC_PORT_STAT_OFFSET + (4 * Index)), RegVal);
638 }
639 }
640
641 //
642 // Wait roothub port power stable
643 //
644 gBS->Stall (EHC_ROOT_PORT_RECOVERY_STALL);
645
646 //
647 // 4. Set all ports routing to EHC
648 //
649 EhcSetOpRegBit (Ehc, EHC_CONFIG_FLAG_OFFSET, CONFIGFLAG_ROUTE_EHC);
650
651 Status = EhcEnablePeriodSchd (Ehc, EHC_GENERIC_TIMEOUT);
652
653 if (EFI_ERROR (Status)) {
654 DEBUG ((EFI_D_ERROR, "EhcInitHC: failed to enable period schedule\n"));
655 return Status;
656 }
657
658 Status = EhcEnableAsyncSchd (Ehc, EHC_GENERIC_TIMEOUT);
659
660 if (EFI_ERROR (Status)) {
661 DEBUG ((EFI_D_ERROR, "EhcInitHC: failed to enable async schedule\n"));
662 return Status;
663 }
664
665 return EFI_SUCCESS;
666 }