]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBusPei / HubPeim.c
1 /** @file
2 Usb Hub Request Support In PEI Phase
3
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "UsbPeim.h"
11 #include "HubPeim.h"
12 #include "PeiUsbLib.h"
13
14 /**
15 Get a given hub port status.
16
17 @param PeiServices General-purpose services that are available to every PEIM.
18 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
19 @param Port Usb hub port number (starting from 1).
20 @param PortStatus Current Hub port status and change status.
21
22 @retval EFI_SUCCESS Port status is obtained successfully.
23 @retval EFI_DEVICE_ERROR Cannot get the port status due to a hardware error.
24 @retval Others Other failure occurs.
25
26 **/
27 EFI_STATUS
28 PeiHubGetPortStatus (
29 IN EFI_PEI_SERVICES **PeiServices,
30 IN PEI_USB_IO_PPI *UsbIoPpi,
31 IN UINT8 Port,
32 OUT UINT32 *PortStatus
33 )
34 {
35 EFI_USB_DEVICE_REQUEST DeviceRequest;
36
37 ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
38
39 //
40 // Fill Device request packet
41 //
42 DeviceRequest.RequestType = USB_HUB_GET_PORT_STATUS_REQ_TYPE;
43 DeviceRequest.Request = USB_HUB_GET_PORT_STATUS;
44 DeviceRequest.Index = Port;
45 DeviceRequest.Length = (UINT16)sizeof (UINT32);
46
47 return UsbIoPpi->UsbControlTransfer (
48 PeiServices,
49 UsbIoPpi,
50 &DeviceRequest,
51 EfiUsbDataIn,
52 PcdGet32 (PcdUsbTransferTimeoutValue),
53 PortStatus,
54 sizeof (UINT32)
55 );
56 }
57
58 /**
59 Set specified feature to a given hub port.
60
61 @param PeiServices General-purpose services that are available to every PEIM.
62 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
63 @param Port Usb hub port number (starting from 1).
64 @param Value New feature value.
65
66 @retval EFI_SUCCESS Port feature is set successfully.
67 @retval EFI_DEVICE_ERROR Cannot set the port feature due to a hardware error.
68 @retval Others Other failure occurs.
69
70 **/
71 EFI_STATUS
72 PeiHubSetPortFeature (
73 IN EFI_PEI_SERVICES **PeiServices,
74 IN PEI_USB_IO_PPI *UsbIoPpi,
75 IN UINT8 Port,
76 IN UINT8 Value
77 )
78 {
79 EFI_USB_DEVICE_REQUEST DeviceRequest;
80
81 ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
82
83 //
84 // Fill Device request packet
85 //
86 DeviceRequest.RequestType = USB_HUB_SET_PORT_FEATURE_REQ_TYPE;
87 DeviceRequest.Request = USB_HUB_SET_PORT_FEATURE;
88 DeviceRequest.Value = Value;
89 DeviceRequest.Index = Port;
90
91 return UsbIoPpi->UsbControlTransfer (
92 PeiServices,
93 UsbIoPpi,
94 &DeviceRequest,
95 EfiUsbNoData,
96 PcdGet32 (PcdUsbTransferTimeoutValue),
97 NULL,
98 0
99 );
100 }
101
102 /**
103 Clear specified feature on a given hub port.
104
105 @param PeiServices General-purpose services that are available to every PEIM.
106 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
107 @param Port Usb hub port number (starting from 1).
108 @param Value Feature value that will be cleared from the hub port.
109
110 @retval EFI_SUCCESS Port feature is cleared successfully.
111 @retval EFI_DEVICE_ERROR Cannot clear the port feature due to a hardware error.
112 @retval Others Other failure occurs.
113
114 **/
115 EFI_STATUS
116 PeiHubClearPortFeature (
117 IN EFI_PEI_SERVICES **PeiServices,
118 IN PEI_USB_IO_PPI *UsbIoPpi,
119 IN UINT8 Port,
120 IN UINT8 Value
121 )
122 {
123 EFI_USB_DEVICE_REQUEST DeviceRequest;
124
125 ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
126
127 //
128 // Fill Device request packet
129 //
130 DeviceRequest.RequestType = USB_HUB_CLEAR_FEATURE_PORT_REQ_TYPE;
131 DeviceRequest.Request = USB_HUB_CLEAR_FEATURE_PORT;
132 DeviceRequest.Value = Value;
133 DeviceRequest.Index = Port;
134
135 return UsbIoPpi->UsbControlTransfer (
136 PeiServices,
137 UsbIoPpi,
138 &DeviceRequest,
139 EfiUsbNoData,
140 PcdGet32 (PcdUsbTransferTimeoutValue),
141 NULL,
142 0
143 );
144 }
145
146 /**
147 Get a given hub status.
148
149 @param PeiServices General-purpose services that are available to every PEIM.
150 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
151 @param HubStatus Current Hub status and change status.
152
153 @retval EFI_SUCCESS Hub status is obtained successfully.
154 @retval EFI_DEVICE_ERROR Cannot get the hub status due to a hardware error.
155 @retval Others Other failure occurs.
156
157 **/
158 EFI_STATUS
159 PeiHubGetHubStatus (
160 IN EFI_PEI_SERVICES **PeiServices,
161 IN PEI_USB_IO_PPI *UsbIoPpi,
162 OUT UINT32 *HubStatus
163 )
164 {
165 EFI_USB_DEVICE_REQUEST DeviceRequest;
166
167 ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
168
169 //
170 // Fill Device request packet
171 //
172 DeviceRequest.RequestType = USB_HUB_GET_HUB_STATUS_REQ_TYPE;
173 DeviceRequest.Request = USB_HUB_GET_HUB_STATUS;
174 DeviceRequest.Length = (UINT16)sizeof (UINT32);
175
176 return UsbIoPpi->UsbControlTransfer (
177 PeiServices,
178 UsbIoPpi,
179 &DeviceRequest,
180 EfiUsbDataIn,
181 PcdGet32 (PcdUsbTransferTimeoutValue),
182 HubStatus,
183 sizeof (UINT32)
184 );
185 }
186
187 /**
188 Clear specified feature on a given hub.
189
190 @param PeiServices General-purpose services that are available to every PEIM.
191 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
192 @param Value Feature value that will be cleared from the hub port.
193
194 @retval EFI_SUCCESS Hub feature is cleared successfully.
195 @retval EFI_DEVICE_ERROR Cannot clear the hub feature due to a hardware error.
196 @retval Others Other failure occurs.
197
198 **/
199 EFI_STATUS
200 PeiHubClearHubFeature (
201 IN EFI_PEI_SERVICES **PeiServices,
202 IN PEI_USB_IO_PPI *UsbIoPpi,
203 IN UINT8 Value
204 )
205 {
206 EFI_USB_DEVICE_REQUEST DeviceRequest;
207
208 ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
209
210 //
211 // Fill Device request packet
212 //
213 DeviceRequest.RequestType = USB_HUB_CLEAR_FEATURE_REQ_TYPE;
214 DeviceRequest.Request = USB_HUB_CLEAR_FEATURE;
215 DeviceRequest.Value = Value;
216
217 return UsbIoPpi->UsbControlTransfer (
218 PeiServices,
219 UsbIoPpi,
220 &DeviceRequest,
221 EfiUsbNoData,
222 PcdGet32 (PcdUsbTransferTimeoutValue),
223 NULL,
224 0
225 );
226 }
227
228 /**
229 Get a given (SuperSpeed) hub descriptor.
230
231 @param PeiServices General-purpose services that are available to every PEIM.
232 @param PeiUsbDevice Indicates the hub controller device.
233 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
234 @param DescriptorSize The length of Hub Descriptor buffer.
235 @param HubDescriptor Caller allocated buffer to store the hub descriptor if
236 successfully returned.
237
238 @retval EFI_SUCCESS Hub descriptor is obtained successfully.
239 @retval EFI_DEVICE_ERROR Cannot get the hub descriptor due to a hardware error.
240 @retval Others Other failure occurs.
241
242 **/
243 EFI_STATUS
244 PeiGetHubDescriptor (
245 IN EFI_PEI_SERVICES **PeiServices,
246 IN PEI_USB_DEVICE *PeiUsbDevice,
247 IN PEI_USB_IO_PPI *UsbIoPpi,
248 IN UINTN DescriptorSize,
249 OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor
250 )
251 {
252 EFI_USB_DEVICE_REQUEST DevReq;
253 UINT8 DescType;
254
255 ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
256
257 DescType = (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) ?
258 USB_DT_SUPERSPEED_HUB :
259 USB_DT_HUB;
260
261 //
262 // Fill Device request packet
263 //
264 DevReq.RequestType = USB_RT_HUB | 0x80;
265 DevReq.Request = USB_HUB_GET_DESCRIPTOR;
266 DevReq.Value = (UINT16)(DescType << 8);
267 DevReq.Length = (UINT16)DescriptorSize;
268
269 return UsbIoPpi->UsbControlTransfer (
270 PeiServices,
271 UsbIoPpi,
272 &DevReq,
273 EfiUsbDataIn,
274 PcdGet32 (PcdUsbTransferTimeoutValue),
275 HubDescriptor,
276 (UINT16)DescriptorSize
277 );
278 }
279
280 /**
281 Read the whole usb hub descriptor. It is necessary
282 to do it in two steps because hub descriptor is of
283 variable length.
284
285 @param PeiServices General-purpose services that are available to every PEIM.
286 @param PeiUsbDevice Indicates the hub controller device.
287 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
288 @param HubDescriptor Caller allocated buffer to store the hub descriptor if
289 successfully returned.
290
291 @retval EFI_SUCCESS Hub descriptor is obtained successfully.
292 @retval EFI_DEVICE_ERROR Cannot get the hub descriptor due to a hardware error.
293 @retval Others Other failure occurs.
294
295 **/
296 EFI_STATUS
297 PeiUsbHubReadDesc (
298 IN EFI_PEI_SERVICES **PeiServices,
299 IN PEI_USB_DEVICE *PeiUsbDevice,
300 IN PEI_USB_IO_PPI *UsbIoPpi,
301 OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor
302 )
303 {
304 EFI_STATUS Status;
305
306 //
307 // First get the hub descriptor length
308 //
309 Status = PeiGetHubDescriptor (PeiServices, PeiUsbDevice, UsbIoPpi, 2, HubDescriptor);
310
311 if (EFI_ERROR (Status)) {
312 return Status;
313 }
314
315 //
316 // Get the whole hub descriptor
317 //
318 return PeiGetHubDescriptor (PeiServices, PeiUsbDevice, UsbIoPpi, HubDescriptor->Length, HubDescriptor);
319 }
320
321 /**
322 USB hub control transfer to set the hub depth.
323
324 @param PeiServices General-purpose services that are available to every PEIM.
325 @param PeiUsbDevice Indicates the hub controller device.
326 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
327
328 @retval EFI_SUCCESS Depth of the hub is set.
329 @retval Others Failed to set the depth.
330
331 **/
332 EFI_STATUS
333 PeiUsbHubCtrlSetHubDepth (
334 IN EFI_PEI_SERVICES **PeiServices,
335 IN PEI_USB_DEVICE *PeiUsbDevice,
336 IN PEI_USB_IO_PPI *UsbIoPpi
337 )
338 {
339 EFI_USB_DEVICE_REQUEST DevReq;
340
341 ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
342
343 //
344 // Fill Device request packet
345 //
346 DevReq.RequestType = USB_RT_HUB;
347 DevReq.Request = USB_HUB_REQ_SET_DEPTH;
348 DevReq.Value = PeiUsbDevice->Tier;
349 DevReq.Length = 0;
350
351 return UsbIoPpi->UsbControlTransfer (
352 PeiServices,
353 UsbIoPpi,
354 &DevReq,
355 EfiUsbNoData,
356 PcdGet32 (PcdUsbTransferTimeoutValue),
357 NULL,
358 0
359 );
360 }
361
362 /**
363 Configure a given hub.
364
365 @param PeiServices General-purpose services that are available to every PEIM.
366 @param PeiUsbDevice Indicating the hub controller device that will be configured
367
368 @retval EFI_SUCCESS Hub configuration is done successfully.
369 @retval EFI_DEVICE_ERROR Cannot configure the hub due to a hardware error.
370
371 **/
372 EFI_STATUS
373 PeiDoHubConfig (
374 IN EFI_PEI_SERVICES **PeiServices,
375 IN PEI_USB_DEVICE *PeiUsbDevice
376 )
377 {
378 UINT8 HubDescBuffer[256];
379 EFI_USB_HUB_DESCRIPTOR *HubDescriptor;
380 EFI_STATUS Status;
381 EFI_USB_HUB_STATUS HubStatus;
382 UINTN Index;
383 PEI_USB_IO_PPI *UsbIoPpi;
384
385 UsbIoPpi = &PeiUsbDevice->UsbIoPpi;
386
387 //
388 // The length field of descriptor is UINT8 type, so the buffer
389 // with 256 bytes is enough to hold the descriptor data.
390 //
391 HubDescriptor = (EFI_USB_HUB_DESCRIPTOR *)HubDescBuffer;
392
393 //
394 // Get the hub descriptor
395 //
396 Status = PeiUsbHubReadDesc (
397 PeiServices,
398 PeiUsbDevice,
399 UsbIoPpi,
400 HubDescriptor
401 );
402 if (EFI_ERROR (Status)) {
403 return EFI_DEVICE_ERROR;
404 }
405
406 PeiUsbDevice->DownStreamPortNo = HubDescriptor->NbrPorts;
407
408 if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) {
409 DEBUG ((DEBUG_INFO, "PeiDoHubConfig: Set Hub Depth as 0x%x\n", PeiUsbDevice->Tier));
410 PeiUsbHubCtrlSetHubDepth (
411 PeiServices,
412 PeiUsbDevice,
413 UsbIoPpi
414 );
415 } else {
416 //
417 // Power all the hub ports
418 //
419 for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {
420 Status = PeiHubSetPortFeature (
421 PeiServices,
422 UsbIoPpi,
423 (UINT8)(Index + 1),
424 EfiUsbPortPower
425 );
426 if (EFI_ERROR (Status)) {
427 DEBUG ((DEBUG_ERROR, "PeiDoHubConfig: PeiHubSetPortFeature EfiUsbPortPower failed %x\n", Index));
428 continue;
429 }
430 }
431
432 DEBUG ((DEBUG_INFO, "PeiDoHubConfig: HubDescriptor.PwrOn2PwrGood: 0x%x\n", HubDescriptor->PwrOn2PwrGood));
433 if (HubDescriptor->PwrOn2PwrGood > 0) {
434 MicroSecondDelay (HubDescriptor->PwrOn2PwrGood * USB_SET_PORT_POWER_STALL);
435 }
436
437 //
438 // Clear Hub Status Change
439 //
440 Status = PeiHubGetHubStatus (
441 PeiServices,
442 UsbIoPpi,
443 (UINT32 *)&HubStatus
444 );
445 if (EFI_ERROR (Status)) {
446 return EFI_DEVICE_ERROR;
447 } else {
448 //
449 // Hub power supply change happens
450 //
451 if ((HubStatus.HubChangeStatus & HUB_CHANGE_LOCAL_POWER) != 0) {
452 PeiHubClearHubFeature (
453 PeiServices,
454 UsbIoPpi,
455 C_HUB_LOCAL_POWER
456 );
457 }
458
459 //
460 // Hub change overcurrent happens
461 //
462 if ((HubStatus.HubChangeStatus & HUB_CHANGE_OVERCURRENT) != 0) {
463 PeiHubClearHubFeature (
464 PeiServices,
465 UsbIoPpi,
466 C_HUB_OVER_CURRENT
467 );
468 }
469 }
470 }
471
472 return EFI_SUCCESS;
473 }
474
475 /**
476 Send reset signal over the given root hub port.
477
478 @param PeiServices General-purpose services that are available to every PEIM.
479 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
480 @param PortNum Usb hub port number (starting from 1).
481
482 **/
483 VOID
484 PeiResetHubPort (
485 IN EFI_PEI_SERVICES **PeiServices,
486 IN PEI_USB_IO_PPI *UsbIoPpi,
487 IN UINT8 PortNum
488 )
489 {
490 EFI_STATUS Status;
491 UINTN Index;
492 EFI_USB_PORT_STATUS HubPortStatus;
493
494 MicroSecondDelay (100 * 1000);
495
496 //
497 // reset root port
498 //
499 PeiHubSetPortFeature (
500 PeiServices,
501 UsbIoPpi,
502 PortNum,
503 EfiUsbPortReset
504 );
505
506 //
507 // Drive the reset signal for worst 20ms. Check USB 2.0 Spec
508 // section 7.1.7.5 for timing requirements.
509 //
510 MicroSecondDelay (USB_SET_PORT_RESET_STALL);
511
512 //
513 // Check USB_PORT_STAT_C_RESET bit to see if the resetting state is done.
514 //
515 ZeroMem (&HubPortStatus, sizeof (EFI_USB_PORT_STATUS));
516
517 for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
518 Status = PeiHubGetPortStatus (
519 PeiServices,
520 UsbIoPpi,
521 PortNum,
522 (UINT32 *)&HubPortStatus
523 );
524
525 if (EFI_ERROR (Status)) {
526 return;
527 }
528
529 if (USB_BIT_IS_SET (HubPortStatus.PortChangeStatus, USB_PORT_STAT_C_RESET)) {
530 break;
531 }
532
533 MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL);
534 }
535
536 if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {
537 DEBUG ((DEBUG_ERROR, "PeiResetHubPort: reset not finished in time on port %d\n", PortNum));
538 return;
539 }
540
541 //
542 // clear reset change root port
543 //
544 PeiHubClearPortFeature (
545 PeiServices,
546 UsbIoPpi,
547 PortNum,
548 EfiUsbPortResetChange
549 );
550
551 MicroSecondDelay (1 * 1000);
552
553 PeiHubClearPortFeature (
554 PeiServices,
555 UsbIoPpi,
556 PortNum,
557 EfiUsbPortConnectChange
558 );
559
560 //
561 // Set port enable
562 //
563 PeiHubSetPortFeature (
564 PeiServices,
565 UsbIoPpi,
566 PortNum,
567 EfiUsbPortEnable
568 );
569
570 //
571 // Clear any change status
572 //
573
574 PeiHubClearPortFeature (
575 PeiServices,
576 UsbIoPpi,
577 PortNum,
578 EfiUsbPortEnableChange
579 );
580
581 MicroSecondDelay (10 * 1000);
582
583 return;
584 }