1 /** @file
2   Debug Port Library implementation based on usb3 debug port.
3 
4   Copyright (c) 2014 - 2015, 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
XhcSetR32Bit(IN OUT UINTN Register,IN UINT32 BitMask)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
XhcClearR32Bit(IN OUT UINTN Register,IN UINT32 BitMask)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
XhcWriteDebugReg(IN USB3_DEBUG_PORT_HANDLE * Handle,IN UINT32 Offset,IN UINT32 Data)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
XhcReadDebugReg(IN USB3_DEBUG_PORT_HANDLE * Handle,IN UINT32 Offset)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
XhcSetDebugRegBit(IN USB3_DEBUG_PORT_HANDLE * Handle,IN UINT32 Offset,IN UINT32 Bit)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
ProgramXhciBaseAddress(VOID)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   Update XHC MMIO base address when MMIO base address is changed.
191 
192   @param  Handle          Debug port handle.
193   @param  XhciMmioBase    XHCI MMIO base address.
194 
195 **/
196 VOID
UpdateXhcResource(IN OUT USB3_DEBUG_PORT_HANDLE * Handle,IN EFI_PHYSICAL_ADDRESS XhciMmioBase)197 UpdateXhcResource (
198   IN OUT USB3_DEBUG_PORT_HANDLE            *Handle,
199   IN EFI_PHYSICAL_ADDRESS                   XhciMmioBase
200   )
201 {
202   if ((Handle == NULL) || (Handle->XhciMmioBase == XhciMmioBase)) {
203     return;
204   }
205 
206   //
207   // Need fix Handle data according to new XHCI MMIO base address.
208   //
209   Handle->XhciMmioBase        = XhciMmioBase;
210   Handle->DebugCapabilityBase = XhciMmioBase + Handle->DebugCapabilityOffset;
211   Handle->XhciOpRegister      = XhciMmioBase + MmioRead8 ((UINTN)XhciMmioBase);
212 }
213 
214 /**
215   Calculate the usb debug port bar address.
216 
217   @param  Handle             Debug port handle.
218 
219   @retval RETURN_UNSUPPORTED The usb host controller does not supported usb debug port capability.
220   @retval RETURN_SUCCESS     Get bar and offset successfully.
221 
222 **/
223 RETURN_STATUS
224 EFIAPI
CalculateUsbDebugPortMmioBase(USB3_DEBUG_PORT_HANDLE * Handle)225 CalculateUsbDebugPortMmioBase (
226   USB3_DEBUG_PORT_HANDLE          *Handle
227  )
228 {
229   UINT16                          VendorId;
230   UINT16                          DeviceId;
231   UINT8                           ProgInterface;
232   UINT8                           SubClassCode;
233   UINT8                           BaseCode;
234   BOOLEAN                         Flag;
235   UINT32                          Capability;
236   EFI_PHYSICAL_ADDRESS            CapabilityPointer;
237   UINT8                           CapLength;
238 
239   VendorId = PciRead16 (PcdGet32(PcdUsbXhciPciAddress) + PCI_VENDOR_ID_OFFSET);
240   DeviceId = PciRead16 (PcdGet32(PcdUsbXhciPciAddress) + PCI_DEVICE_ID_OFFSET);
241 
242   if ((VendorId == 0xFFFF) || (DeviceId == 0xFFFF)) {
243     goto Done;
244   }
245 
246   ProgInterface = PciRead8 (PcdGet32(PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET);
247   SubClassCode  = PciRead8 (PcdGet32(PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET + 1);
248   BaseCode      = PciRead8 (PcdGet32(PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET + 2);
249 
250   if ((ProgInterface != PCI_IF_XHCI) || (SubClassCode != PCI_CLASS_SERIAL_USB) || (BaseCode != PCI_CLASS_SERIAL)) {
251     goto Done;
252   }
253 
254   CapLength = MmioRead8 ((UINTN) Handle->XhciMmioBase);
255 
256   //
257   // Get capability pointer from HCCPARAMS at offset 0x10
258   //
259   CapabilityPointer = Handle->XhciMmioBase + (MmioRead32 ((UINTN)(Handle->XhciMmioBase + XHC_HCCPARAMS_OFFSET)) >> 16) * 4;
260 
261   //
262   // Search XHCI debug capability
263   //
264   Flag = FALSE;
265   Capability = MmioRead32 ((UINTN)CapabilityPointer);
266   while (TRUE) {
267     if ((Capability & XHC_CAPABILITY_ID_MASK) == PCI_CAPABILITY_ID_DEBUG_PORT) {
268       Flag = TRUE;
269       break;
270     }
271     if ((((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) & XHC_CAPABILITY_ID_MASK) == 0) {
272       //
273       // Reach the end of capability list, quit
274       //
275       break;
276     }
277     CapabilityPointer += ((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) * 4;
278     Capability = MmioRead32 ((UINTN)CapabilityPointer);
279   }
280 
281   if (!Flag) {
282     goto Done;
283   }
284 
285   //
286   // USB3 debug capability is supported.
287   //
288   Handle->DebugCapabilityBase   = CapabilityPointer;
289   Handle->DebugCapabilityOffset = CapabilityPointer - Handle->XhciMmioBase;
290   Handle->XhciOpRegister        = Handle->XhciMmioBase + CapLength;
291   Handle->Initialized = USB3DBG_DBG_CAB;
292   return RETURN_SUCCESS;
293 
294 Done:
295   Handle->Initialized = USB3DBG_NO_DBG_CAB;
296   return RETURN_UNSUPPORTED;
297 }
298 
299 /**
300   Check if it needs to re-initialize usb debug port hardware.
301 
302   During different phases switch, such as SEC to PEI or PEI to DXE or DXE to SMM, we should check
303   whether the usb debug port hardware configuration is changed. Such case can be triggerred by
304   Pci bus resource allocation and so on.
305 
306   @param  Handle           Debug port handle.
307 
308   @retval TRUE             The usb debug port hardware configuration is changed.
309   @retval FALSE            The usb debug port hardware configuration is not changed.
310 
311 **/
312 BOOLEAN
313 EFIAPI
NeedReinitializeHardware(IN USB3_DEBUG_PORT_HANDLE * Handle)314 NeedReinitializeHardware(
315   IN USB3_DEBUG_PORT_HANDLE *Handle
316   )
317 {
318   BOOLEAN                 Result;
319   volatile UINT32         Dcctrl;
320 
321   Result = FALSE;
322 
323   //
324   // If DCE bit, it means USB3 debug is not enabled.
325   //
326   Dcctrl = XhcReadDebugReg (Handle, XHC_DC_DCCTRL);
327   if ((Dcctrl & BIT0) == 0) {
328     Result = TRUE;
329   }
330 
331   return Result;
332 }
333 
334 /**
335   Create XHCI event ring.
336 
337   @param  Handle              Debug port handle.
338   @param  EventRing           The created event ring.
339 
340 **/
341 EFI_STATUS
CreateEventRing(IN USB3_DEBUG_PORT_HANDLE * Handle,OUT EVENT_RING * EventRing)342 CreateEventRing (
343   IN  USB3_DEBUG_PORT_HANDLE     *Handle,
344   OUT EVENT_RING                 *EventRing
345   )
346 {
347   VOID                        *Buf;
348   EVENT_RING_SEG_TABLE_ENTRY  *ERSTBase;
349 
350   ASSERT (EventRing != NULL);
351 
352   //
353   // Allocate Event Ring
354   //
355   Buf = AllocateAlignBuffer (sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);
356   ASSERT (Buf != NULL);
357   ASSERT (((UINTN) Buf & 0x3F) == 0);
358   ZeroMem (Buf, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);
359 
360   EventRing->EventRingSeg0    = (EFI_PHYSICAL_ADDRESS)(UINTN) Buf;
361   EventRing->TrbNumber        = EVENT_RING_TRB_NUMBER;
362   EventRing->EventRingDequeue = (EFI_PHYSICAL_ADDRESS)(UINTN) EventRing->EventRingSeg0;
363   EventRing->EventRingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN) EventRing->EventRingSeg0;
364 
365   //
366   // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
367   // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
368   //
369   EventRing->EventRingCCS = 1;
370 
371   //
372   // Allocate Event Ring Segment Table Entry 0 in Event Ring Segment Table
373   //
374   Buf = AllocateAlignBuffer (sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);
375   ASSERT (Buf != NULL);
376   ASSERT (((UINTN) Buf & 0x3F) == 0);
377   ZeroMem (Buf, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);
378 
379   ERSTBase              = (EVENT_RING_SEG_TABLE_ENTRY *) Buf;
380   EventRing->ERSTBase   = (EFI_PHYSICAL_ADDRESS)(UINTN) ERSTBase;
381 
382   //
383   // Fill Event Segment address
384   //
385   ERSTBase->PtrLo       = XHC_LOW_32BIT (EventRing->EventRingSeg0);
386   ERSTBase->PtrHi       = XHC_HIGH_32BIT (EventRing->EventRingSeg0);
387   ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;
388 
389   //
390   // Program the Interrupter Event Ring Dequeue Pointer (DCERDP) register (7.6.4.1)
391   //
392   XhcWriteDebugReg (
393     Handle,
394     XHC_DC_DCERDP,
395     XHC_LOW_32BIT((UINT64)(UINTN)EventRing->EventRingDequeue)
396     );
397 
398   XhcWriteDebugReg (
399     Handle,
400     XHC_DC_DCERDP + 4,
401     XHC_HIGH_32BIT((UINT64)(UINTN)EventRing->EventRingDequeue)
402     );
403 
404   //
405   // Program the Debug Capability Event Ring Segment Table Base Address (DCERSTBA) register(7.6.4.1)
406   //
407   XhcWriteDebugReg (
408     Handle,
409     XHC_DC_DCERSTBA,
410     XHC_LOW_32BIT((UINT64)(UINTN)ERSTBase)
411     );
412 
413   XhcWriteDebugReg (
414     Handle,
415     XHC_DC_DCERSTBA + 4,
416     XHC_HIGH_32BIT((UINT64)(UINTN)ERSTBase)
417     );
418 
419   //
420   // Program the Debug Capability Event Ring Segment Table Size (DCERSTSZ) register(7.6.4.1)
421   //
422   XhcWriteDebugReg (
423     Handle,
424     XHC_DC_DCERSTSZ,
425     ERST_NUMBER
426     );
427   return EFI_SUCCESS;
428 }
429 
430 /**
431   Create XHCI transfer ring.
432 
433   @param  Handle            Debug port handle.
434   @param  TrbNum            The number of TRB in the ring.
435   @param  TransferRing      The created transfer ring.
436 
437 **/
438 VOID
CreateTransferRing(IN USB3_DEBUG_PORT_HANDLE * Handle,IN UINT32 TrbNum,OUT TRANSFER_RING * TransferRing)439 CreateTransferRing (
440   IN  USB3_DEBUG_PORT_HANDLE      *Handle,
441   IN  UINT32                      TrbNum,
442   OUT TRANSFER_RING               *TransferRing
443   )
444 {
445   VOID                  *Buf;
446   LINK_TRB              *EndTrb;
447 
448   Buf = AllocateAlignBuffer (sizeof (TRB_TEMPLATE) * TrbNum);
449   ASSERT (Buf != NULL);
450   ASSERT (((UINTN) Buf & 0xF) == 0);
451   ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);
452 
453   TransferRing->RingSeg0     = (EFI_PHYSICAL_ADDRESS)(UINTN) Buf;
454   TransferRing->TrbNumber    = TrbNum;
455   TransferRing->RingEnqueue  = TransferRing->RingSeg0;
456   TransferRing->RingDequeue  = TransferRing->RingSeg0;
457   TransferRing->RingPCS      = 1;
458   //
459   // 4.9.2 Transfer Ring Management
460   // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
461   // point to the first TRB in the ring.
462   //
463   EndTrb        = (LINK_TRB *) ((UINTN)Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));
464   EndTrb->Type  = TRB_TYPE_LINK;
465   EndTrb->PtrLo = XHC_LOW_32BIT (Buf);
466   EndTrb->PtrHi = XHC_HIGH_32BIT (Buf);
467   //
468   // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
469   //
470   EndTrb->TC    = 1;
471   //
472   // Set Cycle bit as other TRB PCS init value
473   //
474   EndTrb->CycleBit = 0;
475 }
476 
477 /**
478   Create debug capability context for XHC debug device.
479 
480   @param  Handle       Debug port handle.
481 
482   @retval EFI_SUCCESS  The bit successfully changed by host controller.
483   @retval EFI_TIMEOUT  The time out occurred.
484 
485 **/
486 EFI_STATUS
CreateDebugCapabilityContext(IN USB3_DEBUG_PORT_HANDLE * Handle)487 CreateDebugCapabilityContext (
488   IN  USB3_DEBUG_PORT_HANDLE   *Handle
489   )
490 {
491   VOID                        *Buf;
492   XHC_DC_CONTEXT              *DebugCapabilityContext;
493   UINT8                       *String0Desc;
494   UINT8                       *ManufacturerStrDesc;
495   UINT8                       *ProductStrDesc;
496   UINT8                       *SerialNumberStrDesc;
497 
498   //
499   // Allocate debug device context
500   //
501   Buf = AllocateAlignBuffer (sizeof (XHC_DC_CONTEXT));
502   ASSERT (Buf != NULL);
503   ASSERT (((UINTN) Buf & 0xF) == 0);
504   ZeroMem (Buf, sizeof (XHC_DC_CONTEXT));
505 
506   DebugCapabilityContext = (XHC_DC_CONTEXT *)(UINTN) Buf;
507   Handle->DebugCapabilityContext = (EFI_PHYSICAL_ADDRESS)(UINTN) DebugCapabilityContext;
508 
509   //
510   // Initialize DbcInfoContext.
511   //
512   DebugCapabilityContext->DbcInfoContext.String0Length         = STRING0_DESC_LEN;
513   DebugCapabilityContext->DbcInfoContext.ManufacturerStrLength = MANU_DESC_LEN;
514   DebugCapabilityContext->DbcInfoContext.ProductStrLength      = PRODUCT_DESC_LEN;
515   DebugCapabilityContext->DbcInfoContext.SerialNumberStrLength = SERIAL_DESC_LEN;
516 
517   //
518   // Initialize EpOutContext.
519   //
520   DebugCapabilityContext->EpOutContext.CErr             = 0x3;
521   DebugCapabilityContext->EpOutContext.EPType           = ED_BULK_OUT;
522   DebugCapabilityContext->EpOutContext.MaxPacketSize    = XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;
523   DebugCapabilityContext->EpOutContext.AverageTRBLength = 0x1000;
524 
525   //
526   // Initialize EpInContext.
527   //
528   DebugCapabilityContext->EpInContext.CErr             = 0x3;
529   DebugCapabilityContext->EpInContext.EPType           = ED_BULK_IN;
530   DebugCapabilityContext->EpInContext.MaxPacketSize    = XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;
531   DebugCapabilityContext->EpInContext.AverageTRBLength = 0x1000;
532 
533   //
534   // Update string descriptor address
535   //
536   String0Desc = (UINT8 *) AllocateAlignBuffer (STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN);
537   ASSERT (String0Desc != NULL);
538   ZeroMem (String0Desc, STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN);
539   CopyMem (String0Desc, mString0Desc, STRING0_DESC_LEN);
540   DebugCapabilityContext->DbcInfoContext.String0DescAddress = (UINT64)(UINTN)String0Desc;
541 
542   ManufacturerStrDesc = String0Desc + STRING0_DESC_LEN;
543   CopyMem (ManufacturerStrDesc, mManufacturerStrDesc, MANU_DESC_LEN);
544   DebugCapabilityContext->DbcInfoContext.ManufacturerStrDescAddress = (UINT64)(UINTN)ManufacturerStrDesc;
545 
546   ProductStrDesc = ManufacturerStrDesc + MANU_DESC_LEN;
547   CopyMem (ProductStrDesc, mProductStrDesc, PRODUCT_DESC_LEN);
548   DebugCapabilityContext->DbcInfoContext.ProductStrDescAddress = (UINT64)(UINTN)ProductStrDesc;
549 
550   SerialNumberStrDesc = ProductStrDesc + PRODUCT_DESC_LEN;
551   CopyMem (SerialNumberStrDesc, mSerialNumberStrDesc, SERIAL_DESC_LEN);
552   DebugCapabilityContext->DbcInfoContext.SerialNumberStrDescAddress = (UINT64)(UINTN)SerialNumberStrDesc;
553 
554   //
555   // Allocate and initialize the Transfer Ring for the Input Endpoint Context.
556   //
557   ZeroMem (&Handle->TransferRingIn, sizeof (TRANSFER_RING));
558   CreateTransferRing (Handle, TR_RING_TRB_NUMBER, &Handle->TransferRingIn);
559   DebugCapabilityContext->EpInContext.PtrLo = XHC_LOW_32BIT (Handle->TransferRingIn.RingSeg0) | BIT0;
560   DebugCapabilityContext->EpInContext.PtrHi = XHC_HIGH_32BIT (Handle->TransferRingIn.RingSeg0);
561 
562   //
563   // Allocate and initialize the Transfer Ring for the Output Endpoint Context.
564   //
565   ZeroMem (&Handle->TransferRingOut, sizeof (TRANSFER_RING));
566   CreateTransferRing (Handle, TR_RING_TRB_NUMBER, &Handle->TransferRingOut);
567   DebugCapabilityContext->EpOutContext.PtrLo = XHC_LOW_32BIT (Handle->TransferRingOut.RingSeg0) | BIT0;
568   DebugCapabilityContext->EpOutContext.PtrHi = XHC_HIGH_32BIT (Handle->TransferRingOut.RingSeg0);
569 
570   //
571   // Program the Debug Capability Context Pointer (DCCP) register(7.6.8.7)
572   //
573   XhcWriteDebugReg (
574     Handle,
575     XHC_DC_DCCP,
576     XHC_LOW_32BIT((UINT64)(UINTN)DebugCapabilityContext)
577     );
578   XhcWriteDebugReg (
579     Handle,
580     XHC_DC_DCCP + 4,
581     XHC_HIGH_32BIT((UINT64)(UINTN)DebugCapabilityContext)
582     );
583   return EFI_SUCCESS;
584 }
585 
586 /**
587   Check if debug device is running.
588 
589   @param  Handle       Debug port handle.
590 
591 **/
592 VOID
XhcDetectDebugCapabilityReady(IN USB3_DEBUG_PORT_HANDLE * Handle)593 XhcDetectDebugCapabilityReady (
594   IN USB3_DEBUG_PORT_HANDLE *Handle
595   )
596 {
597   UINT64                          TimeOut;
598   volatile UINT32                 Dcctrl;
599 
600   TimeOut = 1;
601   if (Handle->Initialized == USB3DBG_DBG_CAB) {
602     //
603     // As detection is slow in seconds, wait for longer timeout for the first time.
604     // If first initialization is failed, we will try to enable debug device in the
605     // Poll function invoked by timer.
606     //
607     TimeOut = DivU64x32 (PcdGet64 (PcdUsbXhciDebugDetectTimeout), XHC_POLL_DELAY) + 1;
608   }
609 
610   do {
611     //
612     // Check if debug device is in configured state
613     //
614     Dcctrl = XhcReadDebugReg (Handle, XHC_DC_DCCTRL);
615     if ((Dcctrl & BIT0) != 0) {
616       //
617       // Set the flag to indicate debug device is in configured state
618       //
619       Handle->Ready = TRUE;
620       break;
621     }
622     MicroSecondDelay (XHC_POLL_DELAY);
623     TimeOut--;
624   } while (TimeOut != 0);
625 }
626 
627 /**
628   Initialize usb debug port hardware.
629 
630   @param  Handle           Debug port handle.
631 
632   @retval TRUE             The usb debug port hardware configuration is changed.
633   @retval FALSE            The usb debug port hardware configuration is not changed.
634 
635 **/
636 RETURN_STATUS
637 EFIAPI
InitializeUsbDebugHardware(IN USB3_DEBUG_PORT_HANDLE * Handle)638 InitializeUsbDebugHardware (
639   IN USB3_DEBUG_PORT_HANDLE *Handle
640   )
641 {
642   RETURN_STATUS                   Status;
643   UINT8                           *Buffer;
644   UINTN                           Index;
645   UINT8                           TotalUsb3Port;
646   EFI_PHYSICAL_ADDRESS            XhciOpRegister;
647 
648   XhciOpRegister = Handle->XhciOpRegister;
649   TotalUsb3Port = MmioRead32 (((UINTN) Handle->XhciMmioBase + XHC_HCSPARAMS1_OFFSET)) >> 24;
650 
651   if (Handle->Initialized == USB3DBG_NOT_ENABLED) {
652     //
653     // If XHCI supports debug capability, hardware resource has been allocated,
654     // but it has not been enabled, try to enable again.
655     //
656     goto Enable;
657   }
658 
659   //
660   // Initialize for PEI phase when AllocatePages can work.
661   // Allocate data buffer with max packet size for data read and data poll.
662   // Allocate data buffer for data write.
663   //
664   Buffer = AllocateAlignBuffer (XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE * 2 + USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE);
665   if (Buffer == NULL) {
666     //
667     // AllocatePages can not still work now, return fail and do not initialize now.
668     //
669     return RETURN_NOT_READY;
670   }
671 
672   //
673   // Reset port to get debug device discovered
674   //
675   for (Index = 0; Index < TotalUsb3Port; Index++) {
676     XhcSetR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT4);
677     MicroSecondDelay (10 * 1000);
678   }
679 
680   //
681   // Construct the buffer for read, poll and write.
682   //
683   Handle->UrbIn.Data  = (EFI_PHYSICAL_ADDRESS)(UINTN) Buffer;
684   Handle->Data        = (EFI_PHYSICAL_ADDRESS)(UINTN) Buffer + XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;
685   Handle->UrbOut.Data = Handle->UrbIn.Data + XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE * 2;
686 
687   //
688   // Initialize event ring
689   //
690   ZeroMem (&Handle->EventRing, sizeof (EVENT_RING));
691   Status = CreateEventRing (Handle, &Handle->EventRing);
692   ASSERT_EFI_ERROR (Status);
693 
694   //
695   // Init IN and OUT endpoint context
696   //
697   Status = CreateDebugCapabilityContext (Handle);
698   ASSERT_EFI_ERROR (Status);
699 
700   //
701   // Init DCDDI1 and DCDDI2
702   //
703   XhcWriteDebugReg (
704    Handle,
705    XHC_DC_DCDDI1,
706    (UINT32)((XHCI_DEBUG_DEVICE_VENDOR_ID << 16) | XHCI_DEBUG_DEVICE_PROTOCOL)
707    );
708 
709   XhcWriteDebugReg (
710    Handle,
711    XHC_DC_DCDDI2,
712    (UINT32)((XHCI_DEBUG_DEVICE_REVISION << 16) | XHCI_DEBUG_DEVICE_PRODUCT_ID)
713    );
714 
715 Enable:
716   if ((Handle->Initialized == USB3DBG_NOT_ENABLED) && (!Handle->ChangePortPower)) {
717     //
718     // If the first time detection is failed, turn port power off and on in order to
719     // reset port status this time, then try to check if debug device is ready again.
720     //
721     for (Index = 0; Index < TotalUsb3Port; Index++) {
722       XhcClearR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT9);
723       MicroSecondDelay (XHC_DEBUG_PORT_ON_OFF_DELAY);
724       XhcSetR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT9);
725       MicroSecondDelay (XHC_DEBUG_PORT_ON_OFF_DELAY);
726       Handle->ChangePortPower = TRUE;
727     }
728   }
729 
730   //
731   // Set DCE bit and LSE bit to "1" in DCCTRL in first initialization
732   //
733   XhcSetDebugRegBit (Handle, XHC_DC_DCCTRL, BIT1|BIT31);
734 
735   XhcDetectDebugCapabilityReady (Handle);
736 
737   Status = RETURN_SUCCESS;
738   if (!Handle->Ready) {
739     Handle->Initialized = USB3DBG_NOT_ENABLED;
740     Status = RETURN_NOT_READY;
741   } else {
742     Handle->Initialized = USB3DBG_ENABLED;
743   }
744 
745   return Status;
746 }
747 
748 /**
749   Read data from debug device and save the data in buffer.
750 
751   Reads NumberOfBytes data bytes from a debug device into the buffer
752   specified by Buffer. The number of bytes actually read is returned.
753   If the return value is less than NumberOfBytes, then the rest operation failed.
754   If NumberOfBytes is zero, then return 0.
755 
756   @param  Handle           Debug port handle.
757   @param  Buffer           Pointer to the data buffer to store the data read from the debug device.
758   @param  NumberOfBytes    Number of bytes which will be read.
759   @param  Timeout          Timeout value for reading from debug device. It unit is Microsecond.
760 
761   @retval 0                Read data failed, no data is to be read.
762   @retval >0               Actual number of bytes read from debug device.
763 
764 **/
765 UINTN
766 EFIAPI
DebugPortReadBuffer(IN DEBUG_PORT_HANDLE Handle,IN UINT8 * Buffer,IN UINTN NumberOfBytes,IN UINTN Timeout)767 DebugPortReadBuffer (
768   IN   DEBUG_PORT_HANDLE        Handle,
769   IN   UINT8                    *Buffer,
770   IN   UINTN                    NumberOfBytes,
771   IN   UINTN                    Timeout
772   )
773 {
774   USB3_DEBUG_PORT_HANDLE    *UsbDebugPortHandle;
775   RETURN_STATUS             Status;
776   UINT8                     Index;
777   UINT8                     *Data;
778 
779   if (NumberOfBytes != 1 || Buffer == NULL || Timeout != 0) {
780     return 0;
781   }
782 
783   //
784   // If Handle is NULL, it means memory is ready for use.
785   // Use global variable to store handle value.
786   //
787   if (Handle == NULL) {
788     UsbDebugPortHandle = &mDebugCommunicationLibUsb3DebugPortHandle;
789   } else {
790     UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *)Handle;
791   }
792 
793   if (UsbDebugPortHandle->Initialized == USB3DBG_NO_DBG_CAB) {
794     return 0;
795   }
796 
797   if (NeedReinitializeHardware(UsbDebugPortHandle)) {
798     Status = InitializeUsbDebugHardware (UsbDebugPortHandle);
799     if (RETURN_ERROR(Status)) {
800       return 0;
801     }
802   }
803 
804   Data = (UINT8 *)(UINTN)UsbDebugPortHandle->Data;
805 
806   //
807   // Read data from buffer
808   //
809   if (UsbDebugPortHandle->DataCount < 1) {
810     return 0;
811   } else {
812     *Buffer = Data[0];
813 
814     for (Index = 0; Index < UsbDebugPortHandle->DataCount - 1; Index++) {
815       if ((Index + 1) >= XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE) {
816         return 0;
817       }
818       Data[Index] = Data[Index + 1];
819     }
820     UsbDebugPortHandle->DataCount = (UINT8)(UsbDebugPortHandle->DataCount - 1);
821     return 1;
822   }
823 }
824 
825 /**
826   Write data from buffer to debug device.
827 
828   Writes NumberOfBytes data bytes from Buffer to the debug device.
829   The number of bytes actually written to the debug device is returned.
830   If the return value is less than NumberOfBytes, then the write operation failed.
831   If NumberOfBytes is zero, then return 0.
832 
833   @param  Handle           Debug port handle.
834   @param  Buffer           Pointer to the data buffer to be written.
835   @param  NumberOfBytes    Number of bytes to written to the debug device.
836 
837   @retval 0                NumberOfBytes is 0.
838   @retval >0               The number of bytes written to the debug device.
839                            If this value is less than NumberOfBytes, then the read operation failed.
840 
841 **/
842 UINTN
843 EFIAPI
DebugPortWriteBuffer(IN DEBUG_PORT_HANDLE Handle,IN UINT8 * Buffer,IN UINTN NumberOfBytes)844 DebugPortWriteBuffer (
845   IN   DEBUG_PORT_HANDLE    Handle,
846   IN   UINT8                *Buffer,
847   IN   UINTN                NumberOfBytes
848   )
849 {
850   USB3_DEBUG_PORT_HANDLE    *UsbDebugPortHandle;
851   RETURN_STATUS             Status;
852   UINTN                     Sent;
853   UINTN                     Total;
854   EFI_PHYSICAL_ADDRESS      XhciMmioBase;
855   UINTN                     Index;
856 
857   if (NumberOfBytes == 0 || Buffer == NULL) {
858     return 0;
859   }
860 
861   Sent  = 0;
862   Total = 0;
863 
864   //
865   // If Handle is NULL, it means memory is ready for use.
866   // Use global variable to store handle value.
867   //
868   if (Handle == NULL) {
869     UsbDebugPortHandle = &mDebugCommunicationLibUsb3DebugPortHandle;
870   } else {
871     UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *)Handle;
872   }
873 
874   if (UsbDebugPortHandle->Initialized == USB3DBG_NO_DBG_CAB) {
875     return 0;
876   }
877 
878   //
879   // MMIO base address is possible to clear, set it if it is cleared. (XhciMemorySpaceClose in PchUsbCommon.c)
880   //
881   XhciMmioBase = ProgramXhciBaseAddress ();
882 
883   UpdateXhcResource (UsbDebugPortHandle, XhciMmioBase);
884 
885   if (NeedReinitializeHardware(UsbDebugPortHandle)) {
886     Status = InitializeUsbDebugHardware (UsbDebugPortHandle);
887     if (RETURN_ERROR(Status)) {
888       return 0;
889     }
890   }
891 
892   //
893   // When host is trying to send data, write will be blocked.
894   // Poll to see if there is any data sent by host at first.
895   //
896   DebugPortPollBuffer (Handle);
897 
898   Index = 0;
899   while ((Total < NumberOfBytes)) {
900     if (NumberOfBytes - Total > USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE) {
901       Sent = USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE;
902     } else {
903       Sent = (UINT8)(NumberOfBytes - Total);
904     }
905     Status = XhcDataTransfer (UsbDebugPortHandle, EfiUsbDataOut, Buffer + Total, &Sent, DATA_TRANSFER_WRITE_TIMEOUT);
906     Total += Sent;
907   }
908 
909   return Total;
910 }
911 
912 /**
913   Polls a debug device to see if there is any data waiting to be read.
914 
915   Polls a debug device to see if there is any data waiting to be read.
916   If there is data waiting to be read from the debug device, then TRUE is returned.
917   If there is no data waiting to be read from the debug device, then FALSE is returned.
918 
919   @param  Handle           Debug port handle.
920 
921   @retval TRUE             Data is waiting to be read from the debug device.
922   @retval FALSE            There is no data waiting to be read from the serial device.
923 
924 **/
925 BOOLEAN
926 EFIAPI
DebugPortPollBuffer(IN DEBUG_PORT_HANDLE Handle)927 DebugPortPollBuffer (
928   IN DEBUG_PORT_HANDLE      Handle
929   )
930 {
931   USB3_DEBUG_PORT_HANDLE     *UsbDebugPortHandle;
932   UINTN                     Length;
933   RETURN_STATUS             Status;
934   EFI_PHYSICAL_ADDRESS      XhciMmioBase;
935 
936   //
937   // If Handle is NULL, it means memory is ready for use.
938   // Use global variable to store handle value.
939   //
940   if (Handle == NULL) {
941     UsbDebugPortHandle = &mDebugCommunicationLibUsb3DebugPortHandle;
942   } else {
943     UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *)Handle;
944   }
945 
946   if (UsbDebugPortHandle->Initialized == USB3DBG_NO_DBG_CAB) {
947     return 0;
948   }
949 
950   XhciMmioBase = ProgramXhciBaseAddress ();
951   UpdateXhcResource (UsbDebugPortHandle, XhciMmioBase);
952 
953   if (NeedReinitializeHardware(UsbDebugPortHandle)) {
954     Status = InitializeUsbDebugHardware(UsbDebugPortHandle);
955     if (RETURN_ERROR(Status)) {
956       return FALSE;
957     }
958   }
959 
960   //
961   // If the data buffer is not empty, then return TRUE directly.
962   // Otherwise initialize a usb read transaction and read data to internal data buffer.
963   //
964   if (UsbDebugPortHandle->DataCount != 0) {
965     return TRUE;
966   }
967 
968   //
969   // Read data as much as we can
970   //
971   Length = XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;
972   XhcDataTransfer (Handle, EfiUsbDataIn, (VOID *)(UINTN)UsbDebugPortHandle->Data, &Length, DATA_TRANSFER_POLL_TIMEOUT);
973 
974   if (Length > XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE) {
975     return FALSE;
976   }
977 
978   if (Length == 0) {
979     return FALSE;
980   }
981 
982   //
983   // Store data into internal buffer for use later
984   //
985   UsbDebugPortHandle->DataCount = (UINT8) Length;
986   return TRUE;
987 }
988 
989 /**
990   Initialize the debug port.
991 
992   If Function is not NULL, Debug Communication Libary will call this function
993   by passing in the Context to be the first parameter. If needed, Debug Communication
994   Library will create one debug port handle to be the second argument passing in
995   calling the Function, otherwise it will pass NULL to be the second argument of
996   Function.
997 
998   If Function is NULL, and Context is not NULL, the Debug Communication Library could
999     a) Return the same handle as passed in (as Context parameter).
1000     b) Ignore the input Context parameter and create new hanlde to be returned.
1001 
1002   If parameter Function is NULL and Context is NULL, Debug Communication Library could
1003   created a new handle if needed and return it, otherwise it will return NULL.
1004 
1005   @param[in] Context      Context needed by callback function; it was optional.
1006   @param[in] Function     Continue function called by Debug Communication library;
1007                           it was optional.
1008 
1009   @return  The debug port handle created by Debug Communication Library if Function
1010            is not NULL.
1011 
1012 **/
1013 DEBUG_PORT_HANDLE
1014 EFIAPI
DebugPortInitialize(IN VOID * Context,IN DEBUG_PORT_CONTINUE Function)1015 DebugPortInitialize (
1016   IN VOID                 *Context,
1017   IN DEBUG_PORT_CONTINUE  Function
1018   )
1019 {
1020   RETURN_STATUS             Status;
1021   USB3_DEBUG_PORT_HANDLE    Handle;
1022   USB3_DEBUG_PORT_HANDLE    *UsbDebugPortHandle;
1023 
1024   //
1025   // Validate the PCD PcdDebugPortHandleBufferSize value
1026   //
1027   ASSERT (PcdGet16 (PcdDebugPortHandleBufferSize) == sizeof (USB3_DEBUG_PORT_HANDLE));
1028 
1029   if (Function == NULL && Context != NULL) {
1030     UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *)Context;
1031   } else {
1032     ZeroMem(&Handle, sizeof (USB3_DEBUG_PORT_HANDLE));
1033     UsbDebugPortHandle = &Handle;
1034   }
1035 
1036   if (Function == NULL && Context != NULL) {
1037     return (DEBUG_PORT_HANDLE *) Context;
1038   }
1039 
1040   //
1041   // Read 64-bit MMIO base address
1042   //
1043   UsbDebugPortHandle->XhciMmioBase = ProgramXhciBaseAddress ();
1044 
1045   Status = CalculateUsbDebugPortMmioBase (UsbDebugPortHandle);
1046   if (RETURN_ERROR (Status)) {
1047     goto Exit;
1048   }
1049 
1050   if (NeedReinitializeHardware(&Handle)) {
1051     Status = InitializeUsbDebugHardware (&Handle);
1052     if (RETURN_ERROR(Status)) {
1053       goto Exit;
1054     }
1055   }
1056 
1057 Exit:
1058 
1059   if (Function != NULL) {
1060     Function (Context, &Handle);
1061   } else {
1062     CopyMem(&mDebugCommunicationLibUsb3DebugPortHandle, &Handle, sizeof (USB3_DEBUG_PORT_HANDLE));
1063   }
1064 
1065   return (DEBUG_PORT_HANDLE)(UINTN)&mDebugCommunicationLibUsb3DebugPortHandle;
1066 }
1067