blob: 23114c91e1fa3fabe99708ea3215fa5547cdecd3 [file] [log] [blame]
/** @file
Legacy Interrupt Component.
This component implements the Legacy Interrupt Protocol defined in the Framework CSM Spec.
Copyright (c) 2013 Intel Corporation.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Intel Corporation nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**/
#include "CommonHeader.h"
#include "LegacyInterrupt.h"
//
// Protocol interface function prototypes
//
EFI_STATUS
EFIAPI
GetNumberPirqs (
IN EFI_LEGACY_INTERRUPT_PROTOCOL *This,
OUT UINT8 *NumberPirqs
);
EFI_STATUS
EFIAPI
GetLocation (
IN EFI_LEGACY_INTERRUPT_PROTOCOL *This,
OUT UINT8 *Bus,
OUT UINT8 *Device,
OUT UINT8 *Function
);
EFI_STATUS
EFIAPI
ReadPirq (
IN EFI_LEGACY_INTERRUPT_PROTOCOL *This,
IN UINT8 PirqNumber,
OUT UINT8 *PirqData
);
EFI_STATUS
EFIAPI
WritePirq (
IN EFI_LEGACY_INTERRUPT_PROTOCOL *This,
IN UINT8 PirqNumber,
IN UINT8 PirqData
);
//
// Handle for the Legacy Interrupt Protocol instance produced by this driver
//
static EFI_HANDLE mLegacyInterruptHandle = NULL;
//
// The Legacy Interrupt Protocol instance produced by this driver
//
static EFI_LEGACY_INTERRUPT_PROTOCOL mLegacyInterrupt = {
GetNumberPirqs,
GetLocation,
ReadPirq,
WritePirq
};
//
// PIRQ Route Control registers' offsets within the LPC configuration space for PIRQA~H
//
static UINT8 mPirqRouteReg[QNC_NUMBER_PIRQS] = {
R_QNC_LPC_PIRQA_ROUT,
R_QNC_LPC_PIRQB_ROUT,
R_QNC_LPC_PIRQC_ROUT,
R_QNC_LPC_PIRQD_ROUT,
R_QNC_LPC_PIRQE_ROUT,
R_QNC_LPC_PIRQF_ROUT,
R_QNC_LPC_PIRQG_ROUT,
R_QNC_LPC_PIRQH_ROUT
};
/**
Gets the number of PIRQs that this hardware supports.
@param[in] This Indicates the EFI_LEGACY_INTERRUPT_PROTOCOL instance.
@param[out] NumberPirqs Number of PIRQs that are supported.
@retval EFI_SUCCESS The number of PIRQs was returned successfully.
**/
EFI_STATUS
EFIAPI
GetNumberPirqs (
IN EFI_LEGACY_INTERRUPT_PROTOCOL *This,
OUT UINT8 *NumberPirqs
)
{
ASSERT (NumberPirqs != NULL);
*NumberPirqs = QNC_NUMBER_PIRQS;
return EFI_SUCCESS;
}
/**
Gets the PCI location associated with this protocol.
@param[in] This Indicates the EFI_LEGACY_INTERRUPT_PROTOCOL instance.
@param[out] Bus PCI bus number of this device.
@param[out] Device PCI device number of this device.
@param[out] Function PCI function number of this device.
@retval EFI_SUCCESS The PCI location was returned successfully.
**/
EFI_STATUS
EFIAPI
GetLocation (
IN EFI_LEGACY_INTERRUPT_PROTOCOL *This,
OUT UINT8 *Bus,
OUT UINT8 *Device,
OUT UINT8 *Function
)
{
ASSERT (Bus != NULL && Device != NULL && Function != NULL);
*Bus = PCI_BUS_NUMBER_QNC;
*Device = PCI_DEVICE_NUMBER_QNC_LPC;
*Function = PCI_FUNCTION_NUMBER_QNC_LPC;
return EFI_SUCCESS;
}
/**
Reads the given PIRQ register and returns the IRQ that is assigned to it.
@param[in] This Indicates the EFI_LEGACY_INTERRUPT_PROTOCOL instance.
@param[in] PirqNumber PIRQ A = 0, PIRQ B = 1, and so on.
@param[out] PirqData IRQ assigned to this PIRQ.
@retval EFI_SUCCESS The data was returned successfully.
@retval EFI_INVALID_PARAMETER The PIRQ number invalid.
**/
EFI_STATUS
EFIAPI
ReadPirq (
IN EFI_LEGACY_INTERRUPT_PROTOCOL *This,
IN UINT8 PirqNumber,
OUT UINT8 *PirqData
)
{
if (PirqNumber >= QNC_NUMBER_PIRQS) {
return EFI_INVALID_PARAMETER;
}
ASSERT (PirqData != NULL);
*PirqData = (UINT8)(PciRead8 (PCI_QNC_LPC_ADDRESS (mPirqRouteReg[PirqNumber])) & 0x7f);
return EFI_SUCCESS;
}
/**
Writes data to the specified PIRQ register.
@param[in] This Indicates the EFI_LEGACY_INTERRUPT_PROTOCOL instance.
@param[in] PirqNumber PIRQ A = 0, PIRQ B = 1, and so on.
@param[in] PirqData IRQ assigned to this PIRQ.
@retval EFI_SUCCESS The PIRQ was programmed.
@retval EFI_INVALID_PARAMETER The PIRQ number invalid.
**/
EFI_STATUS
EFIAPI
WritePirq (
IN EFI_LEGACY_INTERRUPT_PROTOCOL *This,
IN UINT8 PirqNumber,
IN UINT8 PirqData
)
{
if (PirqNumber >= QNC_NUMBER_PIRQS) {
return EFI_INVALID_PARAMETER;
}
PciWrite8 (PCI_QNC_LPC_ADDRESS (mPirqRouteReg[PirqNumber]), PirqData);
return EFI_SUCCESS;
}
/**
Install Legacy Interrupt Protocol.
@retval EFI_SUCCESS Installed Legacy Interrupt Protocol successfully.
@retval !EFI_SUCESS Error installing Legacy Interrupt Protocol.
**/
EFI_STATUS
LegacyInterruptInstall (
VOID
)
{
//
// Make sure the Legacy Interrupt Protocol is not already installed in the system
//
ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiLegacyInterruptProtocolGuid);
//
// Make a new handle and install the protocol
//
return gBS->InstallMultipleProtocolInterfaces (
&mLegacyInterruptHandle,
&gEfiLegacyInterruptProtocolGuid,
&mLegacyInterrupt,
NULL
);
}