1 /** @file 2 This file contains GPIO routines for RC usage 3 4 Copyright (c) 2017, Intel Corporation. All rights reserved.<BR> 5 SPDX-License-Identifier: BSD-2-Clause-Patent 6 7 **/ 8 #include <Base.h> 9 #include <Uefi/UefiBaseType.h> 10 #include <Library/IoLib.h> 11 #include <Library/DebugLib.h> 12 #include <Library/BaseMemoryLib.h> 13 #include <PchAccess.h> 14 #include <Library/GpioLib.h> 15 #include <Library/GpioNativeLib.h> 16 #include <Library/GpioPrivateLib.h> 17 #include <Library/PchCycleDecodingLib.h> 18 #include <Pch/Library/PeiDxeSmmGpioLib/GpioLibrary.h> 19 /** 20 This procedure will get value of selected gpio register 21 22 @param[in] Group GPIO group number 23 @param[in] Offset GPIO register offset 24 @param[out] RegVal Value of gpio register 25 26 @retval EFI_SUCCESS The function completed successfully 27 @retval EFI_INVALID_PARAMETER Invalid group or pad number 28 **/ 29 EFI_STATUS 30 GpioGetReg ( 31 IN GPIO_GROUP Group, 32 IN UINT32 Offset, 33 OUT UINT32 *RegVal 34 ) 35 { 36 GPIO_GROUP_INFO *GpioGroupInfo; 37 UINTN GpioGroupInfoLength; 38 UINTN GroupIndex; 39 40 GroupIndex = GpioGetGroupIndexFromGroup (Group); 41 GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength); 42 // 43 // Check if group argument exceeds GPIO GROUP INFO array 44 // 45 if ((UINTN) GroupIndex >= GpioGroupInfoLength) { 46 ASSERT (FALSE); 47 return EFI_INVALID_PARAMETER; 48 } 49 50 *RegVal = MmioRead32 (PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, Offset)); 51 52 return EFI_SUCCESS; 53 } 54 55 /** 56 This procedure will set value of selected gpio register 57 58 @param[in] Group GPIO group number 59 @param[in] Offset GPIO register offset 60 @param[in] RegVal Value of gpio register 61 62 @retval EFI_SUCCESS The function completed successfully 63 @retval EFI_INVALID_PARAMETER Invalid group or pad number 64 **/ 65 EFI_STATUS 66 GpioSetReg ( 67 IN GPIO_GROUP Group, 68 IN UINT32 Offset, 69 IN UINT32 RegVal 70 ) 71 { 72 GPIO_GROUP_INFO *GpioGroupInfo; 73 UINTN GpioGroupInfoLength; 74 UINTN GroupIndex; 75 76 GroupIndex = GpioGetGroupIndexFromGroup (Group); 77 GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength); 78 // 79 // Check if group argument exceeds GPIO GROUP INFO array 80 // 81 if ((UINTN) GroupIndex >= GpioGroupInfoLength) { 82 ASSERT (FALSE); 83 return EFI_INVALID_PARAMETER; 84 } 85 86 MmioWrite32 (PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, Offset), RegVal); 87 88 return EFI_SUCCESS; 89 } 90 91 /** 92 This procedure is used by PchSmiDispatcher and will return information 93 needed to register GPI SMI. Relation between Index and GpioPad number is: 94 Index = GpioGroup + 24 * GpioPad 95 96 @param[in] Index GPI SMI number 97 @param[out] GpioPin GPIO pin 98 @param[out] GpiSmiBitOffset GPI SMI bit position within GpiSmi Registers 99 @param[out] GpiSmiEnRegAddress Address of GPI SMI Enable register 100 @param[out] GpiSmiStsRegAddress Address of GPI SMI status register 101 102 @retval EFI_SUCCESS The function completed successfully 103 @retval EFI_INVALID_PARAMETER Invalid group or pad number 104 **/ 105 EFI_STATUS 106 GpioGetPadAndSmiRegs ( 107 IN UINT32 Index, 108 OUT GPIO_PAD *GpioPin, 109 OUT UINT8 *GpiSmiBitOffset, 110 OUT UINT32 *GpiSmiEnRegAddress, 111 OUT UINT32 *GpiSmiStsRegAddress 112 ) 113 { 114 UINT32 GroupIndex; 115 UINT32 PadNumber; 116 GPIO_GROUP_INFO *GpioGroupInfo; 117 GPIO_GROUP GpioGroupOffset; 118 UINTN GpioGroupInfoLength; 119 UINT32 SmiRegOffset; 120 121 GPIO_PAD_OWN PadOwnVal; 122 UINT32 HostOwnVal; 123 124 125 GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength); 126 127 GpioGroupOffset = GpioGetLowestGroup (); 128 129 PadNumber = 0; 130 GroupIndex = 0; 131 for (GroupIndex = 0; GroupIndex < GpioGroupInfoLength; GroupIndex++) { 132 PadNumber = Index; 133 if (PadNumber < GpioGroupInfo[GroupIndex].PadPerGroup) { 134 // 135 // Found group and pad number 136 // 137 break; 138 } 139 Index = Index - GpioGroupInfo[GroupIndex].PadPerGroup; 140 } 141 142 // 143 // Check if legal pad number 144 // 145 if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup){ 146 return EFI_INVALID_PARAMETER; 147 } 148 149 // 150 // Check if selected group has GPI SMI Enable and Status registers 151 // 152 if (GpioGroupInfo[GroupIndex].SmiEnOffset == NO_REGISTER_FOR_PROPERTY) { 153 return EFI_INVALID_PARAMETER; 154 } 155 156 DEBUG_CODE_BEGIN (); 157 // 158 // Check if selected GPIO Pad is not owned by CSME/ISH/IE 159 // 160 GpioGetPadOwnership (GpioGetGpioPadFromGroupAndPadNumber (GroupIndex + GpioGroupOffset, PadNumber), &PadOwnVal); 161 if (PadOwnVal != GpioPadOwnHost) { 162 DEBUG ((DEBUG_ERROR, "GPIO ERROR: Accessing pad not owned by host (Group=%d, Pad=%d)!\n",GroupIndex, PadNumber)); 163 return EFI_INVALID_PARAMETER; 164 } 165 // 166 // Check if Host Software Pad Ownership is set to ACPI Mode 167 // 168 GpioGetHostSwOwnershipForPad (GpioGetGpioPadFromGroupAndPadNumber (GroupIndex + GpioGroupOffset, PadNumber), &HostOwnVal); 169 if (HostOwnVal != V_PCH_PCR_GPIO_HOSTSW_OWN_ACPI) { 170 ASSERT (FALSE); 171 return EFI_INVALID_PARAMETER; 172 } 173 174 DEBUG_CODE_END (); 175 176 *GpioPin = GpioGetGpioPadFromGroupAndPadNumber (GroupIndex + GpioGroupOffset, PadNumber); 177 *GpiSmiBitOffset = (UINT8)(PadNumber % 32); 178 179 SmiRegOffset = GpioGroupInfo[GroupIndex].SmiEnOffset + (PadNumber / 32) * 0x4; 180 *GpiSmiEnRegAddress = PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, SmiRegOffset); 181 182 SmiRegOffset = GpioGroupInfo[GroupIndex].SmiStsOffset + (PadNumber / 32) * 0x4; 183 *GpiSmiStsRegAddress = PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, SmiRegOffset); 184 185 return EFI_SUCCESS; 186 } 187 188 /** 189 This procedure will clear GPIO_UNLOCK_SMI_STS 190 191 @param[in] None 192 193 @retval EFI_SUCCESS The function completed successfully 194 @retval EFI_INVALID_PARAMETER Invalid group or pad number 195 **/ 196 EFI_STATUS 197 GpioClearUnlockSmiSts ( 198 VOID 199 ) 200 { 201 UINT16 AcpiBaseAddr; 202 203 PchAcpiBaseGet (&AcpiBaseAddr); 204 205 // 206 // GPIO_UNLOCK_SMI_STS is cleared by writing 1 to it. Other bits in 207 // R_PCH_SMI_STS registers are either RO or RW/1C so writing 0 to them 208 // will not change their state. 209 // 210 IoWrite32 (AcpiBaseAddr + R_PCH_SMI_STS, B_PCH_SMI_STS_GPIO_UNLOCK); 211 212 return EFI_SUCCESS; 213 } 214 215 216 /** 217 This procedure will set GPIO Driver IRQ number 218 219 @param[in] Irq Irq number 220 221 @retval EFI_SUCCESS The function completed successfully 222 @retval EFI_INVALID_PARAMETER Invalid IRQ number 223 **/ 224 EFI_STATUS 225 GpioSetIrq ( 226 IN UINT8 Irq 227 ) 228 { 229 UINT32 Data32And; 230 UINT32 Data32Or; 231 232 // 233 // Check if Irq is 14 or 15 234 // 235 if ((Irq < 14) || (Irq > 15)) { 236 ASSERT (FALSE); 237 return EFI_INVALID_PARAMETER; 238 } 239 240 Data32And = (UINT32) ~(B_PCH_PCR_GPIO_MISCCFG_IRQ_ROUTE); 241 Data32Or = (UINT32) (Irq - 14) << N_PCH_PCR_GPIO_MISCCFG_IRQ_ROUTE; 242 243 // 244 // Program MISCCFG register for Community 0 245 // 246 MmioAndThenOr32 ( 247 PCH_PCR_ADDRESS (PID_GPIOCOM0, R_PCH_PCR_GPIO_MISCCFG), 248 Data32And, 249 Data32Or 250 ); 251 252 // 253 // Program MISCCFG register for Community 1 254 // 255 MmioAndThenOr32 ( 256 PCH_PCR_ADDRESS (PID_GPIOCOM1, R_PCH_PCR_GPIO_MISCCFG), 257 Data32And, 258 Data32Or 259 ); 260 261 // 262 // Program MISCCFG register for Community 2 263 // 264 MmioAndThenOr32 ( 265 PCH_PCR_ADDRESS (PID_GPIOCOM2, R_PCH_PCR_GPIO_MISCCFG), 266 Data32And, 267 Data32Or 268 ); 269 270 // 271 // Program MISCCFG register for Community 3 272 // 273 MmioAndThenOr32 ( 274 PCH_PCR_ADDRESS (PID_GPIOCOM3, R_PCH_PCR_GPIO_MISCCFG), 275 Data32And, 276 Data32Or 277 ); 278 279 return EFI_SUCCESS; 280 } 281 282 /** 283 This procedure will perform special handling of GPP_A_12 on PCH-LP. 284 285 @param[in] None 286 287 @retval None 288 **/ 289 VOID 290 GpioA12SpecialHandling ( 291 VOID 292 ) 293 { 294 GPIO_PAD_OWN PadOwnVal; 295 296 // 297 // SKL PCH BWG 16.6. PCH-LP GPP_A_12 Special Handling 298 // 299 if (GetPchSeries () == PchLp) { 300 GpioGetPadOwnership (GPIO_SKL_LP_GPP_A12, &PadOwnVal); 301 302 // 303 // If the pad is host-own, BIOS has to always lock this pad after being initialized 304 // 305 if (PadOwnVal == GpioPadOwnHost) { 306 // 307 // Set PadCfgLock for GPP_A_12 308 // 309 GpioLockPadCfg (GPIO_SKL_LP_GPP_A12); 310 } 311 } 312 } 313