Ryzen/AmiModulePkg/KbcEmulation/KbcUhciDxe.c
2022-12-23 15:14:44 +08:00

274 lines
7.6 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 KbcUhciDxe.c
Functions for UHCI in Non-Smm mode.
**/
//---------------------------------------------------------------------------
#include "KbcEmulDxe.h"
#include "KbcUhci.h"
//---------------------------------------------------------------------------
extern BOOLEAN KbcPresent;
static UINT16 SavedLegcyStatus = 0;
static UINT16 UhciTrapByMask = UHCI_TRAPBY_MASK_WITHOUTKBC;
static UINT16 UhciTrapEnMask = UHCI_TRAPEN_MASK_WITHOUTKBC;
UHCI_EMUL_DEVICE Uhci_Hc_Array[] = {
#if defined(UHCI_EMUL_PCI_DEVICES)
UHCI_EMUL_PCI_DEVICES,
#endif
#if defined(INTEL_LEGACY_USB_KBC_EMUL_CONTROL_REG_PCI_DEVICES)
INTEL_LEGACY_USB_KBC_EMUL_CONTROL_REG_PCI_DEVICES,
#endif
{ 0xFFFF, 0xFF, 0xFF, 0xFF, 0xFF }
};
UINTN Uhci_Hc_Array_Size = sizeof(Uhci_Hc_Array) / sizeof(Uhci_Hc_Array[0]);
/**
Validate the UHCI controller.
@param Uhc
@retval Boolean
**/
BOOLEAN
NonSmmValidateUhc (
UHCI_EMUL_DEVICE *Uhc
)
{
UINT32 Data32 = 0;
// End of the Device List.
if(Uhc->BusDevFunc == 0xFFFF) {
return FALSE;
}
if (NonSmmReadPCIConfig (Uhc->BusDevFunc, 0) == 0xFFFFFFFF) {
return FALSE;
}
Data32 = NonSmmReadPCIConfig (Uhc->BusDevFunc, 8) >> 8;
if (Data32 != (*((UINT32*)&Uhc->InterfaceType) & 0x00FFFFFF)) {
return FALSE;
}
return TRUE;
}
/**
Write the Value in to all the UHCI controller Legacy Regsiters.
@param Value
@retval VOID
**/
VOID
NonSmmWriteLegKeyReg (
UINT16 Value
)
{
UINTN UhciCount;
for( UhciCount = 0; UhciCount < Uhci_Hc_Array_Size; ++UhciCount ){
if (!NonSmmValidateUhc(&Uhci_Hc_Array[UhciCount])) {
continue;
}
NonSmmWordWritePCIConfig( Uhci_Hc_Array[UhciCount].BusDevFunc,
Uhci_Hc_Array[UhciCount].LegacyRegOffset, Value);
}
return;
}
/**
Clear the Port6064 SMI Status
@param Value
@retval VOID
**/
VOID
NonSmmClearLegKeyStatusReg (
UINT16 Value
)
{
UINTN UhciCount;
#if ICH10_WORKAROUND
//
// Enable all the UCHI controller
// In ICH10 chipset, we need to clear the Port 6064 SMI status in disabled controller
// also. Otherwise it's keep on generating SMI
//
EnableAllUhciController();
#endif
for( UhciCount = 0; UhciCount < Uhci_Hc_Array_Size; ++UhciCount ){
if (!NonSmmValidateUhc(&Uhci_Hc_Array[UhciCount])) {
continue;
}
NonSmmWordWritePCIConfig( Uhci_Hc_Array[UhciCount].BusDevFunc,
Uhci_Hc_Array[UhciCount].LegacyRegOffset, Value);
}
#if ICH10_WORKAROUND
//
// Restore the UCHI controller's in RCBA Reg
//
RestoreUhciControllerStatus();
#endif
return;
}
/**
Check if trap status is set in UHCI HC.
@param None
@retval BOOLEAN
**/
BOOLEAN
NonSmmUhci_HasTrapStatus ()
{
UINT16 LegcyKeyStatus = 0;
UINTN UhciCount;
for( UhciCount = 0; UhciCount < Uhci_Hc_Array_Size; ++UhciCount ){
if (!NonSmmValidateUhc(&Uhci_Hc_Array[UhciCount])) {
continue;
}
LegcyKeyStatus =(UINT16) NonSmmReadPCIConfig( Uhci_Hc_Array[UhciCount].BusDevFunc ,
Uhci_Hc_Array[UhciCount].LegacyRegOffset );
break;
}
return ((LegcyKeyStatus & UhciTrapEnMask) != 0 );
}
/**
Enable/Disable trapping in UHCI HC.
@param TrapEnable
@retval BOOLEAN
**/
BOOLEAN
NonSmmUhci_TrapEnable (
BOOLEAN TrapEnable
)
{
UINT16 LegcyKeyStatus;
EFI_TPL OldTpl;
UINT16 UhciCount;
for( UhciCount = 0; UhciCount < Uhci_Hc_Array_Size; ++UhciCount ){
if (!NonSmmValidateUhc(&Uhci_Hc_Array[UhciCount])) {
continue;
}
LegcyKeyStatus =(UINT16) NonSmmReadPCIConfig( Uhci_Hc_Array[UhciCount].BusDevFunc ,
Uhci_Hc_Array[UhciCount].LegacyRegOffset );
//
//Record first time that trapping is disabled. Record only trap status bits handled by Trap handler
//
if( (LegcyKeyStatus & UhciTrapEnMask)== UhciTrapEnMask &&
( LegcyKeyStatus & UhciTrapByMask) != 0 ){
//If legacy I/O caused SMI# and this is first time we are in uhci_trapEnable
//then trapping in LEGKEY reg must have been enabled and one trap status is set.
//Any port 60/64 operation within SMI# must be wrapped into
//enable/ disable&clear status. So subsequent trapEnable will not produce any
//trap statuses
SavedLegcyStatus |= LegcyKeyStatus;
}
OldTpl = pBS->RaiseTPL(TPL_HIGH_LEVEL);
if(TrapEnable){
//
// Clear the status
//
NonSmmClearLegKeyStatusReg(LegcyKeyStatus | UhciTrapByMask);
//
// Enable Traps
//
NonSmmWriteLegKeyReg( LegcyKeyStatus | UhciTrapEnMask);
} else {
//
// Clear the status
//
NonSmmClearLegKeyStatusReg(LegcyKeyStatus | UhciTrapByMask);
//
// Disable the Trap
//
NonSmmWriteLegKeyReg( (LegcyKeyStatus & ~UhciTrapEnMask) );
}
pBS->RestoreTPL(OldTpl);
}
return TRUE;
}
/**
* Sets the UHCI Trap Enable Mask value by checking the presence of
* KBC on the platform by reading port 64h.If KBC controller is present
* loads the global variables UhciTrapEnMask and UhciTrapByMask.
* If the platform has KBC then for Port 64h Read SMI will not be generated
* and handled by the KBC Emulation driver.
*
* @param none
* @param none
*
*/
void
NonSmmUhci_SetTrapEnMask()
{
if(KbcPresent){
UhciTrapByMask = UHCI_TRAPBY_MASK_WITHKBC;
UhciTrapEnMask = UHCI_TRAPEN_MASK_WITHKBC;
}
return;
}
//**********************************************************************
//**********************************************************************
//** **
//** (C)Copyright 1985-2016, American Megatrends, Inc. **
//** **
//** All Rights Reserved. **
//** **
//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 **
//** **
//** Phone: (770)-246-8600 **
//** **
//**********************************************************************
//**********************************************************************