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