]> git.proxmox.com Git - mirror_edk2.git/blame - SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.c
ArmPkg/CompilerIntrinsicsLib: Reverse the order of the 'ldrb' instructions in __aeabi...
[mirror_edk2.git] / SourceLevelDebugPkg / Library / DebugCommunicationLibUsb / DebugCommunicationLibUsb.c
CommitLineData
18b144ea 1/** @file\r
2 Debug Port Library implementation based on usb debug port.\r
3\r
83283ef1 4 Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>\r
18b144ea 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 <Base.h>\r
16#include <IndustryStandard/Pci.h>\r
17#include <IndustryStandard/Usb.h>\r
18#include <Library/IoLib.h>\r
19#include <Library/PciLib.h>\r
20#include <Library/PcdLib.h>\r
21#include <Library/TimerLib.h>\r
22#include <Library/DebugCommunicationLib.h>\r
23#include <Library/BaseMemoryLib.h>\r
24#include <Library/BaseLib.h>\r
25\r
26#define SETUP_PID 0x2D\r
27#define INPUT_PID 0x69\r
28#define OUTPUT_PID 0xE1\r
29#define ERROR_PID 0x55\r
30#define DATA0_PID 0xC3\r
31#define DATA1_PID 0x4B\r
32#define DATA2_PID 0x87\r
33#define MDATA_PID 0x0F\r
34#define ACK_PID 0xD2\r
35#define NAK_PID 0x5A\r
36#define STALL_PID 0x1E\r
37#define NYET_PID 0x96\r
38\r
39#define PCI_CAPABILITY_ID_DEBUG_PORT 0x0A\r
40#define USB_DEBUG_PORT_MAX_PACKET_SIZE 0x08\r
41\r
42#define USB_DEBUG_PORT_IN_USE BIT10\r
43#define USB_DEBUG_PORT_ENABLE BIT28\r
44#define USB_DEBUG_PORT_OWNER BIT30\r
45\r
46#define USB_PORT_LINE_STATUS_LS 0x400\r
47#define USB_PORT_LINE_STATUS_MASK 0xC00\r
48\r
49//\r
50// Usb debug device descriptor, which is defined at\r
51// USB2 Debug Device Specification.\r
52//\r
53typedef struct _USB_DEBUG_PORT_DESCRIPTOR {\r
54 UINT8 Length;\r
55 UINT8 DescriptorType;\r
56 UINT8 DebugInEndpoint;\r
57 UINT8 DebugOutEndpoint;\r
58}USB_DEBUG_PORT_DESCRIPTOR;\r
59\r
60USB_DEVICE_REQUEST mGetDebugDescriptor = {\r
61 0x80,\r
62 USB_REQ_GET_DESCRIPTOR,\r
63 (UINT16)(0x0A << 8),\r
64 0x0000,\r
65 sizeof(USB_DEBUG_PORT_DESCRIPTOR)\r
66 };\r
67\r
68USB_DEVICE_REQUEST mSetDebugFeature = {\r
69 0x0,\r
70 USB_REQ_SET_FEATURE,\r
71 (UINT16)(0x06),\r
72 0x0000,\r
73 0x0\r
74 };\r
75\r
76USB_DEVICE_REQUEST mSetDebugAddress = {\r
77 0x0,\r
78 USB_REQ_SET_ADDRESS,\r
79 (UINT16)(0x7F),\r
80 0x0000,\r
81 0x0\r
82 };\r
83\r
84//\r
85// Usb debug port register file, which is defined at\r
86// EHCI Specification.\r
87//\r
88typedef struct _USB_DEBUG_PORT_REGISTER {\r
89 UINT32 ControlStatus;\r
90 UINT8 TokenPid;\r
91 UINT8 SendPid;\r
92 UINT8 ReceivedPid;\r
93 UINT8 Reserved1;\r
94 UINT8 DataBuffer[8];\r
95 UINT8 UsbEndPoint;\r
96 UINT8 UsbAddress;\r
97 UINT8 Reserved2;\r
98 UINT8 Reserved3;\r
99}USB_DEBUG_PORT_REGISTER;\r
100\r
101#pragma pack(1)\r
102//\r
103// The internal data structure of DEBUG_PORT_HANDLE, which stores some\r
104// important datum which are used across various phases.\r
105//\r
106typedef struct _USB_DEBUG_PORT_HANDLE{\r
107 //\r
108 // The usb debug port memory BAR number in EHCI configuration space.\r
109 //\r
110 UINT8 DebugPortBarNumber;\r
111 UINT8 Reserved;\r
112 //\r
113 // The offset of usb debug port registers in EHCI memory range.\r
114 //\r
115 UINT16 DebugPortOffset;\r
116 //\r
117 // The usb debug port memory BAR address.\r
118 //\r
119 UINTN UsbDebugPortMemoryBase;\r
120 //\r
121 // The EHCI memory BAR address.\r
122 //\r
123 UINTN EhciMemoryBase;\r
124 //\r
125 // The Bulk In endpoint toggle bit.\r
126 //\r
127 UINT8 BulkInToggle;\r
128 //\r
129 // The Bulk Out endpoint toggle bit.\r
130 //\r
131 UINT8 BulkOutToggle;\r
132 //\r
133 // The available data length in the following data buffer.\r
134 //\r
135 UINT8 DataCount;\r
136 //\r
137 // The data buffer. Maximum length is 8 bytes.\r
138 //\r
139 UINT8 Data[8];\r
140} USB_DEBUG_PORT_HANDLE;\r
141#pragma pack()\r
142\r
143//\r
144// The global variable which can be used after memory is ready.\r
145//\r
146USB_DEBUG_PORT_HANDLE mUsbDebugPortHandle;\r
147\r
148/**\r
149 Calculate the usb debug port bar address.\r
150\r
151 @param DebugPortOffset Get usb debug port offset in the usb debug port memory space.\r
152 @param DebugPortBarNumbar Get the bar number at which usb debug port is located.\r
153\r
154 @retval RETURN_UNSUPPORTED The usb host controller does not supported usb debug port capability.\r
155 @retval RETURN_SUCCESS Get bar and offset successfully.\r
156\r
157**/\r
158RETURN_STATUS\r
159EFIAPI\r
160CalculateUsbDebugPortBar (\r
161 OUT UINT16 *DebugPortOffset,\r
162 OUT UINT8 *DebugPortBarNumbar\r
163 )\r
164{\r
165 UINT16 PciStatus;\r
166 UINT8 CapabilityPtr;\r
167 UINT8 CapabilityId;\r
168\r
169 //\r
170 // Enable Ehci Host Controller MMIO Space.\r
171 //\r
172 PciStatus = PciRead16 (PcdGet32(PcdUsbEhciPciAddress) + PCI_PRIMARY_STATUS_OFFSET);\r
173\r
174 if ((PciStatus & EFI_PCI_STATUS_CAPABILITY) == 0) {\r
175 //\r
176 // The Pci Device Doesn't Support Capability Pointer.\r
177 //\r
178 return RETURN_UNSUPPORTED;\r
179 }\r
180\r
181 //\r
182 // Get Pointer To Capability List\r
183 //\r
184 CapabilityPtr = PciRead8(PcdGet32(PcdUsbEhciPciAddress) + PCI_CAPBILITY_POINTER_OFFSET);\r
185\r
186 //\r
187 // Find Capability ID 0xA, Which Is For Debug Port\r
188 //\r
189 while (CapabilityPtr != 0) {\r
190 CapabilityId = PciRead8(PcdGet32(PcdUsbEhciPciAddress) + CapabilityPtr);\r
191 if (CapabilityId == PCI_CAPABILITY_ID_DEBUG_PORT) {\r
192 break;\r
193 }\r
194 CapabilityPtr = PciRead8(PcdGet32(PcdUsbEhciPciAddress) + CapabilityPtr + 1);\r
195 }\r
196\r
197 //\r
198 // No Debug Port Capability Found\r
199 //\r
200 if (CapabilityPtr == 0) {\r
201 return RETURN_UNSUPPORTED;\r
202 }\r
203\r
204 //\r
205 // Get The Base Address Of Debug Port Register In Debug Port Capability Register\r
206 //\r
207 *DebugPortOffset = (UINT16)(PciRead16(PcdGet32(PcdUsbEhciPciAddress) + CapabilityPtr + 2) & 0x1FFF);\r
208 *DebugPortBarNumbar = (UINT8)((PciRead16(PcdGet32(PcdUsbEhciPciAddress) + CapabilityPtr + 2) >> 13) - 1);\r
209\r
210 return RETURN_SUCCESS;\r
211}\r
212\r
213/**\r
214 Do a usb IN transaction by usb debug port.\r
215\r
216 @param DebugPortRegister Pointer to the base address of usb debug port register interface.\r
217 @param Buffer Pointer to the buffer receiving data.\r
218 @param Length Number of bytes of the received data.\r
219 @param Token The token PID for each USB transaction.\r
220 @param Addr The usb device address for usb transaction.\r
221 @param Ep The endpoint for usb transaction.\r
222 @param DataToggle The toggle bit used at usb transaction.\r
223\r
224 @retval RETURN_SUCCESS The IN transaction is executed successfully.\r
225 @retval RETURN_INVALID_PARAMETER The parameters passed in are invalid.\r
226 @retval RETURN_DEVICE_ERROR The IN transaction comes across error.\r
227\r
228**/\r
229RETURN_STATUS\r
230EFIAPI\r
231UsbDebugPortIn (\r
232 IN USB_DEBUG_PORT_REGISTER *DebugPortRegister,\r
233 IN OUT UINT8 *Buffer,\r
234 OUT UINT8 *Length,\r
235 IN UINT8 Token,\r
236 IN UINT8 Addr,\r
237 IN UINT8 Ep,\r
238 IN UINT8 DataToggle\r
239 )\r
240{\r
241 UINTN Index;\r
242\r
243 if (Length == NULL) {\r
244 return RETURN_INVALID_PARAMETER;\r
245 }\r
246 *Length = 0;\r
247\r
248 DebugPortRegister->TokenPid = Token;\r
249 if (DataToggle != 0) {\r
250 DebugPortRegister->SendPid = DATA1_PID;\r
251 } else {\r
252 DebugPortRegister->SendPid = DATA0_PID;\r
253 }\r
254\r
255 DebugPortRegister->UsbAddress = (UINT8)(Addr & 0x7F);\r
256 DebugPortRegister->UsbEndPoint = (UINT8)(Ep & 0xF);\r
257\r
258 //\r
259 // Clearing W/R bit to indicate it's a READ operation\r
260 //\r
261 MmioAnd32((UINTN)&DebugPortRegister->ControlStatus, (UINT32)~BIT4);\r
262\r
263 //\r
264 // Setting GO bit as well as clearing DONE bit\r
265 //\r
266 MmioOr32((UINTN)&DebugPortRegister->ControlStatus, (UINT32)BIT5);\r
267\r
268 //\r
269 // Wait for completing the request\r
270 //\r
271 while ((MmioRead32((UINTN)&DebugPortRegister->ControlStatus) & (UINT32)BIT16) == 0);\r
272\r
273 //\r
274 // Check if the request is executed successfully or not.\r
275 //\r
276 if ((MmioRead32((UINTN)&DebugPortRegister->ControlStatus)) & BIT6) {\r
277 return RETURN_DEVICE_ERROR;\r
278 }\r
279\r
280 //\r
281 // Make sure the received data are not beyond the allowable maximum length - 8 byte\r
282 //\r
283 if (((MmioRead32((UINTN)&DebugPortRegister->ControlStatus)) & 0xF) > USB_DEBUG_PORT_MAX_PACKET_SIZE) {\r
284 return RETURN_DEVICE_ERROR;\r
285 }\r
286\r
287 *Length = (UINT8)(MmioRead32((UINTN)&DebugPortRegister->ControlStatus) & 0xF);\r
ec99fa8e 288 if (*Length > 8) {\r
289 return RETURN_DEVICE_ERROR;\r
290 }\r
291\r
18b144ea 292 for (Index = 0; Index < *Length; Index++) {\r
293 Buffer[Index] = DebugPortRegister->DataBuffer[Index];\r
294 }\r
295 return RETURN_SUCCESS;\r
296}\r
297\r
298/**\r
299 Do a usb SETUP/OUT transaction by usb debug port.\r
300\r
301 @param DebugPortRegister Pointer to the base address of usb debug port register interface.\r
302 @param Buffer Pointer to the buffer receiving data.\r
303 @param Length Number of bytes of the received data.\r
304 @param Token The token PID for each USB transaction.\r
305 @param Addr The usb device address for usb transaction.\r
306 @param Ep The endpoint for usb transaction.\r
307 @param DataToggle The toggle bit used at usb transaction.\r
308\r
309 @retval RETURN_SUCCESS The IN transaction is executed successfully.\r
310 @retval RETURN_INVALID_PARAMETER The parameters passed in are invalid.\r
311 @retval RETURN_DEVICE_ERROR The IN transaction comes across error.\r
312\r
313**/\r
314RETURN_STATUS\r
315EFIAPI\r
316UsbDebugPortOut (\r
317 IN USB_DEBUG_PORT_REGISTER *DebugPortRegister,\r
318 IN UINT8 *Buffer,\r
319 IN UINT8 Length,\r
320 IN UINT8 Token,\r
321 IN UINT8 Addr,\r
322 IN UINT8 Ep,\r
323 IN UINT8 DataToggle\r
324 )\r
325{\r
326 UINT8 Index;\r
327\r
328 if (Length > 8) {\r
329 return RETURN_INVALID_PARAMETER;\r
330 }\r
331\r
332 DebugPortRegister->TokenPid = Token;\r
333 if (DataToggle != 0) {\r
334 DebugPortRegister->SendPid = DATA1_PID;\r
335 } else {\r
336 DebugPortRegister->SendPid = DATA0_PID;\r
337 }\r
338 DebugPortRegister->UsbAddress = (UINT8)(Addr & 0x7F);\r
339 DebugPortRegister->UsbEndPoint = (UINT8)(Ep & 0xF);\r
340\r
341 //\r
342 // Fill in the data length and corresponding data.\r
343 //\r
344 MmioAnd32((UINTN)&DebugPortRegister->ControlStatus, (UINT32)~0xF);\r
345 MmioOr32((UINTN)&DebugPortRegister->ControlStatus, Length & 0xF);\r
346 for (Index = 0; Index < Length; Index++) {\r
347 DebugPortRegister->DataBuffer[Index] = Buffer[Index];\r
348 }\r
349\r
350 //\r
351 // Setting W/R bit to indicate it's a WRITE operation\r
352 //\r
353 MmioOr32((UINTN)&DebugPortRegister->ControlStatus, BIT4);\r
354 //\r
355 // Setting GO bit as well as clearing DONE bit\r
356 //\r
357 MmioOr32((UINTN)&DebugPortRegister->ControlStatus, BIT5);\r
358\r
359 //\r
360 // Wait for completing the request\r
361 //\r
362 while ((MmioRead32((UINTN)&DebugPortRegister->ControlStatus) & BIT16) == 0);\r
363\r
364 //\r
365 // Check if the request is executed successfully or not.\r
366 //\r
367 if ((MmioRead32((UINTN)&DebugPortRegister->ControlStatus)) & BIT6) {\r
368 return RETURN_DEVICE_ERROR;\r
369 }\r
370\r
371 //\r
372 // Make sure the sent data are not beyond the allowable maximum length - 8 byte\r
373 //\r
374 if (((MmioRead32((UINTN)&DebugPortRegister->ControlStatus)) & 0xF) > USB_DEBUG_PORT_MAX_PACKET_SIZE) {\r
375 return RETURN_DEVICE_ERROR;\r
376 }\r
377\r
378 return RETURN_SUCCESS;\r
379}\r
380\r
381/**\r
382 Do a usb control transfer by usb debug port.\r
383\r
384 @param DebugPortRegister Pointer to the base address of usb debug port register interface.\r
385 @param SetupPacket The token PID for each USB transaction.\r
386 @param Addr The usb device address for usb transaction.\r
387 @param Ep The endpoint for usb transaction.\r
388 @param Data Pointer to the buffer receiving data.\r
389 @param DataLength Number of bytes of the received data.\r
390\r
391 @retval RETURN_SUCCESS The IN transaction is executed successfully.\r
392 @retval RETURN_INVALID_PARAMETER The parameters passed in are invalid.\r
393 @retval RETURN_DEVICE_ERROR The IN transaction comes across error.\r
394\r
395**/\r
396RETURN_STATUS\r
397EFIAPI\r
398UsbDebugPortControlTransfer (\r
399 IN USB_DEBUG_PORT_REGISTER *DebugPortRegister,\r
400 IN USB_DEVICE_REQUEST *SetupPacket,\r
401 IN UINT8 Addr,\r
402 IN UINT8 Ep,\r
403 OUT UINT8 *Data,\r
404 IN OUT UINT8 *DataLength\r
405 )\r
406{\r
407 RETURN_STATUS Status;\r
408 UINT8 Temp;\r
83283ef1 409 UINT8 ReturnStatus[8];\r
18b144ea 410\r
411 //\r
412 // Setup Phase\r
413 //\r
414 Status = UsbDebugPortOut(DebugPortRegister, (UINT8 *)SetupPacket, (UINT8)sizeof(USB_DEVICE_REQUEST), SETUP_PID, Addr, Ep, 0);\r
415 if (RETURN_ERROR(Status)) {\r
416 return Status;\r
417 }\r
418\r
419 //\r
420 // Data Phase\r
421 //\r
83283ef1 422 if (DataLength != 0) {\r
18b144ea 423 if ((SetupPacket->RequestType & BIT7) != 0) {\r
424 //\r
425 // Get Data From Device\r
426 //\r
427 Status = UsbDebugPortIn(DebugPortRegister, Data, DataLength, INPUT_PID, Addr, Ep, 1);\r
428 if (RETURN_ERROR(Status)) {\r
429 return Status;\r
430 }\r
431 } else {\r
432 //\r
433 // Send Data To Device\r
434 //\r
435 Status = UsbDebugPortOut(DebugPortRegister, Data, *DataLength, OUTPUT_PID, Addr, Ep, 1);\r
436 if (RETURN_ERROR(Status)) {\r
437 return Status;\r
438 }\r
439 }\r
440 }\r
441\r
442 //\r
443 // Status Phase\r
444 //\r
445 if ((SetupPacket->RequestType & BIT7) != 0) {\r
446 //\r
447 // For READ operation, Data Toggle in Status Phase Should be 1.\r
448 //\r
449 Status = UsbDebugPortOut(DebugPortRegister, NULL, 0, OUTPUT_PID, Addr, Ep, 1);\r
450 } else {\r
451 //\r
452 // For WRITE operation, Data Toggle in Status Phase Should be 1.\r
453 //\r
83283ef1 454 Status = UsbDebugPortIn(DebugPortRegister, ReturnStatus, &Temp, INPUT_PID, Addr, Ep, 1);\r
18b144ea 455 }\r
456\r
457 return Status;\r
458}\r
459\r
460/**\r
461 Check if it needs to re-initialize usb debug port hardware.\r
462\r
463 During different phases switch, such as SEC to PEI or PEI to DXE or DXE to SMM, we should check\r
464 whether the usb debug port hardware configuration is changed. Such case can be triggerred by\r
465 Pci bus resource allocation and so on.\r
466\r
467 @param Handle Debug port handle.\r
468\r
469 @retval TRUE The usb debug port hardware configuration is changed.\r
470 @retval FALSE The usb debug port hardware configuration is not changed.\r
471\r
472**/\r
473BOOLEAN\r
474EFIAPI\r
475NeedReinitializeHardware(\r
476 IN USB_DEBUG_PORT_HANDLE *Handle\r
477 )\r
478{\r
479 UINT16 PciCmd;\r
480 UINTN UsbDebugPortMemoryBase;\r
481 UINTN EhciMemoryBase;\r
482 BOOLEAN Status;\r
483 USB_DEBUG_PORT_REGISTER *UsbDebugPortRegister;\r
484\r
485 Status = FALSE;\r
486\r
487 EhciMemoryBase = 0xFFFFFC00 & PciRead32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET);\r
488 if (EhciMemoryBase != Handle->EhciMemoryBase) {\r
489 Handle->EhciMemoryBase = EhciMemoryBase;\r
490 Status = TRUE;\r
491 }\r
492\r
493 UsbDebugPortMemoryBase = 0xFFFFFC00 & PciRead32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + Handle->DebugPortBarNumber * 4);\r
494 if (UsbDebugPortMemoryBase != Handle->UsbDebugPortMemoryBase) {\r
495 Handle->UsbDebugPortMemoryBase = UsbDebugPortMemoryBase;\r
496 Status = TRUE;\r
497 }\r
498\r
499 //\r
500 // Enable Ehci Memory Space Access\r
501 //\r
502 PciCmd = PciRead16 (PcdGet32(PcdUsbEhciPciAddress) + PCI_COMMAND_OFFSET);\r
503 if (((PciCmd & EFI_PCI_COMMAND_MEMORY_SPACE) == 0) || ((PciCmd & EFI_PCI_COMMAND_BUS_MASTER) == 0)) {\r
504 Status = TRUE;\r
505 }\r
506\r
507 //\r
508 // Check if the debug port is enabled and owned by myself.\r
509 //\r
510 UsbDebugPortRegister = (USB_DEBUG_PORT_REGISTER *)(Handle->UsbDebugPortMemoryBase + Handle->DebugPortOffset);\r
511 if ((MmioRead32((UINTN)&UsbDebugPortRegister->ControlStatus) &\r
512 (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_ENABLE | USB_DEBUG_PORT_IN_USE)) == 0) {\r
513 Status = TRUE;\r
514 }\r
515 return Status;\r
516}\r
517\r
518/**\r
519 Initialize usb debug port hardware.\r
520\r
521 1. reset ehci host controller.\r
522 2. set right port to debug port.\r
523 3. find a usb debug device is attached by getting debug device descriptor.\r
524 4. set address for the usb debug device.\r
525 5. configure the usb debug device to debug mode.\r
526\r
527 @param Handle Debug port handle.\r
528\r
529 @retval TRUE The usb debug port hardware configuration is changed.\r
530 @retval FALSE The usb debug port hardware configuration is not changed.\r
531\r
532**/\r
533RETURN_STATUS\r
534EFIAPI\r
535InitializeUsbDebugHardware (\r
536 IN USB_DEBUG_PORT_HANDLE *Handle\r
537)\r
538{\r
539 RETURN_STATUS Status;\r
540 USB_DEBUG_PORT_REGISTER *UsbDebugPortRegister;\r
541 USB_DEBUG_PORT_DESCRIPTOR UsbDebugPortDescriptor;\r
542 UINT16 PciCmd;\r
543 UINT32 *PortStatus;\r
544 UINT32 *UsbCmd;\r
545 UINT32 *UsbStatus;\r
546 UINT32 *UsbHCSParam;\r
547 UINT8 DebugPortNumber;\r
548 UINT8 Length;\r
549\r
550 UsbDebugPortRegister = (USB_DEBUG_PORT_REGISTER *)(Handle->UsbDebugPortMemoryBase + Handle->DebugPortOffset);\r
551 PciCmd = PciRead16 (PcdGet32(PcdUsbEhciPciAddress) + PCI_COMMAND_OFFSET);\r
552 UsbHCSParam = (UINT32 *)(Handle->EhciMemoryBase + 0x04);\r
553 UsbCmd = (UINT32 *)(Handle->EhciMemoryBase + 0x20);\r
554 UsbStatus = (UINT32 *)(Handle->EhciMemoryBase + 0x24);\r
555\r
556 //\r
557 // initialize the data toggle used by bulk in/out endpoint.\r
558 //\r
559 Handle->BulkInToggle = 0;\r
560 Handle->BulkOutToggle = 0;\r
561\r
562 //\r
563 // Enable Ehci Memory Space Access\r
564 //\r
565 if (((PciCmd & EFI_PCI_COMMAND_MEMORY_SPACE) == 0) || ((PciCmd & EFI_PCI_COMMAND_BUS_MASTER) == 0)) {\r
566 PciCmd |= EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER;\r
567 PciWrite16(PcdGet32(PcdUsbEhciPciAddress) + PCI_COMMAND_OFFSET, PciCmd);\r
568 }\r
569\r
570 //\r
571 // If the host controller is not halted, then halt it.\r
572 //\r
573 if ((MmioRead32((UINTN)UsbStatus) & BIT12) == 0) {\r
574 MmioAnd32((UINTN)UsbCmd, (UINT32)~BIT0);\r
575 while ((MmioRead32((UINTN)UsbStatus) & BIT12) == 0);\r
576 }\r
577 //\r
578 // reset the host controller.\r
579 //\r
580 MmioOr32((UINTN)UsbCmd, BIT1);\r
581 //\r
582 // ensure that the host controller is reset.\r
583 //\r
584 while (MmioRead32((UINTN)UsbCmd) & BIT1);\r
585\r
586 //\r
587 // Start the host controller if it's not running\r
588 //\r
589 if (MmioRead32((UINTN)UsbStatus) & BIT12) {\r
590 MmioOr32((UINTN)UsbCmd, BIT0);\r
591 // ensure that the host controller is started (HALTED bit must be cleared)\r
592 while (MmioRead32((UINTN)UsbStatus) & BIT12);\r
593 }\r
594\r
595 //\r
596 // First get the ownership of port 0.\r
597 //\r
598 MmioOr32((UINTN)&UsbDebugPortRegister->ControlStatus, USB_DEBUG_PORT_OWNER);\r
599\r
600 MicroSecondDelay (200000);\r
601\r
602 //\r
603 // Find out which port is used as debug port.\r
604 //\r
605 DebugPortNumber = (UINT8)((MmioRead32((UINTN)UsbHCSParam) & 0x00F00000) >> 20);\r
606 //\r
607 // Should find a non low-speed device is connected\r
608 //\r
609 PortStatus = (UINT32 *)(Handle->EhciMemoryBase + 0x64 + (DebugPortNumber - 1) * 4);\r
610 if (!(MmioRead32((UINTN)PortStatus) & BIT0) || ((MmioRead32((UINTN)PortStatus) & USB_PORT_LINE_STATUS_MASK) == USB_PORT_LINE_STATUS_LS)) {\r
611 return RETURN_NOT_FOUND;\r
612 }\r
613\r
614 //\r
615 // Reset the debug port\r
616 //\r
617 MmioOr32((UINTN)PortStatus, BIT8);\r
618 MicroSecondDelay (200000);\r
619 MmioAnd32((UINTN)PortStatus, (UINT32)~BIT8);\r
620 while (MmioRead32((UINTN)PortStatus) & BIT8);\r
621\r
622 //\r
623 // The port enabled bit should be set by HW.\r
624 //\r
625 if ((MmioRead32((UINTN)PortStatus) & BIT2) == 0) {\r
626 return RETURN_DEVICE_ERROR;\r
627 }\r
628\r
629 //\r
630 // Enable Usb Debug Port Capability\r
631 //\r
632 MmioOr32((UINTN)&UsbDebugPortRegister->ControlStatus, USB_DEBUG_PORT_ENABLE | USB_DEBUG_PORT_IN_USE);\r
633\r
634 //\r
635 // Start to communicate with Usb Debug Device to see if the attached device is usb debug device or not.\r
636 //\r
637 Length = (UINT8)sizeof (USB_DEBUG_PORT_DESCRIPTOR);\r
638\r
639 //\r
640 // It's not a dedicated usb debug device, should use address 0 to get debug descriptor.\r
641 //\r
642 Status = UsbDebugPortControlTransfer (UsbDebugPortRegister, &mGetDebugDescriptor, 0x0, 0x0, (UINT8*)&UsbDebugPortDescriptor, &Length);\r
643 if (RETURN_ERROR(Status)) {\r
644 //\r
645 // The device is not a usb debug device.\r
646 //\r
647 return Status;\r
648 }\r
ec99fa8e 649\r
650 if (Length != sizeof(USB_DEBUG_PORT_DESCRIPTOR)) {\r
651 return RETURN_DEVICE_ERROR;\r
652 }\r
653\r
18b144ea 654 //\r
655 // set usb debug device address as 0x7F.\r
656 //\r
83283ef1 657 Status = UsbDebugPortControlTransfer (UsbDebugPortRegister, &mSetDebugAddress, 0x0, 0x0, NULL, NULL);\r
18b144ea 658 if (RETURN_ERROR(Status)) {\r
659 //\r
660 // The device can not work well.\r
661 //\r
662 return Status;\r
663 }\r
664\r
665 //\r
666 // enable the usb debug feature.\r
667 //\r
668 Status = UsbDebugPortControlTransfer (UsbDebugPortRegister, &mSetDebugFeature, 0x7F, 0x0, NULL, NULL);\r
669\r
670 return Status;\r
671}\r
672\r
673/**\r
674 Read data from debug device and save the datas in buffer.\r
675\r
676 Reads NumberOfBytes data bytes from a debug device into the buffer\r
677 specified by Buffer. The number of bytes actually read is returned.\r
678 If the return value is less than NumberOfBytes, then the rest operation failed.\r
679 If NumberOfBytes is zero, then return 0.\r
680\r
681 @param Handle Debug port handle.\r
682 @param Buffer Pointer to the data buffer to store the data read from the debug device.\r
683 @param NumberOfBytes Number of bytes which will be read.\r
684 @param Timeout Timeout value for reading from debug device. It unit is Microsecond.\r
685\r
686 @retval 0 Read data failed, no data is to be read.\r
687 @retval >0 Actual number of bytes read from debug device.\r
688\r
689**/\r
690UINTN\r
691EFIAPI\r
692DebugPortReadBuffer (\r
693 IN DEBUG_PORT_HANDLE Handle,\r
694 IN UINT8 *Buffer,\r
695 IN UINTN NumberOfBytes,\r
696 IN UINTN Timeout\r
697 )\r
698{\r
699 USB_DEBUG_PORT_HANDLE *UsbDebugPortHandle;\r
700 USB_DEBUG_PORT_REGISTER *UsbDebugPortRegister;\r
701 RETURN_STATUS Status;\r
702 UINT8 Received;\r
703 UINTN Total;\r
704 UINTN Remaining;\r
705 UINT8 Index;\r
706 UINT8 Length;\r
707\r
708 if (NumberOfBytes == 0 || Buffer == NULL) {\r
709 return 0;\r
710 }\r
711\r
712 Received = 0;\r
713 Total = 0;\r
714 Remaining = 0;\r
715\r
716 //\r
717 // If Handle is NULL, it means memory is ready for use.\r
718 // Use global variable to store handle value.\r
719 //\r
720 if (Handle == NULL) {\r
721 UsbDebugPortHandle = &mUsbDebugPortHandle;\r
722 } else {\r
723 UsbDebugPortHandle = (USB_DEBUG_PORT_HANDLE *)Handle;\r
724 }\r
725\r
726 if (NeedReinitializeHardware(UsbDebugPortHandle)) {\r
727 Status = InitializeUsbDebugHardware (UsbDebugPortHandle);\r
728 if (RETURN_ERROR(Status)) {\r
729 return 0;\r
730 }\r
731 }\r
732\r
733 UsbDebugPortRegister = (USB_DEBUG_PORT_REGISTER *)(UsbDebugPortHandle->UsbDebugPortMemoryBase + UsbDebugPortHandle->DebugPortOffset);\r
734\r
735 //\r
736 // First read data from buffer, then read debug port hw to get received data.\r
737 //\r
738 if (UsbDebugPortHandle->DataCount > 0) {\r
739 if (NumberOfBytes <= UsbDebugPortHandle->DataCount) {\r
740 Total = NumberOfBytes;\r
741 } else {\r
742 Total = UsbDebugPortHandle->DataCount;\r
743 }\r
744\r
745 for (Index = 0; Index < Total; Index++) {\r
746 Buffer[Index] = UsbDebugPortHandle->Data[Index];\r
747 }\r
748\r
749 for (Index = 0; Index < UsbDebugPortHandle->DataCount - Total; Index++) {\r
750 if (Total + Index >= 8) {\r
751 return 0;\r
752 }\r
753 UsbDebugPortHandle->Data[Index] = UsbDebugPortHandle->Data[Total + Index];\r
754 }\r
755 UsbDebugPortHandle->DataCount = (UINT8)(UsbDebugPortHandle->DataCount - (UINT8)Total);\r
756 }\r
757\r
758 //\r
759 // If Timeout is equal to 0, then it means it should always wait until all datum required are received.\r
760 //\r
761 if (Timeout == 0) {\r
762 Timeout = 0xFFFFFFFF;\r
763 }\r
764\r
765 //\r
766 // Read remaining data by executing one or more usb debug transfer transactions at usb debug port hw.\r
767 //\r
768 while ((Total < NumberOfBytes) && (Timeout != 0)) {\r
769 Remaining = NumberOfBytes - Total;\r
770 if (Remaining >= USB_DEBUG_PORT_MAX_PACKET_SIZE) {\r
771 Status = UsbDebugPortIn(UsbDebugPortRegister, Buffer + Total, &Received, INPUT_PID, 0x7f, 0x82, UsbDebugPortHandle->BulkInToggle);\r
772\r
773 if (RETURN_ERROR(Status)) {\r
774 return Total;\r
775 }\r
776 } else {\r
777 Status = UsbDebugPortIn(UsbDebugPortRegister, &UsbDebugPortHandle->Data[0], &Received, INPUT_PID, 0x7f, 0x82, UsbDebugPortHandle->BulkInToggle);\r
778\r
779 if (RETURN_ERROR(Status)) {\r
780 return Total;\r
781 }\r
782\r
783 UsbDebugPortHandle->DataCount = Received;\r
784\r
785 if (Remaining <= Received) {\r
786 Length = (UINT8)Remaining;\r
787 } else {\r
788 Length = (UINT8)Received;\r
789 }\r
790\r
791 //\r
792 // Copy required data from the data buffer to user buffer.\r
793 //\r
794 for (Index = 0; Index < Length; Index++) {\r
795 (Buffer + Total)[Index] = UsbDebugPortHandle->Data[Index];\r
796 UsbDebugPortHandle->DataCount--;\r
797 }\r
798\r
799 //\r
800 // reorder the data buffer to make available data arranged from the beginning of the data buffer.\r
801 //\r
802 for (Index = 0; Index < Received - Length; Index++) {\r
803 if (Length + Index >= 8) {\r
804 return 0;\r
805 }\r
806 UsbDebugPortHandle->Data[Index] = UsbDebugPortHandle->Data[Length + Index];\r
807 }\r
808 //\r
809 // fixup the real received length in Buffer.\r
810 //\r
811 Received = Length;\r
812 }\r
813 UsbDebugPortHandle->BulkInToggle ^= 1;\r
814\r
815 Total += Received;\r
816 Timeout -= 100;\r
817 }\r
818\r
819 return Total;\r
820}\r
821\r
822/**\r
823 Write data from buffer to debug device.\r
824\r
825 Writes NumberOfBytes data bytes from Buffer to the debug device.\r
826 The number of bytes actually written to the debug device is returned.\r
827 If the return value is less than NumberOfBytes, then the write operation failed.\r
828 If NumberOfBytes is zero, then return 0.\r
829\r
830 @param Handle Debug port handle.\r
831 @param Buffer Pointer to the data buffer to be written.\r
832 @param NumberOfBytes Number of bytes to written to the debug device.\r
833\r
834 @retval 0 NumberOfBytes is 0.\r
835 @retval >0 The number of bytes written to the debug device.\r
836 If this value is less than NumberOfBytes, then the read operation failed.\r
837\r
838**/\r
839UINTN\r
840EFIAPI\r
841DebugPortWriteBuffer (\r
842 IN DEBUG_PORT_HANDLE Handle,\r
843 IN UINT8 *Buffer,\r
844 IN UINTN NumberOfBytes\r
845 )\r
846{\r
847 USB_DEBUG_PORT_HANDLE *UsbDebugPortHandle;\r
848 USB_DEBUG_PORT_REGISTER *UsbDebugPortRegister;\r
849 RETURN_STATUS Status;\r
850 UINT8 Sent;\r
851 UINTN Total;\r
852 UINT8 ReceivedPid;\r
853\r
854 if (NumberOfBytes == 0 || Buffer == NULL) {\r
855 return 0;\r
856 }\r
857\r
858 Sent = 0;\r
859 Total = 0;\r
860\r
861 //\r
862 // If Handle is NULL, it means memory is ready for use.\r
863 // Use global variable to store handle value.\r
864 //\r
865 if (Handle == NULL) {\r
866 UsbDebugPortHandle = &mUsbDebugPortHandle;\r
867 } else {\r
868 UsbDebugPortHandle = (USB_DEBUG_PORT_HANDLE *)Handle;\r
869 }\r
870\r
871 if (NeedReinitializeHardware(UsbDebugPortHandle)) {\r
872 Status = InitializeUsbDebugHardware (UsbDebugPortHandle);\r
873 if (RETURN_ERROR(Status)) {\r
874 return 0;\r
875 }\r
876 }\r
877\r
878 UsbDebugPortRegister = (USB_DEBUG_PORT_REGISTER *)(UsbDebugPortHandle->UsbDebugPortMemoryBase + UsbDebugPortHandle->DebugPortOffset);\r
879\r
880 while ((Total < NumberOfBytes)) {\r
881 if (NumberOfBytes - Total > USB_DEBUG_PORT_MAX_PACKET_SIZE) {\r
882 Sent = USB_DEBUG_PORT_MAX_PACKET_SIZE;\r
883 } else {\r
884 Sent = (UINT8)(NumberOfBytes - Total);\r
885 }\r
886\r
887 Status = UsbDebugPortOut(UsbDebugPortRegister, Buffer + Total, Sent, OUTPUT_PID, 0x7F, 0x01, UsbDebugPortHandle->BulkOutToggle);\r
888\r
889 if (RETURN_ERROR(Status)) {\r
890 return Total;\r
891 }\r
892\r
893 ReceivedPid = (MmioRead8((UINTN)&UsbDebugPortRegister->ReceivedPid));\r
894 //\r
895 // If received a NAK_PID on write transaction, it means the usb debug device is busy and can not handle this transaction.\r
896 // should send the packet again.\r
897 //\r
898 if (ReceivedPid == NAK_PID) {\r
899 Sent = 0;\r
900 } else {\r
901 UsbDebugPortHandle->BulkOutToggle ^= 1;\r
902 }\r
903 Total += Sent;\r
904 }\r
905 return Total;\r
906}\r
907\r
908/**\r
909 Polls a debug device to see if there is any data waiting to be read.\r
910\r
911 Polls a debug device to see if there is any data waiting to be read.\r
912 If there is data waiting to be read from the debug device, then TRUE is returned.\r
913 If there is no data waiting to be read from the debug device, then FALSE is returned.\r
914\r
915 @param Handle Debug port handle.\r
916\r
917 @retval TRUE Data is waiting to be read from the debug device.\r
918 @retval FALSE There is no data waiting to be read from the serial device.\r
919\r
920**/\r
921BOOLEAN\r
922EFIAPI\r
923DebugPortPollBuffer (\r
924 IN DEBUG_PORT_HANDLE Handle\r
925 )\r
926{\r
927 USB_DEBUG_PORT_HANDLE *UsbDebugPortHandle;\r
928 USB_DEBUG_PORT_REGISTER *UsbDebugPortRegister;\r
929 UINT8 Length;\r
930 UINT8 Index;\r
931 RETURN_STATUS Status;\r
932\r
933 //\r
934 // If Handle is NULL, it means memory is ready for use.\r
935 // Use global variable to store handle value.\r
936 //\r
937 if (Handle == NULL) {\r
938 UsbDebugPortHandle = &mUsbDebugPortHandle;\r
939 } else {\r
940 UsbDebugPortHandle = (USB_DEBUG_PORT_HANDLE *)Handle;\r
941 }\r
942\r
943 if (NeedReinitializeHardware(UsbDebugPortHandle)) {\r
944 Status = InitializeUsbDebugHardware(UsbDebugPortHandle);\r
945 if (RETURN_ERROR(Status)) {\r
946 return FALSE;\r
947 }\r
948 }\r
949\r
950 //\r
951 // If the data buffer is not empty, then return TRUE directly.\r
952 // else initialize a usb read transaction and read data to the data buffer.\r
953 //\r
954 if (UsbDebugPortHandle->DataCount != 0) {\r
955 return TRUE;\r
956 }\r
957\r
958 UsbDebugPortRegister = (USB_DEBUG_PORT_REGISTER *)(UsbDebugPortHandle->UsbDebugPortMemoryBase + UsbDebugPortHandle->DebugPortOffset);\r
959\r
960 UsbDebugPortRegister->TokenPid = INPUT_PID;\r
961 if (UsbDebugPortHandle->BulkInToggle == 0) {\r
962 UsbDebugPortRegister->SendPid = DATA0_PID;\r
963 } else {\r
964 UsbDebugPortRegister->SendPid = DATA1_PID;\r
965 }\r
966 UsbDebugPortRegister->UsbAddress = 0x7F;\r
967 UsbDebugPortRegister->UsbEndPoint = 0x82 & 0x0F;\r
968\r
969 //\r
970 // Clearing W/R bit to indicate it's a READ operation\r
971 //\r
972 MmioAnd32((UINTN)&UsbDebugPortRegister->ControlStatus, (UINT32)~BIT4);\r
973 //\r
974 // Setting GO bit as well as clearing DONE bit\r
975 //\r
976 MmioOr32((UINTN)&UsbDebugPortRegister->ControlStatus, (UINT32)BIT5);\r
977\r
978 //\r
979 // Wait for completing the request\r
980 //\r
981 while ((MmioRead32((UINTN)&UsbDebugPortRegister->ControlStatus) & (UINT32)BIT16) == 0);\r
982\r
983 if ((MmioRead32((UINTN)&UsbDebugPortRegister->ControlStatus)) & BIT6) {\r
984 return FALSE;\r
985 }\r
986\r
987 Length = (UINT8)(MmioRead32((UINTN)&UsbDebugPortRegister->ControlStatus) & 0xF);\r
988\r
989 if (Length > 8) {\r
990 return FALSE;\r
991 }\r
992\r
993 UsbDebugPortHandle->BulkInToggle ^= 1;\r
994\r
995 if (Length == 0) {\r
996 return FALSE;\r
997 }\r
998\r
999 for (Index = 0; Index < Length; Index++) {\r
1000 UsbDebugPortHandle->Data[Index] = UsbDebugPortRegister->DataBuffer[Index];\r
1001 }\r
1002 UsbDebugPortHandle->DataCount = Length;\r
1003\r
1004 return TRUE;\r
1005}\r
1006\r
1007/**\r
1008 Initialize the debug port.\r
1009\r
1010 If Function is not NULL, Debug Communication Libary will call this function\r
1011 by passing in the Context to be the first parameter. If needed, Debug Communication\r
1012 Library will create one debug port handle to be the second argument passing in\r
1013 calling the Function, otherwise it will pass NULL to be the second argument of\r
1014 Function.\r
1015\r
1016 If Function is NULL, and Context is not NULL, the Debug Communication Library could\r
1017 a) Return the same handle as passed in (as Context parameter).\r
1018 b) Ignore the input Context parameter and create new hanlde to be returned.\r
1019\r
1020 If parameter Function is NULL and Context is NULL, Debug Communication Library could\r
1021 created a new handle if needed and return it, otherwise it will return NULL.\r
1022\r
1023 @param[in] Context Context needed by callback function; it was optional.\r
1024 @param[in] Function Continue function called by Debug Communication library;\r
1025 it was optional.\r
1026\r
1027 @return The debug port handle created by Debug Communication Library if Function\r
1028 is not NULL.\r
1029\r
1030**/\r
1031DEBUG_PORT_HANDLE\r
1032EFIAPI\r
1033DebugPortInitialize (\r
1034 IN VOID *Context,\r
1035 IN DEBUG_PORT_CONTINUE Function\r
1036 )\r
1037{\r
1038 RETURN_STATUS Status;\r
1039 USB_DEBUG_PORT_HANDLE Handle;\r
1040\r
1041 if (Function == NULL && Context != NULL) {\r
1042 return (DEBUG_PORT_HANDLE *) Context;\r
1043 }\r
1044\r
1045 ZeroMem(&Handle, sizeof (USB_DEBUG_PORT_HANDLE));\r
1046\r
1047 Status = CalculateUsbDebugPortBar(&Handle.DebugPortOffset, &Handle.DebugPortBarNumber);\r
1048 if (RETURN_ERROR (Status)) {\r
1049 return NULL;\r
1050 }\r
1051\r
1052 Handle.EhciMemoryBase = 0xFFFFFC00 & PciRead32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET);\r
1053\r
1054 if (Handle.EhciMemoryBase == 0) {\r
1055 //\r
1056 // Usb Debug Port MMIO Space Is Not Enabled. Assumption here that DebugPortBase is zero\r
1057 //\r
1058 PciWrite32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET, PcdGet32(PcdUsbEhciMemorySpaceBase));\r
1059 Handle.EhciMemoryBase = 0xFFFFFC00 & PciRead32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET);\r
1060 }\r
1061\r
1062 Handle.UsbDebugPortMemoryBase = 0xFFFFFC00 & PciRead32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + Handle.DebugPortBarNumber * 4);\r
1063\r
1064 if (Handle.UsbDebugPortMemoryBase == 0) {\r
1065 //\r
1066 // Usb Debug Port MMIO Space Is Not Enabled. Assumption here that DebugPortBase is zero\r
1067 //\r
1068 PciWrite32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + Handle.DebugPortBarNumber * 4, PcdGet32(PcdUsbDebugPortMemorySpaceBase));\r
1069 Handle.UsbDebugPortMemoryBase = 0xFFFFFC00 & PciRead32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + Handle.DebugPortBarNumber * 4);\r
1070 }\r
1071\r
1072 Status = InitializeUsbDebugHardware (&Handle);\r
1073 if (RETURN_ERROR(Status)) {\r
1074 return NULL;\r
1075 }\r
1076\r
1077 if (Function != NULL) {\r
1078 Function (Context, &Handle);\r
1079 } else {\r
1080 CopyMem(&mUsbDebugPortHandle, &Handle, sizeof (USB_DEBUG_PORT_HANDLE));\r
1081 }\r
1082\r
1083 return (DEBUG_PORT_HANDLE)(UINTN)&mUsbDebugPortHandle;\r
1084}\r
1085\r