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