]> git.proxmox.com Git - mirror_edk2.git/blame - SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Common.c
MdeModulePkg: add error handling when DXE IPL PPI is not found.
[mirror_edk2.git] / SourceLevelDebugPkg / Library / DebugCommunicationLibUsb3 / DebugCommunicationLibUsb3Common.c
CommitLineData
2cb6eabe
EL
1/** @file\r
2 Debug Port Library implementation based on usb3 debug port.\r
3\r
5d6507a1 4 Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>\r
2cb6eabe
EL
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php.\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "DebugCommunicationLibUsb3Internal.h"\r
16\r
17//\r
18// The global variable which can be used after memory is ready.\r
19//\r
20USB3_DEBUG_PORT_HANDLE mDebugCommunicationLibUsb3DebugPortHandle;\r
21\r
22UINT16 mString0Desc[] = {\r
23 // String Descriptor Type + Length\r
24 ( USB_DESC_TYPE_STRING << 8 ) + STRING0_DESC_LEN,\r
25 0x0409\r
26};\r
27\r
28UINT16 mManufacturerStrDesc[] = {\r
29 // String Descriptor Type + Length\r
30 ( USB_DESC_TYPE_STRING << 8 ) + MANU_DESC_LEN,\r
31 'I', 'n', 't', 'e', 'l'\r
32};\r
33\r
34UINT16 mProductStrDesc[] = {\r
35 // String Descriptor Type + Length\r
36 ( USB_DESC_TYPE_STRING << 8 ) + PRODUCT_DESC_LEN,\r
37 'U', 'S', 'B', ' ', '3', '.', '0', ' ', 'D', 'e', 'b', 'u', 'g', ' ', 'C', 'a', 'b', 'l', 'e'\r
38};\r
39\r
40UINT16 mSerialNumberStrDesc[] = {\r
41 // String Descriptor Type + Length\r
42 ( USB_DESC_TYPE_STRING << 8 ) + SERIAL_DESC_LEN,\r
43 '1'\r
44};\r
45\r
46/**\r
47 Sets bits as per the enabled bit positions in the mask.\r
48\r
49 @param[in, out] Register UINTN register\r
50 @param[in] BitMask 32-bit mask\r
51**/\r
52VOID\r
53XhcSetR32Bit(\r
54 IN OUT UINTN Register, \r
55 IN UINT32 BitMask\r
56 )\r
57{\r
58 UINT32 RegisterValue;\r
59\r
60 RegisterValue = MmioRead32 (Register);\r
61 RegisterValue |= (UINT32)(BitMask);\r
62 MmioWrite32 (Register, RegisterValue);\r
63}\r
64\r
65/**\r
66 Clears bits as per the enabled bit positions in the mask.\r
67\r
68 @param[in, out] Register UINTN register\r
69 @param[in] BitMask 32-bit mask\r
70**/\r
71VOID\r
72XhcClearR32Bit(\r
73 IN OUT UINTN Register, \r
74 IN UINT32 BitMask\r
75 )\r
76{\r
77 UINT32 RegisterValue;\r
78\r
79 RegisterValue = MmioRead32 (Register);\r
80 RegisterValue &= ~BitMask;\r
81 MmioWrite32 (Register, RegisterValue);\r
82}\r
83\r
84/**\r
85 Write the data to the XHCI debug register.\r
86\r
87 @param Handle Debug port handle.\r
88 @param Offset The offset of the runtime register.\r
89 @param Data The data to write.\r
90\r
91**/\r
92VOID\r
93XhcWriteDebugReg (\r
94 IN USB3_DEBUG_PORT_HANDLE *Handle,\r
95 IN UINT32 Offset,\r
96 IN UINT32 Data\r
97 )\r
98{\r
99 EFI_PHYSICAL_ADDRESS DebugCapabilityBase;\r
100 \r
101 DebugCapabilityBase = Handle->DebugCapabilityBase;\r
102 MmioWrite32 ((UINTN)(DebugCapabilityBase + Offset), Data);\r
103 \r
104 return;\r
105}\r
106\r
107/**\r
108 Read XHCI debug register.\r
109\r
110 @param Handle Debug port handle.\r
111 @param Offset The offset of the runtime register.\r
112\r
113 @return The register content read\r
114\r
115**/\r
116UINT32\r
117XhcReadDebugReg (\r
118 IN USB3_DEBUG_PORT_HANDLE *Handle,\r
119 IN UINT32 Offset\r
120 )\r
121{\r
122 UINT32 Data;\r
123 EFI_PHYSICAL_ADDRESS DebugCapabilityBase;\r
124 \r
125 DebugCapabilityBase = Handle->DebugCapabilityBase;\r
126 Data = MmioRead32 ((UINTN)(DebugCapabilityBase + Offset));\r
127\r
128 return Data;\r
129}\r
130\r
131/**\r
132 Set one bit of the runtime register while keeping other bits.\r
133\r
134 @param Handle Debug port handle.\r
135 @param Offset The offset of the runtime register.\r
136 @param Bit The bit mask of the register to set.\r
137\r
138**/\r
139VOID\r
140XhcSetDebugRegBit (\r
141 IN USB3_DEBUG_PORT_HANDLE *Handle,\r
142 IN UINT32 Offset,\r
143 IN UINT32 Bit\r
144 )\r
145{\r
146 UINT32 Data;\r
147\r
148 Data = XhcReadDebugReg (Handle, Offset);\r
149 Data |= Bit;\r
150 XhcWriteDebugReg (Handle, Offset, Data);\r
151}\r
152\r
153/**\r
154 Program and eanble XHCI MMIO base address.\r
155\r
156 @return XHCI MMIO base address.\r
157\r
158**/\r
159EFI_PHYSICAL_ADDRESS\r
160ProgramXhciBaseAddress (\r
161 VOID\r
162 )\r
163{\r
164 UINT16 PciCmd;\r
165 UINT32 Low;\r
166 UINT32 High;\r
167 EFI_PHYSICAL_ADDRESS XhciMmioBase;\r
168 \r
169 Low = PciRead32 (PcdGet32(PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET);\r
170 High = PciRead32 (PcdGet32(PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + 4);\r
171 XhciMmioBase = (EFI_PHYSICAL_ADDRESS) (LShiftU64 ((UINT64) High, 32) | Low);\r
172 XhciMmioBase &= XHCI_BASE_ADDRESS_64_BIT_MASK;\r
173\r
174 if ((XhciMmioBase == 0) || (XhciMmioBase == XHCI_BASE_ADDRESS_64_BIT_MASK)) {\r
175 XhciMmioBase = PcdGet64(PcdUsbXhciMemorySpaceBase);\r
176 PciWrite32(PcdGet32(PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET, XhciMmioBase & 0xFFFFFFFF);\r
177 PciWrite32(PcdGet32(PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + 4, (RShiftU64 (XhciMmioBase, 32) & 0xFFFFFFFF));\r
178 }\r
179\r
180 PciCmd = PciRead16 (PcdGet32(PcdUsbXhciPciAddress) + PCI_COMMAND_OFFSET);\r
181 if (((PciCmd & EFI_PCI_COMMAND_MEMORY_SPACE) == 0) || ((PciCmd & EFI_PCI_COMMAND_BUS_MASTER) == 0)) {\r
182 PciCmd |= EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER;\r
183 PciWrite16(PcdGet32(PcdUsbXhciPciAddress) + PCI_COMMAND_OFFSET, PciCmd);\r
184 }\r
185\r
186 return XhciMmioBase;\r
187}\r
188\r
189/**\r
190 Check if the timer is timeout.\r
191 \r
192 @param[in] UsbDebugPortHandle Pointer to USB Debug port handle\r
193 @param[in] Timer The start timer from the begin.\r
194 @param[in] TimeoutTicker Ticker number need time out.\r
195\r
196 @return TRUE Timer time out occurs.\r
197 @retval FALSE Timer does not time out.\r
198\r
199**/\r
200BOOLEAN\r
201IsTimerTimeout (\r
202 IN USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle,\r
203 IN UINT64 Timer,\r
204 IN UINT64 TimeoutTicker\r
205 )\r
206{\r
207 UINT64 CurrentTimer;\r
208 UINT64 Delta;\r
209\r
210 CurrentTimer = GetPerformanceCounter ();\r
211\r
212 if (UsbDebugPortHandle->TimerCountDown) {\r
213 //\r
214 // The timer counter counts down. Check for roll over condition.\r
215 //\r
216 if (CurrentTimer < Timer) {\r
217 Delta = Timer - CurrentTimer;\r
218 } else {\r
219 //\r
220 // Handle one roll-over. \r
221 //\r
222 Delta = UsbDebugPortHandle->TimerCycle - (CurrentTimer - Timer);\r
223 }\r
224 } else {\r
225 //\r
226 // The timer counter counts up. Check for roll over condition.\r
227 //\r
228 if (CurrentTimer > Timer) {\r
229 Delta = CurrentTimer - Timer;\r
230 } else {\r
231 //\r
232 // Handle one roll-over. \r
233 //\r
234 Delta = UsbDebugPortHandle->TimerCycle - (Timer - CurrentTimer);\r
235 }\r
236 }\r
237 \r
238 return (BOOLEAN) (Delta >= TimeoutTicker);\r
239}\r
240\r
241/**\r
242 Update XHC MMIO base address when MMIO base address is changed.\r
243\r
244 @param Handle Debug port handle.\r
245 @param XhciMmioBase XHCI MMIO base address.\r
246\r
247**/\r
248VOID\r
249UpdateXhcResource (\r
250 IN OUT USB3_DEBUG_PORT_HANDLE *Handle,\r
251 IN EFI_PHYSICAL_ADDRESS XhciMmioBase\r
252 )\r
253{\r
254 if ((Handle == NULL) || (Handle->XhciMmioBase == XhciMmioBase)) {\r
255 return;\r
256 }\r
257\r
258 //\r
259 // Need fix Handle data according to new XHCI MMIO base address.\r
260 //\r
261 Handle->XhciMmioBase = XhciMmioBase;\r
262 Handle->DebugCapabilityBase = XhciMmioBase + Handle->DebugCapabilityOffset;\r
263 Handle->XhciOpRegister = XhciMmioBase + MmioRead8 ((UINTN)XhciMmioBase);\r
264}\r
265\r
266/**\r
267 Calculate the usb debug port bar address.\r
268\r
269 @param Handle Debug port handle.\r
270\r
271 @retval RETURN_UNSUPPORTED The usb host controller does not supported usb debug port capability.\r
272 @retval RETURN_SUCCESS Get bar and offset successfully.\r
273\r
274**/\r
275RETURN_STATUS\r
276EFIAPI\r
277CalculateUsbDebugPortMmioBase (\r
278 USB3_DEBUG_PORT_HANDLE *Handle\r
279 )\r
280{\r
281 UINT16 VendorId;\r
282 UINT16 DeviceId;\r
283 UINT8 ProgInterface;\r
284 UINT8 SubClassCode;\r
285 UINT8 BaseCode;\r
286 BOOLEAN Flag;\r
287 UINT32 Capability;\r
288 EFI_PHYSICAL_ADDRESS CapabilityPointer;\r
289 UINT8 CapLength;\r
290\r
291 VendorId = PciRead16 (PcdGet32(PcdUsbXhciPciAddress) + PCI_VENDOR_ID_OFFSET);\r
292 DeviceId = PciRead16 (PcdGet32(PcdUsbXhciPciAddress) + PCI_DEVICE_ID_OFFSET);\r
293 \r
294 if ((VendorId == 0xFFFF) || (DeviceId == 0xFFFF)) {\r
295 goto Done;\r
296 }\r
297\r
298 ProgInterface = PciRead8 (PcdGet32(PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET);\r
299 SubClassCode = PciRead8 (PcdGet32(PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET + 1);\r
300 BaseCode = PciRead8 (PcdGet32(PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET + 2);\r
301 \r
302 if ((ProgInterface != PCI_IF_XHCI) || (SubClassCode != PCI_CLASS_SERIAL_USB) || (BaseCode != PCI_CLASS_SERIAL)) {\r
303 goto Done;\r
304 }\r
305\r
306 CapLength = MmioRead8 ((UINTN) Handle->XhciMmioBase);\r
307\r
308 //\r
309 // Get capability pointer from HCCPARAMS at offset 0x10\r
310 //\r
311 CapabilityPointer = Handle->XhciMmioBase + (MmioRead32 ((UINTN)(Handle->XhciMmioBase + XHC_HCCPARAMS_OFFSET)) >> 16) * 4;\r
312 \r
313 //\r
314 // Search XHCI debug capability\r
315 //\r
316 Flag = FALSE;\r
317 Capability = MmioRead32 ((UINTN)CapabilityPointer);\r
318 while (TRUE) {\r
319 if ((Capability & XHC_CAPABILITY_ID_MASK) == PCI_CAPABILITY_ID_DEBUG_PORT) {\r
320 Flag = TRUE;\r
321 break;\r
322 }\r
323 if ((((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) & XHC_CAPABILITY_ID_MASK) == 0) {\r
324 //\r
325 // Reach the end of capability list, quit\r
326 //\r
327 break;\r
328 }\r
329 CapabilityPointer += ((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) * 4;\r
330 Capability = MmioRead32 ((UINTN)CapabilityPointer);\r
331 }\r
332\r
333 if (!Flag) {\r
334 goto Done;\r
335 }\r
336\r
337 //\r
338 // USB3 debug capability is supported.\r
339 //\r
340 Handle->DebugCapabilityBase = CapabilityPointer;\r
341 Handle->DebugCapabilityOffset = CapabilityPointer - Handle->XhciMmioBase;\r
342 Handle->XhciOpRegister = Handle->XhciMmioBase + CapLength;\r
343 Handle->Initialized = USB3DBG_DBG_CAB;\r
344 return RETURN_SUCCESS;\r
345\r
346Done:\r
347 Handle->Initialized = USB3DBG_NO_DBG_CAB;\r
348 return RETURN_UNSUPPORTED;\r
349}\r
350\r
351/**\r
352 Check if it needs to re-initialize usb debug port hardware.\r
353\r
354 During different phases switch, such as SEC to PEI or PEI to DXE or DXE to SMM, we should check\r
355 whether the usb debug port hardware configuration is changed. Such case can be triggerred by\r
356 Pci bus resource allocation and so on.\r
357\r
358 @param Handle Debug port handle.\r
359\r
360 @retval TRUE The usb debug port hardware configuration is changed.\r
361 @retval FALSE The usb debug port hardware configuration is not changed.\r
362\r
363**/\r
364BOOLEAN\r
365EFIAPI\r
366NeedReinitializeHardware(\r
367 IN USB3_DEBUG_PORT_HANDLE *Handle\r
368 )\r
369{\r
370 BOOLEAN Result;\r
371 volatile UINT32 Dcctrl;\r
372\r
373 Result = FALSE;\r
374\r
375 //\r
376 // If DCE bit, it means USB3 debug is not enabled.\r
377 //\r
378 Dcctrl = XhcReadDebugReg (Handle, XHC_DC_DCCTRL);\r
379 if ((Dcctrl & BIT0) == 0) {\r
380 Result = TRUE;\r
381 }\r
382\r
383 return Result;\r
384}\r
385\r
386/**\r
387 Create XHCI event ring.\r
388\r
389 @param Handle Debug port handle.\r
390 @param EventRing The created event ring.\r
391\r
392**/\r
393EFI_STATUS\r
394CreateEventRing (\r
395 IN USB3_DEBUG_PORT_HANDLE *Handle,\r
396 OUT EVENT_RING *EventRing\r
397 )\r
398{\r
399 VOID *Buf;\r
400 EVENT_RING_SEG_TABLE_ENTRY *ERSTBase;\r
401\r
402 ASSERT (EventRing != NULL);\r
403 \r
404 //\r
405 // Allocate Event Ring\r
406 //\r
407 Buf = AllocateAlignBuffer (sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);\r
408 ASSERT (Buf != NULL);\r
409 ASSERT (((UINTN) Buf & 0x3F) == 0);\r
410 ZeroMem (Buf, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);\r
411\r
412 EventRing->EventRingSeg0 = (EFI_PHYSICAL_ADDRESS)(UINTN) Buf;\r
413 EventRing->TrbNumber = EVENT_RING_TRB_NUMBER;\r
414 EventRing->EventRingDequeue = (EFI_PHYSICAL_ADDRESS)(UINTN) EventRing->EventRingSeg0;\r
415 EventRing->EventRingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN) EventRing->EventRingSeg0;\r
416 \r
417 //\r
418 // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'\r
419 // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.\r
420 //\r
421 EventRing->EventRingCCS = 1;\r
422\r
423 //\r
424 // Allocate Event Ring Segment Table Entry 0 in Event Ring Segment Table\r
425 //\r
426 Buf = AllocateAlignBuffer (sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);\r
427 ASSERT (Buf != NULL);\r
428 ASSERT (((UINTN) Buf & 0x3F) == 0);\r
429 ZeroMem (Buf, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);\r
430\r
431 ERSTBase = (EVENT_RING_SEG_TABLE_ENTRY *) Buf;\r
432 EventRing->ERSTBase = (EFI_PHYSICAL_ADDRESS)(UINTN) ERSTBase;\r
433\r
434 //\r
435 // Fill Event Segment address\r
436 //\r
437 ERSTBase->PtrLo = XHC_LOW_32BIT (EventRing->EventRingSeg0);\r
438 ERSTBase->PtrHi = XHC_HIGH_32BIT (EventRing->EventRingSeg0);\r
439 ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;\r
440\r
441 //\r
442 // Program the Interrupter Event Ring Dequeue Pointer (DCERDP) register (7.6.4.1)\r
443 //\r
444 XhcWriteDebugReg (\r
445 Handle,\r
446 XHC_DC_DCERDP,\r
447 XHC_LOW_32BIT((UINT64)(UINTN)EventRing->EventRingDequeue)\r
448 );\r
449\r
450 XhcWriteDebugReg (\r
451 Handle,\r
452 XHC_DC_DCERDP + 4,\r
453 XHC_HIGH_32BIT((UINT64)(UINTN)EventRing->EventRingDequeue)\r
454 );\r
455\r
456 //\r
457 // Program the Debug Capability Event Ring Segment Table Base Address (DCERSTBA) register(7.6.4.1)\r
458 //\r
459 XhcWriteDebugReg (\r
460 Handle,\r
461 XHC_DC_DCERSTBA,\r
462 XHC_LOW_32BIT((UINT64)(UINTN)ERSTBase)\r
463 );\r
464\r
465 XhcWriteDebugReg (\r
466 Handle,\r
467 XHC_DC_DCERSTBA + 4,\r
468 XHC_HIGH_32BIT((UINT64)(UINTN)ERSTBase)\r
469 );\r
470\r
471 //\r
472 // Program the Debug Capability Event Ring Segment Table Size (DCERSTSZ) register(7.6.4.1)\r
473 //\r
474 XhcWriteDebugReg (\r
475 Handle,\r
476 XHC_DC_DCERSTSZ,\r
477 ERST_NUMBER\r
478 );\r
479 return EFI_SUCCESS;\r
480}\r
481\r
482/**\r
483 Create XHCI transfer ring.\r
484\r
485 @param Handle Debug port handle.\r
486 @param TrbNum The number of TRB in the ring.\r
487 @param TransferRing The created transfer ring.\r
488\r
489**/\r
490VOID\r
491CreateTransferRing (\r
492 IN USB3_DEBUG_PORT_HANDLE *Handle,\r
493 IN UINT32 TrbNum,\r
494 OUT TRANSFER_RING *TransferRing\r
495 )\r
496{\r
497 VOID *Buf;\r
498 LINK_TRB *EndTrb;\r
499 \r
500 Buf = AllocateAlignBuffer (sizeof (TRB_TEMPLATE) * TrbNum);\r
501 ASSERT (Buf != NULL);\r
502 ASSERT (((UINTN) Buf & 0xF) == 0);\r
503 ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);\r
504\r
505 TransferRing->RingSeg0 = (EFI_PHYSICAL_ADDRESS)(UINTN) Buf;\r
506 TransferRing->TrbNumber = TrbNum;\r
507 TransferRing->RingEnqueue = TransferRing->RingSeg0;\r
508 TransferRing->RingDequeue = TransferRing->RingSeg0;\r
509 TransferRing->RingPCS = 1;\r
510 //\r
511 // 4.9.2 Transfer Ring Management\r
512 // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to\r
513 // point to the first TRB in the ring.\r
514 //\r
515 EndTrb = (LINK_TRB *) ((UINTN)Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));\r
516 EndTrb->Type = TRB_TYPE_LINK;\r
517 EndTrb->PtrLo = XHC_LOW_32BIT (Buf);\r
518 EndTrb->PtrHi = XHC_HIGH_32BIT (Buf);\r
519 //\r
520 // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.\r
521 //\r
522 EndTrb->TC = 1;\r
523 //\r
524 // Set Cycle bit as other TRB PCS init value\r
525 //\r
526 EndTrb->CycleBit = 0;\r
527}\r
528\r
529/**\r
530 Create debug capability context for XHC debug device.\r
531\r
532 @param Handle Debug port handle.\r
533\r
534 @retval EFI_SUCCESS The bit successfully changed by host controller.\r
535 @retval EFI_TIMEOUT The time out occurred.\r
536\r
537**/\r
538EFI_STATUS\r
539CreateDebugCapabilityContext (\r
540 IN USB3_DEBUG_PORT_HANDLE *Handle\r
541 )\r
542{\r
543 VOID *Buf;\r
544 XHC_DC_CONTEXT *DebugCapabilityContext;\r
545 UINT8 *String0Desc;\r
546 UINT8 *ManufacturerStrDesc;\r
547 UINT8 *ProductStrDesc;\r
548 UINT8 *SerialNumberStrDesc;\r
549 \r
550 //\r
551 // Allocate debug device context\r
552 //\r
553 Buf = AllocateAlignBuffer (sizeof (XHC_DC_CONTEXT));\r
554 ASSERT (Buf != NULL);\r
555 ASSERT (((UINTN) Buf & 0xF) == 0);\r
556 ZeroMem (Buf, sizeof (XHC_DC_CONTEXT));\r
557 \r
558 DebugCapabilityContext = (XHC_DC_CONTEXT *)(UINTN) Buf;\r
559 Handle->DebugCapabilityContext = (EFI_PHYSICAL_ADDRESS)(UINTN) DebugCapabilityContext;\r
560 \r
561 //\r
562 // Initialize DbcInfoContext.\r
563 //\r
564 DebugCapabilityContext->DbcInfoContext.String0Length = STRING0_DESC_LEN;\r
565 DebugCapabilityContext->DbcInfoContext.ManufacturerStrLength = MANU_DESC_LEN;\r
566 DebugCapabilityContext->DbcInfoContext.ProductStrLength = PRODUCT_DESC_LEN;\r
567 DebugCapabilityContext->DbcInfoContext.SerialNumberStrLength = SERIAL_DESC_LEN;\r
568\r
569 //\r
570 // Initialize EpOutContext.\r
571 //\r
572 DebugCapabilityContext->EpOutContext.CErr = 0x3;\r
573 DebugCapabilityContext->EpOutContext.EPType = ED_BULK_OUT;\r
5d6507a1 574 DebugCapabilityContext->EpOutContext.MaxPacketSize = XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;\r
2cb6eabe
EL
575 DebugCapabilityContext->EpOutContext.AverageTRBLength = 0x1000;\r
576 \r
577 //\r
578 // Initialize EpInContext.\r
579 //\r
580 DebugCapabilityContext->EpInContext.CErr = 0x3;\r
581 DebugCapabilityContext->EpInContext.EPType = ED_BULK_IN;\r
5d6507a1 582 DebugCapabilityContext->EpInContext.MaxPacketSize = XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;\r
2cb6eabe
EL
583 DebugCapabilityContext->EpInContext.AverageTRBLength = 0x1000;\r
584 \r
585 //\r
586 // Update string descriptor address\r
587 //\r
588 String0Desc = (UINT8 *) AllocateAlignBuffer (STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN);\r
589 ASSERT (String0Desc != NULL);\r
590 ZeroMem (String0Desc, STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN);\r
591 CopyMem (String0Desc, mString0Desc, STRING0_DESC_LEN);\r
592 DebugCapabilityContext->DbcInfoContext.String0DescAddress = (UINT64)(UINTN)String0Desc;\r
593 \r
594 ManufacturerStrDesc = String0Desc + STRING0_DESC_LEN;\r
595 CopyMem (ManufacturerStrDesc, mManufacturerStrDesc, MANU_DESC_LEN);\r
596 DebugCapabilityContext->DbcInfoContext.ManufacturerStrDescAddress = (UINT64)(UINTN)ManufacturerStrDesc;\r
597 \r
598 ProductStrDesc = ManufacturerStrDesc + MANU_DESC_LEN;\r
599 CopyMem (ProductStrDesc, mProductStrDesc, PRODUCT_DESC_LEN);\r
600 DebugCapabilityContext->DbcInfoContext.ProductStrDescAddress = (UINT64)(UINTN)ProductStrDesc;\r
601 \r
602 SerialNumberStrDesc = ProductStrDesc + PRODUCT_DESC_LEN;\r
603 CopyMem (SerialNumberStrDesc, mSerialNumberStrDesc, SERIAL_DESC_LEN);\r
604 DebugCapabilityContext->DbcInfoContext.SerialNumberStrDescAddress = (UINT64)(UINTN)SerialNumberStrDesc;\r
605 \r
606 //\r
607 // Allocate and initialize the Transfer Ring for the Input Endpoint Context.\r
608 //\r
609 ZeroMem (&Handle->TransferRingIn, sizeof (TRANSFER_RING));\r
610 CreateTransferRing (Handle, TR_RING_TRB_NUMBER, &Handle->TransferRingIn);\r
611 DebugCapabilityContext->EpInContext.PtrLo = XHC_LOW_32BIT (Handle->TransferRingIn.RingSeg0) | BIT0;\r
612 DebugCapabilityContext->EpInContext.PtrHi = XHC_HIGH_32BIT (Handle->TransferRingIn.RingSeg0);\r
613\r
614 //\r
615 // Allocate and initialize the Transfer Ring for the Output Endpoint Context.\r
616 //\r
617 ZeroMem (&Handle->TransferRingOut, sizeof (TRANSFER_RING));\r
618 CreateTransferRing (Handle, TR_RING_TRB_NUMBER, &Handle->TransferRingOut);\r
619 DebugCapabilityContext->EpOutContext.PtrLo = XHC_LOW_32BIT (Handle->TransferRingOut.RingSeg0) | BIT0;\r
620 DebugCapabilityContext->EpOutContext.PtrHi = XHC_HIGH_32BIT (Handle->TransferRingOut.RingSeg0);\r
621\r
622 //\r
623 // Program the Debug Capability Context Pointer (DCCP) register(7.6.8.7)\r
624 //\r
625 XhcWriteDebugReg (\r
626 Handle,\r
627 XHC_DC_DCCP,\r
628 XHC_LOW_32BIT((UINT64)(UINTN)DebugCapabilityContext)\r
629 );\r
630 XhcWriteDebugReg (\r
631 Handle,\r
632 XHC_DC_DCCP + 4,\r
633 XHC_HIGH_32BIT((UINT64)(UINTN)DebugCapabilityContext)\r
634 );\r
635 return EFI_SUCCESS;\r
636}\r
637\r
638/**\r
639 Check if debug device is running.\r
640\r
641 @param Handle Debug port handle.\r
642\r
643**/\r
644VOID\r
645XhcDetectDebugCapabilityReady (\r
646 IN USB3_DEBUG_PORT_HANDLE *Handle\r
647 )\r
648{\r
649 UINT64 TimeOut;\r
650 volatile UINT32 Dcctrl;\r
651\r
652 TimeOut = 1;\r
653 if (Handle->Initialized == USB3DBG_DBG_CAB) {\r
654 //\r
655 // As detection is slow in seconds, wait for longer timeout for the first time.\r
656 // If first initialization is failed, we will try to enable debug device in the\r
657 // Poll function invoked by timer.\r
658 //\r
659 TimeOut = DivU64x32 (PcdGet64 (PcdUsbXhciDebugDetectTimeout), XHC_POLL_DELAY) + 1;\r
660 }\r
661\r
662 do {\r
663 //\r
664 // Check if debug device is in configured state\r
665 //\r
666 Dcctrl = XhcReadDebugReg (Handle, XHC_DC_DCCTRL);\r
667 if ((Dcctrl & BIT0) != 0) {\r
668 //\r
669 // Set the flag to indicate debug device is in configured state\r
670 //\r
671 Handle->Ready = TRUE;\r
672 break;\r
673 }\r
674 MicroSecondDelay (XHC_POLL_DELAY);\r
675 TimeOut--;\r
676 } while (TimeOut != 0);\r
677}\r
678\r
679/**\r
680 Initialize usb debug port hardware.\r
681\r
682 @param Handle Debug port handle.\r
683\r
684 @retval TRUE The usb debug port hardware configuration is changed.\r
685 @retval FALSE The usb debug port hardware configuration is not changed.\r
686\r
687**/\r
688RETURN_STATUS\r
689EFIAPI\r
690InitializeUsbDebugHardware (\r
691 IN USB3_DEBUG_PORT_HANDLE *Handle\r
692 )\r
693{\r
694 RETURN_STATUS Status;\r
695 UINT8 *Buffer;\r
696 UINTN Index;\r
697 UINT8 TotalUsb3Port;\r
698 EFI_PHYSICAL_ADDRESS XhciOpRegister;\r
699\r
700 XhciOpRegister = Handle->XhciOpRegister;\r
701 TotalUsb3Port = MmioRead32 (((UINTN) Handle->XhciMmioBase + XHC_HCSPARAMS1_OFFSET)) >> 24;\r
702\r
703 if (Handle->Initialized == USB3DBG_NOT_ENABLED) {\r
704 //\r
705 // If XHCI supports debug capability, hardware resource has been allocated, \r
706 // but it has not been enabled, try to enable again.\r
707 //\r
708 goto Enable;\r
709 }\r
710\r
711 //\r
5d6507a1
EL
712 // Initialize for PEI phase when AllocatePages can work.\r
713 // Allocate data buffer with max packet size for data read and data poll.\r
714 // Allocate data buffer for data write.\r
2cb6eabe 715 //\r
5d6507a1 716 Buffer = AllocateAlignBuffer (XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE * 2 + USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE);\r
2cb6eabe
EL
717 if (Buffer == NULL) {\r
718 //\r
719 // AllocatePages can not still work now, return fail and do not initialize now.\r
720 //\r
721 return RETURN_NOT_READY;\r
722 }\r
723\r
724 //\r
725 // Reset port to get debug device discovered\r
726 // \r
727 for (Index = 0; Index < TotalUsb3Port; Index++) {\r
728 XhcSetR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT4);\r
729 MicroSecondDelay (10 * 1000);\r
730 }\r
731\r
732 //\r
5d6507a1 733 // Construct the buffer for read, poll and write.\r
2cb6eabe
EL
734 //\r
735 Handle->UrbIn.Data = (EFI_PHYSICAL_ADDRESS)(UINTN) Buffer;\r
5d6507a1
EL
736 Handle->Data = (EFI_PHYSICAL_ADDRESS)(UINTN) Buffer + XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;\r
737 Handle->UrbOut.Data = Handle->UrbIn.Data + XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE * 2;\r
2cb6eabe
EL
738 \r
739 //\r
740 // Initialize event ring\r
741 //\r
742 ZeroMem (&Handle->EventRing, sizeof (EVENT_RING));\r
743 Status = CreateEventRing (Handle, &Handle->EventRing);\r
744 ASSERT_EFI_ERROR (Status);\r
745 \r
746 //\r
747 // Init IN and OUT endpoint context\r
748 //\r
749 Status = CreateDebugCapabilityContext (Handle);\r
750 ASSERT_EFI_ERROR (Status);\r
751 \r
752 //\r
753 // Init DCDDI1 and DCDDI2\r
754 //\r
755 XhcWriteDebugReg (\r
756 Handle,\r
757 XHC_DC_DCDDI1,\r
758 (UINT32)((XHCI_DEBUG_DEVICE_VENDOR_ID << 16) | XHCI_DEBUG_DEVICE_PROTOCOL)\r
759 ); \r
760\r
761 XhcWriteDebugReg (\r
762 Handle,\r
763 XHC_DC_DCDDI2,\r
764 (UINT32)((XHCI_DEBUG_DEVICE_REVISION << 16) | XHCI_DEBUG_DEVICE_PRODUCT_ID)\r
765 );\r
766\r
767Enable:\r
768 if ((Handle->Initialized == USB3DBG_NOT_ENABLED) && (!Handle->ChangePortPower)) {\r
769 //\r
770 // If the first time detection is failed, turn port power off and on in order to \r
771 // reset port status this time, then try to check if debug device is ready again.\r
772 //\r
773 for (Index = 0; Index < TotalUsb3Port; Index++) {\r
774 XhcClearR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT9);\r
775 MicroSecondDelay (XHC_DEBUG_PORT_ON_OFF_DELAY);\r
776 XhcSetR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT9);\r
777 MicroSecondDelay (XHC_DEBUG_PORT_ON_OFF_DELAY);\r
778 Handle->ChangePortPower = TRUE;\r
779 }\r
780 }\r
781\r
782 //\r
783 // Set DCE bit and LSE bit to "1" in DCCTRL in first initialization\r
784 //\r
785 XhcSetDebugRegBit (Handle, XHC_DC_DCCTRL, BIT1|BIT31);\r
786 \r
787 XhcDetectDebugCapabilityReady (Handle);\r
788 \r
789 Status = RETURN_SUCCESS;\r
790 if (!Handle->Ready) {\r
791 Handle->Initialized = USB3DBG_NOT_ENABLED;\r
792 Status = RETURN_NOT_READY;\r
793 } else {\r
794 Handle->Initialized = USB3DBG_ENABLED;\r
795 }\r
796\r
797 return Status;\r
798}\r
799\r
800/**\r
801 Read data from debug device and save the data in buffer.\r
802\r
803 Reads NumberOfBytes data bytes from a debug device into the buffer\r
804 specified by Buffer. The number of bytes actually read is returned.\r
805 If the return value is less than NumberOfBytes, then the rest operation failed.\r
806 If NumberOfBytes is zero, then return 0.\r
807\r
808 @param Handle Debug port handle.\r
809 @param Buffer Pointer to the data buffer to store the data read from the debug device.\r
810 @param NumberOfBytes Number of bytes which will be read.\r
811 @param Timeout Timeout value for reading from debug device. It unit is Microsecond.\r
812\r
813 @retval 0 Read data failed, no data is to be read.\r
814 @retval >0 Actual number of bytes read from debug device.\r
815\r
816**/\r
817UINTN\r
818EFIAPI\r
819DebugPortReadBuffer (\r
820 IN DEBUG_PORT_HANDLE Handle,\r
821 IN UINT8 *Buffer,\r
822 IN UINTN NumberOfBytes,\r
823 IN UINTN Timeout\r
824 )\r
825{\r
826 USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle;\r
827 RETURN_STATUS Status;\r
828 UINTN Received;\r
829 UINTN Total;\r
830 UINTN Remaining;\r
831 UINT8 Index;\r
832 UINTN Length;\r
833 UINT64 Begin;\r
834 UINT64 TimeoutTicker;\r
835 UINT64 TimerRound;\r
836 EFI_PHYSICAL_ADDRESS XhciMmioBase;\r
5d6507a1 837 UINT8 *Data;\r
2cb6eabe
EL
838\r
839 if (NumberOfBytes == 0 || Buffer == NULL) {\r
840 return 0;\r
841 }\r
842\r
843 Received = 0;\r
844 Total = 0;\r
845 Remaining = 0;\r
846\r
847 //\r
848 // If Handle is NULL, it means memory is ready for use.\r
849 // Use global variable to store handle value.\r
850 //\r
851 if (Handle == NULL) {\r
852 UsbDebugPortHandle = &mDebugCommunicationLibUsb3DebugPortHandle;\r
853 } else {\r
854 UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *)Handle;\r
855 }\r
856 \r
857 if (UsbDebugPortHandle->Initialized == USB3DBG_NO_DBG_CAB) {\r
858 return 0;\r
859 }\r
860 \r
861 XhciMmioBase = ProgramXhciBaseAddress ();\r
862 UpdateXhcResource (UsbDebugPortHandle, XhciMmioBase);\r
863 \r
864 if (NeedReinitializeHardware(UsbDebugPortHandle)) {\r
865 Status = InitializeUsbDebugHardware (UsbDebugPortHandle);\r
866 if (RETURN_ERROR(Status)) {\r
867 return 0;\r
868 }\r
869 }\r
870\r
5d6507a1
EL
871 Data = (UINT8 *)(UINTN)UsbDebugPortHandle->Data;\r
872\r
2cb6eabe
EL
873 //\r
874 // First read data from buffer, then read debug port hw to get received data.\r
875 //\r
876 if (UsbDebugPortHandle->DataCount > 0) {\r
877 if (NumberOfBytes <= UsbDebugPortHandle->DataCount) {\r
878 Total = NumberOfBytes;\r
879 } else {\r
880 Total = UsbDebugPortHandle->DataCount;\r
881 }\r
882\r
883 for (Index = 0; Index < Total; Index++) {\r
5d6507a1 884 Buffer[Index] = Data[Index];\r
2cb6eabe
EL
885 }\r
886\r
887 for (Index = 0; Index < UsbDebugPortHandle->DataCount - Total; Index++) {\r
5d6507a1 888 if (Total + Index >= XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE) {\r
2cb6eabe
EL
889 return 0;\r
890 }\r
5d6507a1 891 Data[Index] = Data[Total + Index];\r
2cb6eabe
EL
892 }\r
893 UsbDebugPortHandle->DataCount = (UINT8)(UsbDebugPortHandle->DataCount - (UINT8)Total);\r
894 }\r
895\r
896 //\r
897 // If Timeout is equal to 0, then it means it should always wait until all data required are received.\r
898 //\r
899 Begin = 0;\r
900 TimeoutTicker = 0; \r
901 TimerRound = 0;\r
902 if (Timeout != 0) {\r
903 Begin = GetPerformanceCounter ();\r
904 TimeoutTicker = DivU64x32 (\r
905 MultU64x64 (\r
906 UsbDebugPortHandle->TimerFrequency,\r
907 Timeout\r
908 ),\r
909 1000000u\r
910 );\r
911 TimerRound = DivU64x64Remainder (\r
912 TimeoutTicker,\r
913 DivU64x32 (UsbDebugPortHandle->TimerCycle, 2),\r
914 &TimeoutTicker\r
915 );\r
916 }\r
917\r
918 //\r
919 // Read remaining data by executing one or more usb debug transfer transactions at usb debug port hw.\r
920 //\r
921 while (Total < NumberOfBytes) {\r
922 if (Timeout != 0) {\r
923 if (TimerRound == 0) {\r
924 if (IsTimerTimeout (UsbDebugPortHandle, Begin, TimeoutTicker)) {\r
925 //\r
926 // If time out occurs.\r
927 //\r
928 return 0;\r
929 }\r
930 } else {\r
931 if (IsTimerTimeout (UsbDebugPortHandle, Begin, DivU64x32 (UsbDebugPortHandle->TimerCycle, 2))) {\r
932 TimerRound --;\r
933 }\r
934 }\r
935 }\r
936 Remaining = NumberOfBytes - Total;\r
5d6507a1
EL
937 if (Remaining >= XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE) {\r
938 Received = XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;\r
2cb6eabe
EL
939 Status = XhcDataTransfer (UsbDebugPortHandle, EfiUsbDataIn, Buffer + Total, &Received, DATA_TRANSFER_READ_TIMEOUT);\r
940 } else {\r
5d6507a1
EL
941 Received = XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;\r
942 Status = XhcDataTransfer (UsbDebugPortHandle, EfiUsbDataIn, (VOID *)Data, &Received, DATA_TRANSFER_READ_TIMEOUT);\r
2cb6eabe
EL
943 UsbDebugPortHandle->DataCount = (UINT8) Received;\r
944\r
945 if (Remaining <= Received) {\r
946 //\r
947 // The data received are more than required\r
948 //\r
949 Length = (UINT8)Remaining;\r
950 } else {\r
951 //\r
952 // The data received are less than the remaining bytes\r
953 //\r
954 Length = (UINT8)Received;\r
955 }\r
956\r
957 //\r
958 // Copy required data from the data buffer to user buffer.\r
959 //\r
960 for (Index = 0; Index < Length; Index++) {\r
5d6507a1 961 (Buffer + Total)[Index] = Data[Index];\r
2cb6eabe
EL
962 UsbDebugPortHandle->DataCount--;\r
963 }\r
964\r
965 //\r
966 // reorder the data buffer to make available data arranged from the beginning of the data buffer.\r
967 //\r
968 for (Index = 0; Index < Received - Length; Index++) {\r
5d6507a1 969 if (Length + Index >= XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE) {\r
2cb6eabe
EL
970 return 0;\r
971 }\r
5d6507a1 972 Data[Index] = Data[Length + Index];\r
2cb6eabe
EL
973 }\r
974 //\r
975 // fixup the real required length of data.\r
976 //\r
977 Received = Length;\r
978 }\r
979 Total += Received;\r
980 }\r
981 return Total;\r
982}\r
983\r
984/**\r
985 Write data from buffer to debug device.\r
986\r
987 Writes NumberOfBytes data bytes from Buffer to the debug device.\r
988 The number of bytes actually written to the debug device is returned.\r
989 If the return value is less than NumberOfBytes, then the write operation failed.\r
990 If NumberOfBytes is zero, then return 0.\r
991\r
992 @param Handle Debug port handle.\r
993 @param Buffer Pointer to the data buffer to be written.\r
994 @param NumberOfBytes Number of bytes to written to the debug device.\r
995\r
996 @retval 0 NumberOfBytes is 0.\r
997 @retval >0 The number of bytes written to the debug device.\r
998 If this value is less than NumberOfBytes, then the read operation failed.\r
999\r
1000**/\r
1001UINTN\r
1002EFIAPI\r
1003DebugPortWriteBuffer (\r
1004 IN DEBUG_PORT_HANDLE Handle,\r
1005 IN UINT8 *Buffer,\r
1006 IN UINTN NumberOfBytes\r
1007 )\r
1008{\r
1009 USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle;\r
1010 RETURN_STATUS Status;\r
1011 UINTN Sent;\r
1012 UINTN Total;\r
1013 EFI_PHYSICAL_ADDRESS XhciMmioBase;\r
1014 UINTN Index;\r
1015\r
1016 if (NumberOfBytes == 0 || Buffer == NULL) {\r
1017 return 0;\r
1018 }\r
1019\r
1020 Sent = 0;\r
1021 Total = 0;\r
1022\r
1023 //\r
1024 // If Handle is NULL, it means memory is ready for use.\r
1025 // Use global variable to store handle value.\r
1026 //\r
1027 if (Handle == NULL) {\r
1028 UsbDebugPortHandle = &mDebugCommunicationLibUsb3DebugPortHandle;\r
1029 } else {\r
1030 UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *)Handle;\r
1031 }\r
1032 \r
1033 if (UsbDebugPortHandle->Initialized == USB3DBG_NO_DBG_CAB) {\r
1034 return 0;\r
1035 }\r
1036\r
1037 //\r
1038 // MMIO base address is possible to clear, set it if it is cleared. (XhciMemorySpaceClose in PchUsbCommon.c)\r
1039 //\r
1040 XhciMmioBase = ProgramXhciBaseAddress ();\r
1041\r
1042 UpdateXhcResource (UsbDebugPortHandle, XhciMmioBase);\r
1043\r
1044 if (NeedReinitializeHardware(UsbDebugPortHandle)) {\r
1045 Status = InitializeUsbDebugHardware (UsbDebugPortHandle);\r
1046 if (RETURN_ERROR(Status)) {\r
1047 return 0;\r
1048 }\r
1049 }\r
1050\r
1051 //\r
1052 // When host is trying to send data, write will be blocked.\r
1053 // Poll to see if there is any data sent by host at first.\r
1054 //\r
1055 DebugPortPollBuffer (Handle);\r
1056\r
1057 Index = 0;\r
1058 while ((Total < NumberOfBytes)) {\r
5d6507a1
EL
1059 if (NumberOfBytes - Total > USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE) {\r
1060 Sent = USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE;\r
2cb6eabe
EL
1061 } else {\r
1062 Sent = (UINT8)(NumberOfBytes - Total);\r
1063 }\r
1064 Status = XhcDataTransfer (UsbDebugPortHandle, EfiUsbDataOut, Buffer + Total, &Sent, DATA_TRANSFER_WRITE_TIMEOUT);\r
1065 Total += Sent;\r
1066 }\r
1067 \r
1068 return Total;\r
1069}\r
1070\r
1071/**\r
1072 Polls a debug device to see if there is any data waiting to be read.\r
1073\r
1074 Polls a debug device to see if there is any data waiting to be read.\r
1075 If there is data waiting to be read from the debug device, then TRUE is returned.\r
1076 If there is no data waiting to be read from the debug device, then FALSE is returned.\r
1077\r
1078 @param Handle Debug port handle.\r
1079\r
1080 @retval TRUE Data is waiting to be read from the debug device.\r
1081 @retval FALSE There is no data waiting to be read from the serial device.\r
1082\r
1083**/\r
1084BOOLEAN\r
1085EFIAPI\r
1086DebugPortPollBuffer (\r
1087 IN DEBUG_PORT_HANDLE Handle\r
1088 )\r
1089{\r
1090 USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle;\r
1091 UINTN Length;\r
1092 RETURN_STATUS Status;\r
2cb6eabe
EL
1093 EFI_PHYSICAL_ADDRESS XhciMmioBase;\r
1094\r
1095 //\r
1096 // If Handle is NULL, it means memory is ready for use.\r
1097 // Use global variable to store handle value.\r
1098 //\r
1099 if (Handle == NULL) {\r
1100 UsbDebugPortHandle = &mDebugCommunicationLibUsb3DebugPortHandle;\r
1101 } else {\r
1102 UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *)Handle;\r
1103 }\r
1104\r
1105 if (UsbDebugPortHandle->Initialized == USB3DBG_NO_DBG_CAB) {\r
1106 return 0;\r
1107 }\r
1108\r
1109 XhciMmioBase = ProgramXhciBaseAddress ();\r
1110 UpdateXhcResource (UsbDebugPortHandle, XhciMmioBase);\r
1111 \r
1112 if (NeedReinitializeHardware(UsbDebugPortHandle)) {\r
1113 Status = InitializeUsbDebugHardware(UsbDebugPortHandle);\r
1114 if (RETURN_ERROR(Status)) {\r
1115 return FALSE;\r
1116 }\r
1117 }\r
1118 \r
1119 //\r
1120 // If the data buffer is not empty, then return TRUE directly.\r
1121 // Otherwise initialize a usb read transaction and read data to internal data buffer.\r
1122 //\r
1123 if (UsbDebugPortHandle->DataCount != 0) {\r
1124 return TRUE;\r
1125 }\r
1126\r
1127 //\r
5d6507a1 1128 // Read data as much as we can\r
2cb6eabe 1129 //\r
5d6507a1
EL
1130 Length = XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;\r
1131 XhcDataTransfer (Handle, EfiUsbDataIn, (VOID *)(UINTN)UsbDebugPortHandle->Data, &Length, DATA_TRANSFER_POLL_TIMEOUT);\r
2cb6eabe 1132\r
5d6507a1 1133 if (Length > XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE) {\r
2cb6eabe
EL
1134 return FALSE;\r
1135 }\r
1136\r
1137 if (Length == 0) {\r
1138 return FALSE;\r
1139 }\r
1140\r
1141 //\r
1142 // Store data into internal buffer for use later\r
1143 //\r
2cb6eabe
EL
1144 UsbDebugPortHandle->DataCount = (UINT8) Length;\r
1145 return TRUE;\r
1146}\r
1147\r
1148/**\r
1149 Initialize the debug port.\r
1150\r
1151 If Function is not NULL, Debug Communication Libary will call this function\r
1152 by passing in the Context to be the first parameter. If needed, Debug Communication\r
1153 Library will create one debug port handle to be the second argument passing in\r
1154 calling the Function, otherwise it will pass NULL to be the second argument of\r
1155 Function.\r
1156\r
1157 If Function is NULL, and Context is not NULL, the Debug Communication Library could\r
1158 a) Return the same handle as passed in (as Context parameter).\r
1159 b) Ignore the input Context parameter and create new hanlde to be returned.\r
1160\r
1161 If parameter Function is NULL and Context is NULL, Debug Communication Library could\r
1162 created a new handle if needed and return it, otherwise it will return NULL.\r
1163\r
1164 @param[in] Context Context needed by callback function; it was optional.\r
1165 @param[in] Function Continue function called by Debug Communication library;\r
1166 it was optional.\r
1167\r
1168 @return The debug port handle created by Debug Communication Library if Function\r
1169 is not NULL.\r
1170\r
1171**/\r
1172DEBUG_PORT_HANDLE\r
1173EFIAPI\r
1174DebugPortInitialize (\r
1175 IN VOID *Context,\r
1176 IN DEBUG_PORT_CONTINUE Function\r
1177 )\r
1178{\r
1179 RETURN_STATUS Status;\r
1180 USB3_DEBUG_PORT_HANDLE Handle;\r
1181 USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle;\r
1182 UINT64 TimerStartValue;\r
1183 UINT64 TimerEndValue;\r
1184\r
1185 //\r
1186 // Validate the PCD PcdDebugPortHandleBufferSize value \r
1187 //\r
1188 ASSERT (PcdGet16 (PcdDebugPortHandleBufferSize) == sizeof (USB3_DEBUG_PORT_HANDLE));\r
1189\r
1190 if (Function == NULL && Context != NULL) {\r
1191 UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *)Context;\r
1192 } else {\r
1193 ZeroMem(&Handle, sizeof (USB3_DEBUG_PORT_HANDLE));\r
1194 UsbDebugPortHandle = &Handle;\r
1195 }\r
1196\r
1197 UsbDebugPortHandle->TimerFrequency = GetPerformanceCounterProperties (\r
1198 &TimerStartValue,\r
1199 &TimerEndValue\r
1200 );\r
1201\r
1202 if (TimerEndValue < TimerStartValue) {\r
1203 UsbDebugPortHandle->TimerCountDown = TRUE;\r
1204 UsbDebugPortHandle->TimerCycle = TimerStartValue - TimerEndValue;\r
1205 } else {\r
1206 UsbDebugPortHandle->TimerCountDown = FALSE;\r
1207 UsbDebugPortHandle->TimerCycle = TimerEndValue - TimerStartValue;\r
1208 } \r
1209\r
1210 if (Function == NULL && Context != NULL) {\r
1211 return (DEBUG_PORT_HANDLE *) Context;\r
1212 }\r
1213 \r
1214 //\r
1215 // Read 64-bit MMIO base address\r
1216 //\r
1217 UsbDebugPortHandle->XhciMmioBase = ProgramXhciBaseAddress ();\r
1218\r
1219 Status = CalculateUsbDebugPortMmioBase (UsbDebugPortHandle);\r
1220 if (RETURN_ERROR (Status)) {\r
1221 goto Exit;\r
1222 }\r
1223\r
1224 if (NeedReinitializeHardware(&Handle)) {\r
1225 Status = InitializeUsbDebugHardware (&Handle);\r
1226 if (RETURN_ERROR(Status)) {\r
1227 goto Exit;\r
1228 }\r
1229 }\r
1230\r
1231Exit:\r
1232\r
1233 if (Function != NULL) {\r
1234 Function (Context, &Handle);\r
1235 } else {\r
1236 CopyMem(&mDebugCommunicationLibUsb3DebugPortHandle, &Handle, sizeof (USB3_DEBUG_PORT_HANDLE));\r
1237 }\r
1238\r
1239 return (DEBUG_PORT_HANDLE)(UINTN)&mDebugCommunicationLibUsb3DebugPortHandle;\r
1240}\r