]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/EhciDxe/EhciReg.c
59752d1bdc649ba213af3465d58bf73cc38a2349
[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
377
378
379 /**
380 Enable asynchrounous schedule.
381
382 @param Ehc The EHCI device.
383 @param Timeout Time to wait before abort.
384
385 @retval EFI_SUCCESS The EHCI asynchronous schedule is enabled.
386 @return Others Failed to enable the asynchronous scheudle.
387
388 **/
389 EFI_STATUS
390 EhcEnableAsyncSchd (
391 IN USB2_HC_DEV *Ehc,
392 IN UINT32 Timeout
393 )
394 {
395 EFI_STATUS Status;
396
397 EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_ASYNC);
398
399 Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_ASYNC_ENABLED, TRUE, Timeout);
400 return Status;
401 }
402
403
404
405
406
407
408
409 /**
410 Whether Ehc is halted.
411
412 @param Ehc The EHCI device.
413
414 @retval TRUE The controller is halted.
415 @retval FALSE It isn't halted.
416
417 **/
418 BOOLEAN
419 EhcIsHalt (
420 IN USB2_HC_DEV *Ehc
421 )
422 {
423 return EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT);
424 }
425
426
427 /**
428 Whether system error occurred.
429
430 @param Ehc The EHCI device.
431
432 @return TRUE System error happened.
433 @return FALSE No system error.
434
435 **/
436 BOOLEAN
437 EhcIsSysError (
438 IN USB2_HC_DEV *Ehc
439 )
440 {
441 return EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_SYS_ERROR);
442 }
443
444
445 /**
446 Reset the host controller.
447
448 @param Ehc The EHCI device.
449 @param Timeout Time to wait before abort (in millisecond, ms).
450
451 @retval EFI_SUCCESS The host controller is reset.
452 @return Others Failed to reset the host.
453
454 **/
455 EFI_STATUS
456 EhcResetHC (
457 IN USB2_HC_DEV *Ehc,
458 IN UINT32 Timeout
459 )
460 {
461 EFI_STATUS Status;
462
463 //
464 // Host can only be reset when it is halt. If not so, halt it
465 //
466 if (!EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) {
467 Status = EhcHaltHC (Ehc, Timeout);
468
469 if (EFI_ERROR (Status)) {
470 return Status;
471 }
472 }
473
474 EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RESET);
475 Status = EhcWaitOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RESET, FALSE, Timeout);
476 return Status;
477 }
478
479
480 /**
481 Halt the host controller.
482
483 @param Ehc The EHCI device.
484 @param Timeout Time to wait before abort.
485
486 @retval EFI_SUCCESS The EHCI is halt.
487 @retval EFI_TIMEOUT Failed to halt the controller before Timeout.
488
489 **/
490 EFI_STATUS
491 EhcHaltHC (
492 IN USB2_HC_DEV *Ehc,
493 IN UINT32 Timeout
494 )
495 {
496 EFI_STATUS Status;
497
498 EhcClearOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);
499 Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT, TRUE, Timeout);
500 return Status;
501 }
502
503
504 /**
505 Set the EHCI to run.
506
507 @param Ehc The EHCI device.
508 @param Timeout Time to wait before abort.
509
510 @retval EFI_SUCCESS The EHCI is running.
511 @return Others Failed to set the EHCI to run.
512
513 **/
514 EFI_STATUS
515 EhcRunHC (
516 IN USB2_HC_DEV *Ehc,
517 IN UINT32 Timeout
518 )
519 {
520 EFI_STATUS Status;
521
522 EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);
523 Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT, FALSE, Timeout);
524 return Status;
525 }
526
527
528 /**
529 Initialize the HC hardware.
530 EHCI spec lists the five things to do to initialize the hardware:
531 1. Program CTRLDSSEGMENT
532 2. Set USBINTR to enable interrupts
533 3. Set periodic list base
534 4. Set USBCMD, interrupt threshold, frame list size etc
535 5. Write 1 to CONFIGFLAG to route all ports to EHCI
536
537 @param Ehc The EHCI device.
538
539 @return EFI_SUCCESS The EHCI has come out of halt state.
540 @return EFI_TIMEOUT Time out happened.
541
542 **/
543 EFI_STATUS
544 EhcInitHC (
545 IN USB2_HC_DEV *Ehc
546 )
547 {
548 EFI_STATUS Status;
549 UINT32 Index;
550 UINT32 RegVal;
551
552 // This ASSERT crashes the BeagleBoard. There is some issue in the USB stack.
553 // This ASSERT needs to be removed so the BeagleBoard will boot. When we fix
554 // the USB stack we can put this ASSERT back in
555 // ASSERT (EhcIsHalt (Ehc));
556
557 //
558 // Allocate the periodic frame and associated memeory
559 // management facilities if not already done.
560 //
561 if (Ehc->PeriodFrame != NULL) {
562 EhcFreeSched (Ehc);
563 }
564
565 Status = EhcInitSched (Ehc);
566
567 if (EFI_ERROR (Status)) {
568 return Status;
569 }
570
571 //
572 // 1. Clear USBINTR to disable all the interrupt. UEFI works by polling
573 //
574 EhcWriteOpReg (Ehc, EHC_USBINTR_OFFSET, 0);
575
576 //
577 // 2. Start the Host Controller
578 //
579 EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);
580
581 //
582 // 3. Power up all ports if EHCI has Port Power Control (PPC) support
583 //
584 if (Ehc->HcStructParams & HCSP_PPC) {
585 for (Index = 0; Index < (UINT8) (Ehc->HcStructParams & HCSP_NPORTS); Index++) {
586 //
587 // Do not clear port status bits on initialization. Otherwise devices will
588 // not enumerate properly at startup.
589 //
590 RegVal = EhcReadOpReg(Ehc, (UINT32)(EHC_PORT_STAT_OFFSET + (4 * Index)));
591 RegVal &= ~PORTSC_CHANGE_MASK;
592 RegVal |= PORTSC_POWER;
593 EhcWriteOpReg (Ehc, (UINT32) (EHC_PORT_STAT_OFFSET + (4 * Index)), RegVal);
594 }
595 }
596
597 //
598 // Wait roothub port power stable
599 //
600 gBS->Stall (EHC_ROOT_PORT_RECOVERY_STALL);
601
602 //
603 // 4. Set all ports routing to EHC
604 //
605 EhcSetOpRegBit (Ehc, EHC_CONFIG_FLAG_OFFSET, CONFIGFLAG_ROUTE_EHC);
606
607 Status = EhcEnablePeriodSchd (Ehc, EHC_GENERIC_TIMEOUT);
608
609 if (EFI_ERROR (Status)) {
610 DEBUG ((EFI_D_ERROR, "EhcInitHC: failed to enable period schedule\n"));
611 return Status;
612 }
613
614 Status = EhcEnableAsyncSchd (Ehc, EHC_GENERIC_TIMEOUT);
615
616 if (EFI_ERROR (Status)) {
617 DEBUG ((EFI_D_ERROR, "EhcInitHC: failed to enable async schedule\n"));
618 return Status;
619 }
620
621 return EFI_SUCCESS;
622 }