alder_lake_bios/Intel/AlderLake/AlderLakePlatSamplePkg/Features/Usb/UsbDeviceDxe/UsbDeviceDxe.c

522 lines
14 KiB
C

/** @file
Implementation of USBFN protocol driver.
@copyright
INTEL CONFIDENTIAL
Copyright 2015 - 2020 Intel Corporation.
The source code contained or described herein and all documents related to the
source code ("Material") are owned by Intel Corporation or its suppliers or
licensors. Title to the Material remains with Intel Corporation or its suppliers
and licensors. The Material may contain trade secrets and proprietary and
confidential information of Intel Corporation and its suppliers and licensors,
and is protected by worldwide copyright and trade secret laws and treaty
provisions. No part of the Material may be used, copied, reproduced, modified,
published, uploaded, posted, transmitted, distributed, or disclosed in any way
without Intel's prior express written permission.
No license under any patent, copyright, trade secret or other intellectual
property right is granted to or conferred upon you by disclosure or delivery
of the Materials, either expressly, by implication, inducement, estoppel or
otherwise. Any license under such intellectual property rights must be
express and approved by Intel in writing.
Unless otherwise agreed by Intel in writing, you may not remove or alter
this notice or any other notice embedded in Materials by Intel or
Intel's suppliers or licensors in any way.
This file contains a 'Sample Driver' and is licensed as such under the terms
of your license agreement with Intel or your vendor. This file may be modified
by the user, subject to the additional terms of the license agreement.
@par Specification Reference:
**/
#include "UsbDeviceDxe.h"
#include <Library/PchPciBdfLib.h>
EFI_DRIVER_BINDING_PROTOCOL mUsbDeviceDxeDriverBinding = {
UsbDeviceDxeDriverSupported,
UsbDeviceDxeDriverStart,
UsbDeviceDxeDriverStop,
0x1,
NULL,
NULL
};
#define DEVICE_CONNECT_TIMEOUT_IN_SECS 5 * 60 //Wait for 5 Mins for cable detection
/**
This function can be called to poll for certain value within a time given.
@param[in] MmioAddress The Mmio Address.
@param[in] BitMask Bits to be masked.
@param[in] BitValue Value to be polled.
#param[in] DelayTime Delay time in terms of 100 micro seconds.
@retval EFI_SUCCESS Successfully polled the value.
@retval EFI_TIMEOUT Timeout while polling the value.
**/
EFI_STATUS
EFIAPI
PchMmioPoll32 (
IN UINTN MmioAddress,
IN UINT32 BitMask,
IN UINT32 BitValue,
IN UINT16 DelayTime
)
{
UINT32 LoopTime;
UINT8 PollSuccess;
LoopTime = 0;
PollSuccess = 0;
DEBUG ((DEBUG_INFO, "PchMmioPoll32, BitMask: %x, BitValue: %x\n", BitMask, BitValue));
for (LoopTime = 0; LoopTime < DelayTime; LoopTime++) {
if ((MmioRead32 (MmioAddress) & BitMask) == (BitValue & BitMask)) {
PollSuccess = 1;
break;
} else {
gBS->Stall (100);
}
}
if (PollSuccess) {
return EFI_SUCCESS;
} else {
return EFI_TIMEOUT;
}
}
/**
Platform specific initialization.
**/
VOID
EFIAPI
PlatformSpecificInit (
VOID
)
{
UINT64 OtgPciMmBase;
EFI_STATUS Status;
WDT_PROTOCOL *WdtProtocol;
UINT8 WdtState;
WdtState = 1;
Status = EFI_SUCCESS;
Status = gBS->LocateProtocol (&gWdtProtocolGuid, NULL, (VOID **)&WdtProtocol);
if (!EFI_ERROR(Status)) {
WdtState = WdtProtocol->IsWdtEnabled ();
DEBUG ((DEBUG_INFO, "WdtState %d\n", WdtState));
}
//
// Configure Controllers.
//
OtgPciMmBase = PchXdciPciCfgBase ();
DEBUG ((DEBUG_INFO, "OtgPciMmBase: %x\n", OtgPciMmBase));
PciSegmentWrite8 ((OtgPciMmBase + 0x04), 0x06); // enable MSE to access xDCI MMIO
return;
}
VOID
EFIAPI
UsbDeviceDxeExitBootService (
EFI_EVENT Event,
VOID *Context
)
{
USB_XDCI_DEV_CONTEXT *UsbXdciDevContext;
UsbXdciDevContext = (USB_XDCI_DEV_CONTEXT *) Context;
DEBUG ((EFI_D_INFO, "UsbDeviceDxeExitBootService enter\n"));
if (UsbXdciDevContext->XdciPollTimer != NULL) {
gBS->SetTimer (UsbXdciDevContext->XdciPollTimer, TimerCancel, 0);
gBS->CloseEvent (UsbXdciDevContext->XdciPollTimer);
UsbXdciDevContext->XdciPollTimer = NULL;
}
return;
}
/**
The USB bus driver entry pointer.
@param ImageHandle The driver image handle.
@param SystemTable The system table.
@return EFI_SUCCESS The component name protocol is installed.
@return Others Failed to init the usb driver.
**/
EFI_STATUS
EFIAPI
UsbDeviceDxeEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
BOOLEAN UsbFnEnable;
SETUP_DATA SystemConfiguration;
UINTN VarSize;
DEBUG ((DEBUG_INFO, "UsbDeviceDxeEntryPoint entry\n"));
UsbFnEnable = FALSE;
VarSize = sizeof (SETUP_DATA);
Status = gRT->GetVariable (
L"Setup",
&gSetupVariableGuid,
NULL,
&VarSize,
&SystemConfiguration
);
if (!EFI_ERROR(Status)) {
UsbFnEnable = SystemConfiguration.UsbFnEnable;
}
DEBUG ((DEBUG_INFO, "UsbFnEnable: %x\n", UsbFnEnable));
if (UsbFnEnable == TRUE) {
Status = EfiLibInstallDriverBindingComponentName2 (
ImageHandle,
SystemTable,
&mUsbDeviceDxeDriverBinding,
ImageHandle,
&mUsbDeviceDxeComponentName,
&mUsbDeviceDxeComponentName2
);
}
DEBUG ((DEBUG_INFO, "UsbDeviceDxeEntryPoint exit, Status: %r\n", Status));
return Status;
}
/**
Check whether USB bus driver support this device.
@param This The USB bus driver binding protocol.
@param Controller The controller handle to check.
@param RemainingDevicePath The remaining device path.
@retval EFI_SUCCESS The bus supports this controller.
@retval EFI_UNSUPPORTED This device isn't supported.
**/
EFI_STATUS
EFIAPI
UsbDeviceDxeDriverSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_STATUS Status;
EFI_PCI_IO_PROTOCOL *PciIo;
USB_CLASSC UsbClassCReg;
Status = gBS->OpenProtocol (
Controller,
&gEfiPciIoProtocolGuid,
(VOID **) &PciIo,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
Status = PciIo->Pci.Read (
PciIo,
EfiPciIoWidthUint8,
PCI_CLASSCODE_OFFSET,
sizeof (USB_CLASSC) / sizeof (UINT8),
&UsbClassCReg
);
if (EFI_ERROR (Status)) {
Status = EFI_UNSUPPORTED;
goto ON_EXIT;
}
//
// Test whether the controller belongs to USB device type
//
// 0x0C03FE / 0x0C0380
if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||
(UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||
((UsbClassCReg.ProgInterface != PCI_IF_USBDEV) && (UsbClassCReg.ProgInterface != 0x80))) {
Status = EFI_UNSUPPORTED;
}
ON_EXIT:
gBS->CloseProtocol (
Controller,
&gEfiPciIoProtocolGuid,
This->DriverBindingHandle,
Controller
);
return Status;
}
/**
Start to process the controller.
@param This The USB bus driver binding instance.
@param Controller The controller to check.
@param RemainingDevicePath The remaining device patch.
@retval EFI_SUCCESS The controller is controlled by the usb bus.
@retval EFI_ALREADY_STARTED The controller is already controlled by the usb
bus.
@retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
**/
EFI_STATUS
EFIAPI
UsbDeviceDxeDriverStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_STATUS Status;
USB_XDCI_DEV_CONTEXT *UsbXdciDevContext;
EFI_PCI_IO_PROTOCOL *PciIo;
UINT32 XdciMmioBarHigh;
EFI_EVENT ExitBootServicesEvent;
DEBUG ((USB_FUIO_DEBUG_LOAD, "UsbFunIoEntryPoint - Entry\n"));
UsbXdciDevContext = NULL;
XdciMmioBarHigh = 0;
//
// Provide protocol interface
//
//
// Get the PCI I/O Protocol on PciHandle
//
Status = gBS->OpenProtocol (
Controller,
&gEfiPciIoProtocolGuid,
(VOID **) &PciIo,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
goto ErrorExit;
}
UsbXdciDevContext = AllocateZeroPool (sizeof (USB_XDCI_DEV_CONTEXT));
if (UsbXdciDevContext == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ErrorExit;
}
//
// Initialize the driver context
//
UsbXdciDevContext->StartUpController = FALSE;
UsbXdciDevContext->XdciHandle = Controller;
UsbXdciDevContext->FirstNodePtr = NULL;
UsbXdciDevContext->Signature = EFI_USB_DEV_SIGNATURE;
PciIo->Pci.Read (
PciIo,
EfiPciIoWidthUint32,
R_PCH_OTG_BAR0,
1,
&UsbXdciDevContext->XdciMmioBarAddr
);
if ((UsbXdciDevContext->XdciMmioBarAddr & B_PCH_OTG_BAR0_TYPE) == B_PCH_OTG_BAR0_64_BIT) {
PciIo->Pci.Read (
PciIo,
EfiPciIoWidthUint32,
R_PCH_OTG_BAR_HIGH,
1,
&XdciMmioBarHigh
);
}
UsbXdciDevContext->XdciMmioBarAddr = ((UINT64) XdciMmioBarHigh << 32) | (UsbXdciDevContext->XdciMmioBarAddr & B_PCH_OTG_BAR0_BA);
DEBUG ((USB_FUIO_DEBUG_INFO, "USB DEV mode IO addr 0x%016lx\n", UsbXdciDevContext->XdciMmioBarAddr));
if (UsbXdciDevContext->XdciMmioBarAddr == 0) {
Status = EFI_DEVICE_ERROR;
}
CopyMem (
&(UsbXdciDevContext->UsbFunIoProtocol),
&mUsbFunIoProtocol,
sizeof (EFI_USBFN_IO_PROTOCOL)
);
CopyMem (
&(UsbXdciDevContext->UsbDevModeProtocol),
&mUsbDeviceModeProtocol,
sizeof (EFI_USB_DEVICE_MODE_PROTOCOL)
);
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
UsbDeviceDxeExitBootService,
UsbXdciDevContext,
&gEfiEventExitBootServicesGuid,
&ExitBootServicesEvent
);
if (EFI_ERROR (Status)) {
goto ErrorExit;
}
Status = gBS->InstallMultipleProtocolInterfaces (
&UsbXdciDevContext->XdciHandle,
&gUsbFnIoProtocolGuid,
&UsbXdciDevContext->UsbFunIoProtocol,
&gUsbDeviceModeProtocolGuid,
&UsbXdciDevContext->UsbDevModeProtocol,
NULL
);
if (EFI_ERROR (Status)) {
DEBUG ((USB_FUIO_DEBUG_ERROR, "ERROR - Failed to install upper protocol, Status: %r\n", Status));
goto ErrorExit;
}
DEBUG ((USB_FUIO_DEBUG_LOAD, "Done - install upper protocol complete\n"));
DEBUG ((USB_FUIO_DEBUG_LOAD, "UsbFunIoEntryPoint - Exit\n"));
return Status;
ErrorExit:
gBS->CloseProtocol (
Controller,
&gEfiPciIoProtocolGuid,
This->DriverBindingHandle,
Controller
);
if (UsbXdciDevContext != NULL) {
if (UsbXdciDevContext->XdciPollTimer != NULL) {
gBS->CloseEvent (UsbXdciDevContext->XdciPollTimer);
UsbXdciDevContext->XdciPollTimer = NULL;
}
FreePool (UsbXdciDevContext);
}
DEBUG ((USB_FUIO_DEBUG_ERROR, "ERROR - UsbFunIoEntryPoint - Exit\n"));
DEBUG ((DEBUG_INFO, "UsbDeviceDxeDriverStart, Status: %r\n", Status));
return Status;
}
/**
Stop handle the controller by this USB bus driver.
@param This The USB bus driver binding protocol.
@param Controller The controller to release.
@param NumberOfChildren The child of USB bus that opened controller
BY_CHILD.
@param ChildHandleBuffer The array of child handle.
@retval EFI_SUCCESS The controller or children are stopped.
@retval EFI_DEVICE_ERROR Failed to stop the driver.
**/
EFI_STATUS
EFIAPI
UsbDeviceDxeDriverStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
)
{
EFI_USBFN_IO_PROTOCOL *UsbFunIoProtocol;
EFI_STATUS Status;
USB_XDCI_DEV_CONTEXT *UsbXdciDevContext;
//
// Locate USB_BUS for the current host controller
//
Status = gBS->OpenProtocol (
Controller,
&gUsbFnIoProtocolGuid,
(VOID**) &UsbFunIoProtocol,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return Status;
}
UsbXdciDevContext = USBFUIO_CONTEXT_FROM_PROTOCOL (UsbFunIoProtocol);
//
// free pool
//
while (UsbXdciDevContext->FirstNodePtr != NULL) {
RemoveNode (UsbFunIoProtocol, UsbXdciDevContext->FirstNodePtr);
}
Status = gBS->UninstallMultipleProtocolInterfaces (
UsbXdciDevContext->XdciHandle,
&gUsbFnIoProtocolGuid,
&UsbXdciDevContext->UsbFunIoProtocol,
&gUsbDeviceModeProtocolGuid,
&UsbXdciDevContext->UsbDevModeProtocol,
NULL
);
//
// Deinit??
//
if (UsbXdciDevContext->StartUpController == TRUE) {
Status = StopController (UsbFunIoProtocol);
DEBUG ((USB_FUIO_DEBUG_INFO, "USB DEV mode STOP UsbFnDeInitDevice %r\n", Status));
}
if (UsbXdciDevContext->XdciPollTimer != NULL) {
gBS->SetTimer (UsbXdciDevContext->XdciPollTimer, TimerCancel, 0);
gBS->CloseEvent (UsbXdciDevContext->XdciPollTimer);
UsbXdciDevContext->XdciPollTimer = NULL;
}
gBS->CloseProtocol (
Controller,
&gEfiPciIoProtocolGuid,
This->DriverBindingHandle,
Controller
);
if (UsbXdciDevContext->DevInfoPtr != NULL) {
FreeDeviceInfo(UsbXdciDevContext->DevInfoPtr);
FreePool(UsbXdciDevContext->DevInfoPtr);
}
FreePool (UsbXdciDevContext);
DEBUG ((DEBUG_INFO, "UsbDeviceDxeDriverStop, Status: %r\n", Status));
return EFI_SUCCESS;
}