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