/** @file
Implementation of Usb Controller PPI.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <PiPei.h>
#include <Ppi/UsbController.h>
#include <Library/DebugLib.h>
#include <Library/PeimEntryPoint.h>
#include <Library/PeiServicesLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/PcdLib.h>
#include <Library/PciLib.h>
#include <Library/IoLib.h>
#include "UsbPei.h"
//
// Globals
//
//
EFI_PEI_PPI_DESCRIPTOR mPpiList = {
(EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
&gPeiUsbControllerPpiGuid,
NULL
};
UINTN mIohOhciPciReg[IOH_MAX_OHCI_USB_CONTROLLERS] = {
PCI_LIB_ADDRESS (IOH_USB_BUS_NUMBER, IOH_USB_OHCI_DEVICE_NUMBER, IOH_OHCI_FUNCTION_NUMBER, 0)
};
UINTN mIohEhciPciReg[IOH_MAX_EHCI_USB_CONTROLLERS] = {
PCI_LIB_ADDRESS (IOH_USB_BUS_NUMBER, IOH_USB_EHCI_DEVICE_NUMBER, IOH_EHCI_FUNCTION_NUMBER, 0),
};
/**
When EHCI get started in DXE, OHCI couldn't get the ownership
of roothub after warm reset because CF@EHCI hasn't been cleared.
We should clear that reg before UpdateBootMode. But Reg@EHCI is
memory-mapped, so need assume a range of space without conflict
in PCI memory space.
@param[in] PeiServices The pointer of EFI_PEI_SERVICES
**/
VOID
SwitchConfigFlag (
IN EFI_PEI_SERVICES **PeiServices
)
{
UINT32 SavBaseAddr;
UINT32 UsbBaseAddr;
UINT16 SaveCmdData;
UINT8 EhciCapLen;
UINT8 Index;
UsbBaseAddr = 0;
for (Index = 0; Index < IOH_MAX_EHCI_USB_CONTROLLERS; Index++) {
UsbBaseAddr = PcdGet32(PcdPeiQNCUsbControllerMemoryBaseAddress);
//
// Manage EHCI on IOH, set UsbBaseAddr
//
SavBaseAddr = PciRead32 (mIohEhciPciReg[Index] | R_IOH_USB_MEMBAR);
PciWrite32 (mIohEhciPciReg[Index] | R_IOH_USB_MEMBAR, UsbBaseAddr);
//
// Save Cmd register
//
SaveCmdData = PciRead16 (mIohEhciPciReg[Index] | R_IOH_USB_COMMAND);
//
// Enable EHCI on IOH
//
PciOr16 (mIohEhciPciReg[Index] | R_IOH_USB_COMMAND, B_IOH_USB_COMMAND_BME | B_IOH_USB_COMMAND_MSE );
//
// Clear CF register on EHCI
//
EhciCapLen = MmioRead8 (UsbBaseAddr + R_IOH_EHCI_CAPLENGTH);
MmioWrite32 (UsbBaseAddr + EhciCapLen + R_IOH_EHCI_CONFIGFLAGS, 0);
DEBUG ((EFI_D_INFO, "CF@EHCI = %x \n", UsbBaseAddr + EhciCapLen + R_IOH_EHCI_CONFIGFLAGS));
//
// Restore EHCI UsbBaseAddr in PCI space
//
PciWrite32 (mIohEhciPciReg[Index] | R_IOH_USB_MEMBAR, SavBaseAddr);
//
// Restore EHCI Command register in PCI space
//
PciWrite16(mIohEhciPciReg[Index] | R_IOH_USB_COMMAND, SaveCmdData);
}
}
/**
Retrieved specified the USB controller information.
@param PeiServices The pointer of EFI_PEI_SERVICES.
@param This This PEI_USB_CONTROLLER_PPI instance.
@param UsbControllerId Indicate which usb controller information will be retrieved.
@param ControllerType Indicate the controller is Ehci, Ohci, OHCI
@param BaseAddress Indicate the memory bar of the controller
@retval EFI_SUCCESS The reset operation succeeded.
@retval EFI_INVALID_PARAMETER Attributes is not valid.
**/
EFI_STATUS
GetOhciController (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_USB_CONTROLLER_PPI *This,
IN UINT8 UsbControllerId,
IN UINTN *ControllerType,
IN UINTN *BaseAddress
)
{
IOH_OHCI_DEVICE *PeiIohOhciDev;
PeiIohOhciDev = IOH_OHCI_DEVICE_FROM_THIS (This);
if (UsbControllerId >= IOH_MAX_OHCI_USB_CONTROLLERS) {
return EFI_INVALID_PARAMETER;
}
*ControllerType = PEI_OHCI_CONTROLLER;
*BaseAddress = PeiIohOhciDev->MmioBase[UsbControllerId];
return EFI_SUCCESS;
}
/**
Retrieved specified the USB controller information.
@param PeiServices The pointer of EFI_PEI_SERVICES.
@param This This PEI_USB_CONTROLLER_PPI instance.
@param UsbControllerId Indicate which usb controller information will be retrieved.
@param ControllerType Indicate the controller is Ehci, Ohci, OHCI
@param BaseAddress Indicate the memory bar of the controller
@retval EFI_SUCCESS The reset operation succeeded.
@retval EFI_INVALID_PARAMETER Attributes is not valid.
**/
EFI_STATUS
GetEhciController (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_USB_CONTROLLER_PPI *This,
IN UINT8 UsbControllerId,
IN UINTN *ControllerType,
IN UINTN *BaseAddress
)
{
IOH_EHCI_DEVICE *PeiIohEhciDev;
PeiIohEhciDev = IOH_EHCI_DEVICE_FROM_THIS (This);
if (UsbControllerId >= IOH_MAX_EHCI_USB_CONTROLLERS) {
return EFI_INVALID_PARAMETER;
}
*ControllerType = PEI_EHCI_CONTROLLER;
*BaseAddress = PeiIohEhciDev->MmioBase[UsbControllerId];
return EFI_SUCCESS;
}
/**
Retrieved specified the USB controller information.
@param IohOhciPciReg Ohci device address list.
@param OhciCount The count of the OHCI
@param IohEhciPciReg Ehci device address list.
@param EhciCount The count of the EHCI
**/
VOID
EnableBusMaster (
IN UINTN IohOhciPciReg[],
IN UINT8 OhciCount,
IN UINTN IohEhciPciReg[],
IN UINT8 EhciCount
)
{
UINT8 Index;
UINT16 CmdReg;
for (Index = 0; Index < OhciCount; Index ++) {
CmdReg = PciRead16 (IohOhciPciReg[Index] | R_IOH_USB_COMMAND);
CmdReg = (UINT16) (CmdReg | B_IOH_USB_COMMAND_BME );
PciWrite16 (IohOhciPciReg[Index] | R_IOH_USB_COMMAND, CmdReg);
}
for (Index = 0; Index < EhciCount; Index ++) {
CmdReg = PciRead16 (IohEhciPciReg[Index] | R_IOH_USB_COMMAND);
CmdReg = (UINT16) (CmdReg | B_IOH_USB_COMMAND_BME );
PciWrite16 (IohEhciPciReg[Index] | R_IOH_USB_COMMAND, CmdReg);
}
}
PEI_USB_CONTROLLER_PPI mUsbControllerPpi[2] = { {GetOhciController}, {GetEhciController}};
/**
@param FileHandle Handle of the file being invoked.
@param PeiServices Describes the list of possible PEI Services.
@retval EFI_SUCCESS PPI successfully installed
**/
EFI_STATUS
PeimInitializeIchUsb (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
EFI_STATUS Status;
UINTN i;
EFI_PHYSICAL_ADDRESS AllocateAddress;
IOH_OHCI_DEVICE *PeiIohOhciDev;
IOH_EHCI_DEVICE *PeiIohEhciDev;
UINT16 CmdReg;
Status = PeiServicesAllocatePages (
EfiBootServicesCode,
1,
&AllocateAddress
);
ASSERT_EFI_ERROR (Status);
EnableBusMaster (
mIohOhciPciReg,
IOH_MAX_OHCI_USB_CONTROLLERS,
mIohEhciPciReg,
IOH_MAX_EHCI_USB_CONTROLLERS
);
if (FeaturePcdGet (PcdEhciRecoveryEnabled)) {
DEBUG ((EFI_D_INFO, "UsbPei:EHCI is used for recovery\n"));
//
// EHCI recovery is enabled
//
PeiIohEhciDev = (IOH_EHCI_DEVICE *)((UINTN)AllocateAddress);
ZeroMem (PeiIohEhciDev, sizeof(IOH_EHCI_DEVICE));
PeiIohEhciDev->Signature = PEI_IOH_EHCI_SIGNATURE;
CopyMem(&(PeiIohEhciDev->UsbControllerPpi), &mUsbControllerPpi[1], sizeof(PEI_USB_CONTROLLER_PPI));
CopyMem(&(PeiIohEhciDev->PpiList), &mPpiList, sizeof(mPpiList));
PeiIohEhciDev->PpiList.Ppi = &PeiIohEhciDev->UsbControllerPpi;
//
// Assign resources and enable Ehci controllers
//
for (i = 0; i < IOH_MAX_EHCI_USB_CONTROLLERS; i++) {
DEBUG ((EFI_D_INFO, "UsbPei:Enable the %dth EHCI controller for recovery\n", i));
PeiIohEhciDev->MmioBase[i] = PcdGet32(PcdPeiQNCUsbControllerMemoryBaseAddress) + IOH_USB_CONTROLLER_MMIO_RANGE * i;
//
// Assign base address register, Enable Bus Master and Memory Io
//
PciWrite32 (mIohEhciPciReg[i] | R_IOH_USB_MEMBAR, PeiIohEhciDev->MmioBase[i]);
CmdReg = PciRead16 (mIohEhciPciReg[i] | R_IOH_USB_COMMAND);
CmdReg = (UINT16) (CmdReg | B_IOH_USB_COMMAND_MSE | B_IOH_USB_COMMAND_BME );
PciWrite16 (mIohEhciPciReg[i] | R_IOH_USB_COMMAND, CmdReg);
}
//
// Install USB Controller PPI
//
Status = (**PeiServices).InstallPpi (
PeiServices,
&PeiIohEhciDev->PpiList
);
ASSERT_EFI_ERROR (Status);
} else {
DEBUG ((EFI_D_INFO, "UsbPei:OHCI is used for recovery\n"));
//
// OHCI recovery is enabled
//
SwitchConfigFlag ((EFI_PEI_SERVICES**)PeiServices);
PeiIohOhciDev = (IOH_OHCI_DEVICE *)((UINTN)AllocateAddress);
ZeroMem (PeiIohOhciDev, sizeof(IOH_OHCI_DEVICE));
PeiIohOhciDev->Signature = PEI_IOH_OHCI_SIGNATURE;
CopyMem(&(PeiIohOhciDev->UsbControllerPpi), &mUsbControllerPpi[0], sizeof(PEI_USB_CONTROLLER_PPI));
CopyMem(&(PeiIohOhciDev->PpiList), &mPpiList, sizeof(mPpiList));
PeiIohOhciDev->PpiList.Ppi = &PeiIohOhciDev->UsbControllerPpi;
//
// Assign resources and enable OHCI controllers
//
for (i = 0; i < IOH_MAX_OHCI_USB_CONTROLLERS; i++) {
DEBUG ((EFI_D_INFO, "UsbPei:Enable the %dth OHCI controller for recovery\n", i));
PeiIohOhciDev->MmioBase[i] = PcdGet32(PcdPeiQNCUsbControllerMemoryBaseAddress) + IOH_USB_CONTROLLER_MMIO_RANGE * i;
//
// Assign base address register, Enable Bus Master and Memory Io
//
PciWrite32 (mIohOhciPciReg[i] | R_IOH_USB_MEMBAR, PeiIohOhciDev->MmioBase[i]);
Status = PeiServicesAllocatePages (
EfiBootServicesCode,
1,
&AllocateAddress
);
ASSERT_EFI_ERROR (Status);
MmioWrite32(PeiIohOhciDev->MmioBase[i] + R_IOH_USB_OHCI_HCCABAR, (UINT32)AllocateAddress);
CmdReg = PciRead16 (mIohOhciPciReg[i] | R_IOH_USB_COMMAND);
CmdReg = (UINT16) (CmdReg | B_IOH_USB_COMMAND_MSE | B_IOH_USB_COMMAND_BME );
PciWrite16 (mIohOhciPciReg[i] | R_IOH_USB_COMMAND, CmdReg);
}
//
// Install USB Controller PPI
//
Status = (**PeiServices).InstallPpi (
PeiServices,
&PeiIohOhciDev->PpiList
);
ASSERT_EFI_ERROR (Status);
}
return Status;
}