]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c
5607c65b1330318934f9b2dbac23d0b69a87d0a5
[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 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
198 /**
199 Clear specified feature on a given hub.
200
201 @param PeiServices General-purpose services that are available to every PEIM.
202 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
203 @param Value Feature value that will be cleared from the hub port.
204
205 @retval EFI_SUCCESS Hub feature is cleared successfully.
206 @retval EFI_DEVICE_ERROR Cannot clear the hub feature due to a hardware error.
207 @retval Others Other failure occurs.
208
209 **/
210 EFI_STATUS
211 PeiHubClearHubFeature (
212 IN EFI_PEI_SERVICES **PeiServices,
213 IN PEI_USB_IO_PPI *UsbIoPpi,
214 IN UINT8 Value
215 )
216 {
217 EFI_USB_DEVICE_REQUEST DeviceRequest;
218
219 ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
220
221 //
222 // Fill Device request packet
223 //
224 DeviceRequest.RequestType = USB_HUB_CLEAR_FEATURE_REQ_TYPE;
225 DeviceRequest.Request = USB_HUB_CLEAR_FEATURE;
226 DeviceRequest.Value = Value;
227
228 return UsbIoPpi->UsbControlTransfer (
229 PeiServices,
230 UsbIoPpi,
231 &DeviceRequest,
232 EfiUsbNoData,
233 PcdGet32 (PcdUsbTransferTimeoutValue),
234 NULL,
235 0
236 );
237 }
238
239 /**
240 Get a given (SuperSpeed) hub descriptor.
241
242 @param PeiServices General-purpose services that are available to every PEIM.
243 @param PeiUsbDevice Indicates the hub controller device.
244 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
245 @param DescriptorSize The length of Hub Descriptor buffer.
246 @param HubDescriptor Caller allocated buffer to store the hub descriptor if
247 successfully returned.
248
249 @retval EFI_SUCCESS Hub descriptor is obtained successfully.
250 @retval EFI_DEVICE_ERROR Cannot get the hub descriptor due to a hardware error.
251 @retval Others Other failure occurs.
252
253 **/
254 EFI_STATUS
255 PeiGetHubDescriptor (
256 IN EFI_PEI_SERVICES **PeiServices,
257 IN PEI_USB_DEVICE *PeiUsbDevice,
258 IN PEI_USB_IO_PPI *UsbIoPpi,
259 IN UINTN DescriptorSize,
260 OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor
261 )
262 {
263 EFI_USB_DEVICE_REQUEST DevReq;
264 UINT8 DescType;
265
266 ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
267
268 DescType = (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) ?
269 USB_DT_SUPERSPEED_HUB :
270 USB_DT_HUB;
271
272 //
273 // Fill Device request packet
274 //
275 DevReq.RequestType = USB_RT_HUB | 0x80;
276 DevReq.Request = USB_HUB_GET_DESCRIPTOR;
277 DevReq.Value = (UINT16) (DescType << 8);
278 DevReq.Length = (UINT16) DescriptorSize;
279
280 return UsbIoPpi->UsbControlTransfer (
281 PeiServices,
282 UsbIoPpi,
283 &DevReq,
284 EfiUsbDataIn,
285 PcdGet32 (PcdUsbTransferTimeoutValue),
286 HubDescriptor,
287 (UINT16)DescriptorSize
288 );
289 }
290
291 /**
292 Read the whole usb hub descriptor. It is necessary
293 to do it in two steps because hub descriptor is of
294 variable length.
295
296 @param PeiServices General-purpose services that are available to every PEIM.
297 @param PeiUsbDevice Indicates the hub controller device.
298 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
299 @param HubDescriptor Caller allocated buffer to store the hub descriptor if
300 successfully returned.
301
302 @retval EFI_SUCCESS Hub descriptor is obtained successfully.
303 @retval EFI_DEVICE_ERROR Cannot get the hub descriptor due to a hardware error.
304 @retval Others Other failure occurs.
305
306 **/
307 EFI_STATUS
308 PeiUsbHubReadDesc (
309 IN EFI_PEI_SERVICES **PeiServices,
310 IN PEI_USB_DEVICE *PeiUsbDevice,
311 IN PEI_USB_IO_PPI *UsbIoPpi,
312 OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor
313 )
314 {
315 EFI_STATUS Status;
316
317 //
318 // First get the hub descriptor length
319 //
320 Status = PeiGetHubDescriptor (PeiServices, PeiUsbDevice, UsbIoPpi, 2, HubDescriptor);
321
322 if (EFI_ERROR (Status)) {
323 return Status;
324 }
325
326 //
327 // Get the whole hub descriptor
328 //
329 return PeiGetHubDescriptor (PeiServices, PeiUsbDevice, UsbIoPpi, HubDescriptor->Length, HubDescriptor);
330 }
331
332 /**
333 USB hub control transfer to set the hub depth.
334
335 @param PeiServices General-purpose services that are available to every PEIM.
336 @param PeiUsbDevice Indicates the hub controller device.
337 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
338
339 @retval EFI_SUCCESS Depth of the hub is set.
340 @retval Others Failed to set the depth.
341
342 **/
343 EFI_STATUS
344 PeiUsbHubCtrlSetHubDepth (
345 IN EFI_PEI_SERVICES **PeiServices,
346 IN PEI_USB_DEVICE *PeiUsbDevice,
347 IN PEI_USB_IO_PPI *UsbIoPpi
348 )
349 {
350 EFI_USB_DEVICE_REQUEST DevReq;
351 ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
352
353 //
354 // Fill Device request packet
355 //
356 DevReq.RequestType = USB_RT_HUB;
357 DevReq.Request = USB_HUB_REQ_SET_DEPTH;
358 DevReq.Value = PeiUsbDevice->Tier;
359 DevReq.Length = 0;
360
361 return UsbIoPpi->UsbControlTransfer (
362 PeiServices,
363 UsbIoPpi,
364 &DevReq,
365 EfiUsbNoData,
366 PcdGet32 (PcdUsbTransferTimeoutValue),
367 NULL,
368 0
369 );
370 }
371
372 /**
373 Configure a given hub.
374
375 @param PeiServices General-purpose services that are available to every PEIM.
376 @param PeiUsbDevice Indicating the hub controller device that will be configured
377
378 @retval EFI_SUCCESS Hub configuration is done successfully.
379 @retval EFI_DEVICE_ERROR Cannot configure the hub due to a hardware error.
380
381 **/
382 EFI_STATUS
383 PeiDoHubConfig (
384 IN EFI_PEI_SERVICES **PeiServices,
385 IN PEI_USB_DEVICE *PeiUsbDevice
386 )
387 {
388 UINT8 HubDescBuffer[256];
389 EFI_USB_HUB_DESCRIPTOR *HubDescriptor;
390 EFI_STATUS Status;
391 EFI_USB_HUB_STATUS HubStatus;
392 UINTN Index;
393 PEI_USB_IO_PPI *UsbIoPpi;
394
395 UsbIoPpi = &PeiUsbDevice->UsbIoPpi;
396
397 //
398 // The length field of descriptor is UINT8 type, so the buffer
399 // with 256 bytes is enough to hold the descriptor data.
400 //
401 HubDescriptor = (EFI_USB_HUB_DESCRIPTOR *) HubDescBuffer;
402
403 //
404 // Get the hub descriptor
405 //
406 Status = PeiUsbHubReadDesc (
407 PeiServices,
408 PeiUsbDevice,
409 UsbIoPpi,
410 HubDescriptor
411 );
412 if (EFI_ERROR (Status)) {
413 return EFI_DEVICE_ERROR;
414 }
415
416 PeiUsbDevice->DownStreamPortNo = HubDescriptor->NbrPorts;
417
418 if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) {
419 DEBUG ((EFI_D_INFO, "PeiDoHubConfig: Set Hub Depth as 0x%x\n", PeiUsbDevice->Tier));
420 PeiUsbHubCtrlSetHubDepth (
421 PeiServices,
422 PeiUsbDevice,
423 UsbIoPpi
424 );
425 } else {
426 //
427 // Power all the hub ports
428 //
429 for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {
430 Status = PeiHubSetPortFeature (
431 PeiServices,
432 UsbIoPpi,
433 (UINT8) (Index + 1),
434 EfiUsbPortPower
435 );
436 if (EFI_ERROR (Status)) {
437 DEBUG (( EFI_D_ERROR, "PeiDoHubConfig: PeiHubSetPortFeature EfiUsbPortPower failed %x\n", Index));
438 continue;
439 }
440 }
441
442 DEBUG (( EFI_D_INFO, "PeiDoHubConfig: HubDescriptor.PwrOn2PwrGood: 0x%x\n", HubDescriptor->PwrOn2PwrGood));
443 if (HubDescriptor->PwrOn2PwrGood > 0) {
444 MicroSecondDelay (HubDescriptor->PwrOn2PwrGood * USB_SET_PORT_POWER_STALL);
445 }
446
447 //
448 // Clear Hub Status Change
449 //
450 Status = PeiHubGetHubStatus (
451 PeiServices,
452 UsbIoPpi,
453 (UINT32 *) &HubStatus
454 );
455 if (EFI_ERROR (Status)) {
456 return EFI_DEVICE_ERROR;
457 } else {
458 //
459 // Hub power supply change happens
460 //
461 if ((HubStatus.HubChangeStatus & HUB_CHANGE_LOCAL_POWER) != 0) {
462 PeiHubClearHubFeature (
463 PeiServices,
464 UsbIoPpi,
465 C_HUB_LOCAL_POWER
466 );
467 }
468 //
469 // Hub change overcurrent happens
470 //
471 if ((HubStatus.HubChangeStatus & HUB_CHANGE_OVERCURRENT) != 0) {
472 PeiHubClearHubFeature (
473 PeiServices,
474 UsbIoPpi,
475 C_HUB_OVER_CURRENT
476 );
477 }
478 }
479 }
480
481 return EFI_SUCCESS;
482 }
483
484 /**
485 Send reset signal over the given root hub port.
486
487 @param PeiServices General-purpose services that are available to every PEIM.
488 @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
489 @param PortNum Usb hub port number (starting from 1).
490
491 **/
492 VOID
493 PeiResetHubPort (
494 IN EFI_PEI_SERVICES **PeiServices,
495 IN PEI_USB_IO_PPI *UsbIoPpi,
496 IN UINT8 PortNum
497 )
498 {
499 EFI_STATUS Status;
500 UINTN Index;
501 EFI_USB_PORT_STATUS HubPortStatus;
502
503 MicroSecondDelay (100 * 1000);
504
505 //
506 // reset root port
507 //
508 PeiHubSetPortFeature (
509 PeiServices,
510 UsbIoPpi,
511 PortNum,
512 EfiUsbPortReset
513 );
514
515 //
516 // Drive the reset signal for worst 20ms. Check USB 2.0 Spec
517 // section 7.1.7.5 for timing requirements.
518 //
519 MicroSecondDelay (USB_SET_PORT_RESET_STALL);
520
521 //
522 // Check USB_PORT_STAT_C_RESET bit to see if the resetting state is done.
523 //
524 ZeroMem (&HubPortStatus, sizeof (EFI_USB_PORT_STATUS));
525
526 for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
527 Status = PeiHubGetPortStatus (
528 PeiServices,
529 UsbIoPpi,
530 PortNum,
531 (UINT32 *) &HubPortStatus
532 );
533
534 if (EFI_ERROR (Status)) {
535 return;
536 }
537
538 if (USB_BIT_IS_SET (HubPortStatus.PortChangeStatus, USB_PORT_STAT_C_RESET)) {
539 break;
540 }
541
542 MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL);
543 }
544
545 if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {
546 DEBUG ((EFI_D_ERROR, "PeiResetHubPort: reset not finished in time on port %d\n", PortNum));
547 return;
548 }
549
550 //
551 // clear reset change root port
552 //
553 PeiHubClearPortFeature (
554 PeiServices,
555 UsbIoPpi,
556 PortNum,
557 EfiUsbPortResetChange
558 );
559
560 MicroSecondDelay (1 * 1000);
561
562 PeiHubClearPortFeature (
563 PeiServices,
564 UsbIoPpi,
565 PortNum,
566 EfiUsbPortConnectChange
567 );
568
569 //
570 // Set port enable
571 //
572 PeiHubSetPortFeature (
573 PeiServices,
574 UsbIoPpi,
575 PortNum,
576 EfiUsbPortEnable
577 );
578
579 //
580 // Clear any change status
581 //
582
583 PeiHubClearPortFeature (
584 PeiServices,
585 UsbIoPpi,
586 PortNum,
587 EfiUsbPortEnableChange
588 );
589
590 MicroSecondDelay (10 * 1000);
591
592 return;
593 }