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