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