BayTrail/AmiModulePkg/Usb/UsbIrq.c
2018-06-21 15:06:56 +08:00

475 lines
15 KiB
C

//*************************************************************************
//*************************************************************************
//** **
//** (C)Copyright 1985-2016, American Megatrends, Inc. **
//** **
//** All Rights Reserved. **
//** **
//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 **
//** **
//** Phone: (770)-246-8600 **
//** **
//*************************************************************************
/** @file UsbIrq.c
**/
// Module specific Includes
#include <Token.h>
// Consumed Protocols
#include "Rt/AmiDef.h"
#include "Rt/UsbDef.h"
#include "Uhcd.h"
#include <Protocol/Cpu.h>
#include <Protocol/Legacy8259.h>
#include <Protocol/SmmControl2.h>
#include <Protocol/PciIo.h>
#include <Protocol/LegacyBios.h>
#include "UsbIrq.h"
#include <AmiCspLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/UefiLib.h>
EFI_LEGACY_8259_PROTOCOL *mLegacy8259;
EFI_CPU_ARCH_PROTOCOL *CpuArch;
EFI_USB_PROTOCOL *gAmiUsbController;
USB_GLOBAL_DATA *gUsbData;
UINT16 IrqEnableStore;
#if USB_RUNTIME_DRIVER_IN_SMM
EFI_SMM_CONTROL2_PROTOCOL *gSmmCtl = NULL;
#endif
URP_STRUC *UrpBuffer=NULL;
UINT8 UefiIsrInstall = FALSE;
UINT8 LegacyIsrInstall = FALSE;
UINT8 LegacyBiosInstall = FALSE;
EFI_LEGACY_BIOS_PROTOCOL *LegacyBios = NULL;
#ifndef SLAVE_8259_IRQ
#define SLAVE_8259_IRQ 0x02
#endif
#define LEGACY_HOST_INFO_STRUCT 0x24245548 //$$UH
#define LEGACY_HOST_INFO_STRUCT_SIZE 0x4
#define URP_COUNT_SIZE 0x1
#define URP_INFO_SIZE 0x5
#define MEMORY_OFFSET_1M 0x100000
#define MEMORY_OFFSET_896K 0xe0000
#define IRQ0_LEGACY_INT_OFFSET 0x08
#define IRQ8_LEGACY_INT_OFFSET 0x70
#define LEGACY_ISR_TABLE_STRUCT1 0x24245531 //$$U1
#define LEGACY_ISR_TABLE_STRUCT1_SIZE 0x04
#define LEGACY_ISR_TABLE_STRUCT2 0x24245532 //$$U2
#define LEGACY_ISR_TABLE_STRUCT2_SIZE 0x04
#define GenericIrqHandler(x) VOID UsbInterruptHandler##x (\
IN EFI_EXCEPTION_TYPE InterruptType,\
IN EFI_SYSTEM_CONTEXT SystemContext\
)\
{\
UsbInterruptHandler(x);\
}
typedef VOID (INTERRUPT_HANDLER_MAP)(
IN EFI_EXCEPTION_TYPE InterruptType,
IN EFI_SYSTEM_CONTEXT SystemContext );
/**
USB IRQ Interrupt Handler
@param Irq - USB IRQ number.
*/
VOID
EFIAPI
UsbInterruptHandler(
EFI_8259_IRQ Irq
)
{
EFI_TPL OldTpl;
URP_STRUC Params;
UINTN Index;
#if USB_RUNTIME_DRIVER_IN_SMM
URP_STRUC *UrpTemp=NULL;
UINT8 SwSmiValue = USB_SWSMI;
UINT8 DataSize = 1;
#endif
OldTpl = pBS->RaiseTPL(TPL_HIGH_LEVEL);
// clear the interrupt flag
mLegacy8259->EndOfInterrupt(mLegacy8259, Irq);
//Find Usb Host & exectue interrupt.
for (Index = 0;Index < gUsbData->NumOfHc;Index++){
if (gUsbData->HcTable[Index]->Irq == Irq) {
Params.bFuncNumber = USB_API_HC_PROC;
Params.bSubFunc = opHC_ProcessInterrupt;
Params.bRetValue = USB_ERROR;
Params.ApiData.HcProc.paramBuffer = &gUsbData->HcTable[Index];
Params.ApiData.HcProc.paramSize = sizeof(VOID*)*1;
Params.ApiData.HcProc.bHCType = gUsbData->HcTable[Index]->bHCType;
Params.ApiData.HcProc.retVal = 0;
if (gAmiUsbController->UsbInvokeApi) {
gAmiUsbController->UsbInvokeApi(&Params);
} else {
UrpTemp = gUsbData->fpURP;
gUsbData->fpURP = &Params;
gSmmCtl->Trigger(gSmmCtl, &SwSmiValue, &DataSize, 0, 0);
gUsbData->fpURP = UrpTemp;
}
}
}
pBS->RestoreTPL(OldTpl);
}
//
// Usb Interrutp Handler
//
GenericIrqHandler(0)
GenericIrqHandler(1)
GenericIrqHandler(2)
GenericIrqHandler(3)
GenericIrqHandler(4)
GenericIrqHandler(5)
GenericIrqHandler(6)
GenericIrqHandler(7)
GenericIrqHandler(8)
GenericIrqHandler(9)
GenericIrqHandler(10)
GenericIrqHandler(11)
GenericIrqHandler(12)
GenericIrqHandler(13)
GenericIrqHandler(14)
GenericIrqHandler(15)
//
// Usb Interrupt Handler list
//
INTERRUPT_HANDLER_MAP* UsbInterruptHandlerList[] = {
UsbInterruptHandler0,
UsbInterruptHandler1,
UsbInterruptHandler2,
UsbInterruptHandler3,
UsbInterruptHandler4,
UsbInterruptHandler5,
UsbInterruptHandler6,
UsbInterruptHandler7,
UsbInterruptHandler8,
UsbInterruptHandler9,
UsbInterruptHandler10,
UsbInterruptHandler11,
UsbInterruptHandler12,
UsbInterruptHandler13,
UsbInterruptHandler14,
UsbInterruptHandler15,
NULL };
/**
The Eevent wait for Legacy Bios protocol ready.
@param Event
@param Context
@retval None
**/
VOID
EFIAPI
CsmReadyEvent (
IN EFI_EVENT Event,
IN VOID *Context )
{
LegacyBiosInstall = TRUE;
}
/**
Read To Boot Callback routine for init USB legacy ISR.
@param Event
@param Context
@retval None
**/
VOID
EFIAPI
UsbIsrReadyToBoot(
IN EFI_EVENT Event,
IN VOID *Context
)
{
UINT32 UsbIsrStructOffset;
UINT32 UrpTempOffset = (UINT32)UrpBuffer;
UINTN Index;
URP_STRUC *Params;
UINT32 IntTableOffset, IsrSegment;
UINT16 IrqEnableTemp1=0,IrqEnableTemp2=0;
// check LegacyBios protocol ready.
if (LegacyBiosInstall == FALSE) return;
// Check Usb Legacy Isr install.
if(LegacyIsrInstall==TRUE) return;
LegacyIsrInstall = TRUE;
//Open shadow
NbRuntimeShadowRamWrite(TRUE);
// seek e0000~100000 memory to find '$$UH'
for (UsbIsrStructOffset = MEMORY_OFFSET_896K; UsbIsrStructOffset < MEMORY_OFFSET_1M; ++UsbIsrStructOffset) {
if (*(UINT32*)UsbIsrStructOffset == LEGACY_HOST_INFO_STRUCT) break;
}
UsbIsrStructOffset+=LEGACY_HOST_INFO_STRUCT_SIZE;
// Set Urp info to shadow ram.
*(UINT8*)UsbIsrStructOffset = gUsbData->NumOfHc;
UsbIsrStructOffset+=URP_COUNT_SIZE;
for (Index = 0;Index < gUsbData->NumOfHc;Index++){
Params = (URP_STRUC*)UrpTempOffset;
Params->ApiData.HcProc.paramBuffer = &gUsbData->HcTable[Index];
*(UINT8*)UsbIsrStructOffset = gUsbData->HcTable[Index]->Irq;
*(UINT32*)(UsbIsrStructOffset+1) = UrpTempOffset;
UsbIsrStructOffset += URP_INFO_SIZE;
UrpTempOffset += sizeof(URP_STRUC);
}
// close shodow
NbRuntimeShadowRamWrite(FALSE);
// seek e0000~100000 memory to find '$$U1'
for (UsbIsrStructOffset = MEMORY_OFFSET_896K; UsbIsrStructOffset < MEMORY_OFFSET_1M; ++UsbIsrStructOffset) {
if (*(UINT32*)UsbIsrStructOffset == LEGACY_ISR_TABLE_STRUCT1) break;
}
UsbIsrStructOffset += LEGACY_ISR_TABLE_STRUCT1_SIZE;
// seek e0000~100000 memory to find '$$U2'
for (IsrSegment = MEMORY_OFFSET_896K; IsrSegment < MEMORY_OFFSET_1M; ++IsrSegment) {
if (*(UINT32*)IsrSegment == LEGACY_ISR_TABLE_STRUCT2) break;
}
IsrSegment += LEGACY_ISR_TABLE_STRUCT2_SIZE;
IsrSegment = IsrSegment - (UINT16)*(UINT16*)UsbIsrStructOffset;
IsrSegment = IsrSegment >> 4;
for (Index = 0;Index < gUsbData->NumOfHc;Index++){
IrqEnableTemp2 = 1<<(gUsbData->HcTable[Index]->Irq);
if (!(IrqEnableTemp2&IrqEnableTemp1)){
IrqEnableTemp1 |= 1<<(gUsbData->HcTable[Index]->Irq);
IntTableOffset = (UINT32)gUsbData->HcTable[Index]->Irq;
if (gUsbData->HcTable[Index]->Irq<8){
IntTableOffset = (IntTableOffset + IRQ0_LEGACY_INT_OFFSET)*4;
} else {
IntTableOffset = (IntTableOffset - 8 + IRQ8_LEGACY_INT_OFFSET)*4;
}
*(UINT16*)IntTableOffset = *(UINT16*)(gUsbData->HcTable[Index]->Irq*2+UsbIsrStructOffset);
*(UINT16*)(IntTableOffset+2) = (UINT16)IsrSegment;
}
}
}
/**
This function call to install the USB Legacy Irq handler.
@param This - The AMI_USB_ISR_PROTOCOL instance.
@retval EFI_SUCCESS - The USB handler was installed.
@retval EFI_UNSUPPORTED - The platform does not support Usb irq interrupts.
@retval EFI_DEVICE_ERROR - The Usb irq handler could not be registered.
*/
EFI_STATUS
EFIAPI
InstallUsbLegacyInterrupt(
IN AMI_USB_ISR_PROTOCOL *This
)
{
if (UefiIsrInstall==FALSE) return EFI_SUCCESS;
UsbIsrReadyToBoot( NULL,NULL );
return EFI_SUCCESS;
}
/**
This function call to install the USB Irq handler.
@param This - The AMI_USB_ISR_PROTOCOL instance.
@retval EFI_SUCCESS - The USB handler was installed.
@retval EFI_UNSUPPORTED - The platform does not support Usb irq interrupts.
@retval EFI_DEVICE_ERROR - The Usb irq handler could not be registered.
*/
EFI_STATUS
EFIAPI
InstallUsbInterrupt(
IN AMI_USB_ISR_PROTOCOL *This
)
{
EFI_STATUS Status;
UINT32 UsbVector = 0;
VOID *InterruptHandlerAddr;
UINT16 IrqEnableTemp = 1<<(gUsbData->HcTable[gUsbData->NumOfHc-1]->Irq);
UINT32 UrpTempOffset = (UINT32)UrpBuffer;
URP_STRUC Params;
if (UefiIsrInstall==FALSE) UefiIsrInstall = TRUE;
// Init URP_STRUC data.
Params.bFuncNumber = USB_API_HC_PROC;
Params.bSubFunc = opHC_ProcessInterrupt;
Params.bRetValue = USB_ERROR;
Params.ApiData.HcProc.paramBuffer = &gUsbData->HcTable[gUsbData->NumOfHc-1];
Params.ApiData.HcProc.paramSize = sizeof(VOID*)*1;
Params.ApiData.HcProc.bHCType = gUsbData->HcTable[gUsbData->NumOfHc-1]->bHCType;
Params.ApiData.HcProc.retVal = 0;
UrpTempOffset += sizeof(URP_STRUC) * (gUsbData->NumOfHc-1);
// Check this USB Host IRQ Handle has been installed.
if (IrqEnableStore&IrqEnableTemp){
CopyMem((UINT32*)UrpTempOffset, &Params, sizeof(URP_STRUC));
return EFI_SUCCESS;
}
#if USB_RUNTIME_DRIVER_IN_SMM
if (!gSmmCtl){
Status = pBS->LocateProtocol(&gEfiSmmControl2ProtocolGuid, NULL, &gSmmCtl);
ASSERT_EFI_ERROR(Status);
}
#endif
// Get Interrupt vector.
Status = mLegacy8259->GetVector( mLegacy8259, gUsbData->HcTable[gUsbData->NumOfHc-1]->Irq, (UINT8 *) & UsbVector);
ASSERT_EFI_ERROR(Status);
// Get Usb Interrupt handler address.
InterruptHandlerAddr = (VOID*)UsbInterruptHandlerList[gUsbData->HcTable[gUsbData->NumOfHc-1]->Irq];
// Register USB interrupt handler
Status = CpuArch->RegisterInterruptHandler(CpuArch, UsbVector, InterruptHandlerAddr);
ASSERT_EFI_ERROR(Status);
if (!EFI_ERROR(Status)){
IrqEnableStore |= 1<<(gUsbData->HcTable[gUsbData->NumOfHc-1]->Irq);
// Enable USB Irq.
mLegacy8259->EnableIrq(mLegacy8259, gUsbData->HcTable[gUsbData->NumOfHc-1]->Irq, FALSE);
// Enable slave 8259.
if (gUsbData->HcTable[gUsbData->NumOfHc-1]->Irq>7)
mLegacy8259->EnableIrq(mLegacy8259, SLAVE_8259_IRQ, FALSE);
CopyMem((UINT32*)UrpTempOffset, &Params, sizeof(URP_STRUC));
}
return Status;
}
//
// USB isr protocol
//
AMI_USB_ISR_PROTOCOL gAmiUsbIsrProtocol =
{
InstallUsbInterrupt,
InstallUsbLegacyInterrupt
};
/**
Initialize the USB IRQ driver
@param ImageHandle - ImageHandle of the loaded driver
@param SystemTable - Pointer to the System Table
@retval EFI_SUCCESS - USB ISR Protocol created
@retval EFI_OUT_OF_RESOURCES - Not enough resources available to initialize driver.
@retval EFI_DEVICE_ERROR - A device error occured attempting to initialize the driver.
*/
EFI_STATUS
EFIAPI
UsbIrqInitEntry(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_GUID gAmiUsbIsrProtocolGuid = AMI_USB_ISR_PROTOCOL_GUID;
EFI_EVENT ReadyToBoot;
EFI_EVENT mLegacyBiosEvent;
VOID *mLegacyBiosReg;
InitAmiLib(ImageHandle, SystemTable);
// Find the Legacy Interrupt(8259) Protocol
Status = gBS->LocateProtocol(&gEfiLegacy8259ProtocolGuid, 0, &mLegacy8259);
ASSERT_EFI_ERROR(Status);
// Find the CPU Arch Protocol
Status = gBS->LocateProtocol(&gEfiCpuArchProtocolGuid, 0, &CpuArch);
ASSERT_EFI_ERROR(Status);
// Find the AMI USB protocol.
Status = gBS->LocateProtocol(&gEfiUsbProtocolGuid, NULL, &gAmiUsbController);
ASSERT_EFI_ERROR(Status);
gUsbData = gAmiUsbController->USBDataPtr;
UrpBuffer = (URP_STRUC*) 0xFFFFFFFF;
Status = gBS->AllocatePages(
AllocateMaxAddress,
EfiRuntimeServicesData,
EFI_SIZE_TO_PAGES(sizeof(URP_STRUC) * 8),
(EFI_PHYSICAL_ADDRESS*)&UrpBuffer);
ASSERT_EFI_ERROR(Status);
// Find the Legacy Bios Protocol
Status = gBS->LocateProtocol(&gEfiLegacyBiosProtocolGuid, 0, &LegacyBios);
if (!EFI_ERROR(Status)){
LegacyBiosInstall = TRUE;
} else {
RegisterProtocolCallback(
&gEfiLegacyBiosProtocolGuid,
CsmReadyEvent,
NULL,
&mLegacyBiosEvent,
&mLegacyBiosReg);
}
// A event for init USB legacy isr.
Status = EfiCreateEventReadyToBootEx(
TPL_CALLBACK, UsbIsrReadyToBoot,
NULL, &ReadyToBoot);
Status = gBS->InstallProtocolInterface(
&ImageHandle,
&gAmiUsbIsrProtocolGuid,
EFI_NATIVE_INTERFACE,
&gAmiUsbIsrProtocol );
return Status;
}
//*************************************************************************
//*************************************************************************
//** **
//** (C)Copyright 1985-2016, American Megatrends, Inc. **
//** **
//** All Rights Reserved. **
//** **
//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 **
//** **
//** Phone: (770)-246-8600 **
//** **
//*************************************************************************
//*************************************************************************