1 /** @file 2 Legacy Interrupt Support 3 4 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> 5 6 This program and the accompanying materials are 7 licensed and made available under the terms and conditions of the BSD License 8 which accompanies this distribution. The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 **/ 15 16 #include "LegacyInterrupt.h" 17 18 // 19 // Handle for the Legacy Interrupt Protocol instance produced by this driver 20 // 21 STATIC EFI_HANDLE mLegacyInterruptHandle = NULL; 22 23 // 24 // Legacy Interrupt Device number (0x01 on piix4, 0x1f on q35/mch) 25 // 26 STATIC UINT8 mLegacyInterruptDevice; 27 28 // 29 // The Legacy Interrupt Protocol instance produced by this driver 30 // 31 STATIC EFI_LEGACY_INTERRUPT_PROTOCOL mLegacyInterrupt = { 32 GetNumberPirqs, 33 GetLocation, 34 ReadPirq, 35 WritePirq 36 }; 37 38 STATIC UINT8 PirqReg[MAX_PIRQ_NUMBER] = { PIRQA, PIRQB, PIRQC, PIRQD, PIRQE, PIRQF, PIRQG, PIRQH }; 39 40 41 /** 42 Return the number of PIRQs supported by this chipset. 43 44 @param[in] This Pointer to LegacyInterrupt Protocol 45 @param[out] NumberPirqs The pointer to return the max IRQ number supported 46 47 @retval EFI_SUCCESS Max PIRQs successfully returned 48 49 **/ 50 EFI_STATUS 51 EFIAPI 52 GetNumberPirqs ( 53 IN EFI_LEGACY_INTERRUPT_PROTOCOL *This, 54 OUT UINT8 *NumberPirqs 55 ) 56 { 57 *NumberPirqs = MAX_PIRQ_NUMBER; 58 59 return EFI_SUCCESS; 60 } 61 62 63 /** 64 Return PCI location of this device. 65 $PIR table requires this info. 66 67 @param[in] This - Protocol instance pointer. 68 @param[out] Bus - PCI Bus 69 @param[out] Device - PCI Device 70 @param[out] Function - PCI Function 71 72 @retval EFI_SUCCESS Bus/Device/Function returned 73 74 **/ 75 EFI_STATUS 76 EFIAPI 77 GetLocation ( 78 IN EFI_LEGACY_INTERRUPT_PROTOCOL *This, 79 OUT UINT8 *Bus, 80 OUT UINT8 *Device, 81 OUT UINT8 *Function 82 ) 83 { 84 *Bus = LEGACY_INT_BUS; 85 *Device = mLegacyInterruptDevice; 86 *Function = LEGACY_INT_FUNC; 87 88 return EFI_SUCCESS; 89 } 90 91 92 /** 93 Builds the PCI configuration address for the register specified by PirqNumber 94 95 @param[in] PirqNumber - The PIRQ number to build the PCI configuration address for 96 97 @return The PCI Configuration address for the PIRQ 98 **/ 99 UINTN 100 GetAddress ( 101 UINT8 PirqNumber 102 ) 103 { 104 return PCI_LIB_ADDRESS( 105 LEGACY_INT_BUS, 106 mLegacyInterruptDevice, 107 LEGACY_INT_FUNC, 108 PirqReg[PirqNumber] 109 ); 110 } 111 112 /** 113 Read the given PIRQ register 114 115 @param[in] This Protocol instance pointer 116 @param[in] PirqNumber The Pirq register 0 = A, 1 = B etc 117 @param[out] PirqData Value read 118 119 @retval EFI_SUCCESS Decoding change affected. 120 @retval EFI_INVALID_PARAMETER Invalid PIRQ number 121 122 **/ 123 EFI_STATUS 124 EFIAPI 125 ReadPirq ( 126 IN EFI_LEGACY_INTERRUPT_PROTOCOL *This, 127 IN UINT8 PirqNumber, 128 OUT UINT8 *PirqData 129 ) 130 { 131 if (PirqNumber >= MAX_PIRQ_NUMBER) { 132 return EFI_INVALID_PARAMETER; 133 } 134 135 *PirqData = PciRead8 (GetAddress (PirqNumber)); 136 *PirqData = (UINT8) (*PirqData & 0x7f); 137 138 return EFI_SUCCESS; 139 } 140 141 142 /** 143 Write the given PIRQ register 144 145 @param[in] This Protocol instance pointer 146 @param[in] PirqNumber The Pirq register 0 = A, 1 = B etc 147 @param[out] PirqData Value to write 148 149 @retval EFI_SUCCESS Decoding change affected. 150 @retval EFI_INVALID_PARAMETER Invalid PIRQ number 151 152 **/ 153 EFI_STATUS 154 EFIAPI 155 WritePirq ( 156 IN EFI_LEGACY_INTERRUPT_PROTOCOL *This, 157 IN UINT8 PirqNumber, 158 IN UINT8 PirqData 159 ) 160 { 161 if (PirqNumber >= MAX_PIRQ_NUMBER) { 162 return EFI_INVALID_PARAMETER; 163 } 164 165 PciWrite8 (GetAddress (PirqNumber), PirqData); 166 return EFI_SUCCESS; 167 } 168 169 170 /** 171 Initialize Legacy Interrupt support 172 173 @retval EFI_SUCCESS Successfully initialized 174 175 **/ 176 EFI_STATUS 177 LegacyInterruptInstall ( 178 VOID 179 ) 180 { 181 UINT16 HostBridgeDevId; 182 EFI_STATUS Status; 183 184 // 185 // Make sure the Legacy Interrupt Protocol is not already installed in the system 186 // 187 ASSERT_PROTOCOL_ALREADY_INSTALLED(NULL, &gEfiLegacyInterruptProtocolGuid); 188 189 // 190 // Query Host Bridge DID to determine platform type, then set device number 191 // 192 HostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId); 193 switch (HostBridgeDevId) { 194 case INTEL_82441_DEVICE_ID: 195 mLegacyInterruptDevice = LEGACY_INT_DEV_PIIX4; 196 break; 197 case INTEL_Q35_MCH_DEVICE_ID: 198 mLegacyInterruptDevice = LEGACY_INT_DEV_Q35; 199 break; 200 default: 201 DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n", 202 __FUNCTION__, HostBridgeDevId)); 203 ASSERT (FALSE); 204 return EFI_UNSUPPORTED; 205 } 206 207 // 208 // Make a new handle and install the protocol 209 // 210 Status = gBS->InstallMultipleProtocolInterfaces ( 211 &mLegacyInterruptHandle, 212 &gEfiLegacyInterruptProtocolGuid, 213 &mLegacyInterrupt, 214 NULL 215 ); 216 ASSERT_EFI_ERROR(Status); 217 218 return Status; 219 } 220 221