1/** @file 2Common Lib function for QNC internal network access. 3 4Copyright (c) 2013-2015 Intel Corporation. 5 6This program and the accompanying materials 7are licensed and made available under the terms and conditions of the BSD License 8which accompanies this distribution. The full text of the license may be found at 9http://opensource.org/licenses/bsd-license.php 10 11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14**/ 15 16// 17// The package level header files this module uses 18// 19#include <Uefi.h> 20 21#include <IntelQNCRegs.h> 22#include <Library/QNCAccessLib.h> 23#include <Library/DebugLib.h> 24#include <IndustryStandard/Pci22.h> 25 26UINT32 27EFIAPI 28QNCPortRead( 29 UINT8 Port, 30 UINT32 RegAddress 31 ) 32{ 33 McD0PciCfg32 (QNC_ACCESS_PORT_MEA) = (RegAddress & 0xFFFFFF00); 34 McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = MESSAGE_READ_DW (Port, RegAddress); 35 return McD0PciCfg32 (QNC_ACCESS_PORT_MDR); 36} 37 38VOID 39EFIAPI 40QNCPortWrite ( 41 UINT8 Port, 42 UINT32 RegAddress, 43 UINT32 WriteValue 44 ) 45{ 46 McD0PciCfg32 (QNC_ACCESS_PORT_MDR) = WriteValue; 47 McD0PciCfg32 (QNC_ACCESS_PORT_MEA) = (RegAddress & 0xFFFFFF00); 48 McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = MESSAGE_WRITE_DW (Port, RegAddress); 49} 50 51UINT32 52EFIAPI 53QNCAltPortRead ( 54 UINT8 Port, 55 UINT32 RegAddress 56 ) 57{ 58 McD0PciCfg32 (QNC_ACCESS_PORT_MEA) = (RegAddress & 0xFFFFFF00); 59 McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = ALT_MESSAGE_READ_DW (Port, RegAddress); 60 return McD0PciCfg32 (QNC_ACCESS_PORT_MDR); 61} 62 63VOID 64EFIAPI 65QNCAltPortWrite ( 66 UINT8 Port, 67 UINT32 RegAddress, 68 UINT32 WriteValue 69 ) 70{ 71 McD0PciCfg32 (QNC_ACCESS_PORT_MDR) = WriteValue; 72 McD0PciCfg32 (QNC_ACCESS_PORT_MEA) = (RegAddress & 0xFFFFFF00); 73 McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = ALT_MESSAGE_WRITE_DW (Port, RegAddress); 74} 75 76UINT32 77EFIAPI 78QNCPortIORead( 79 UINT8 Port, 80 UINT32 RegAddress 81 ) 82{ 83 McD0PciCfg32 (QNC_ACCESS_PORT_MEA) = (RegAddress & 0xFFFFFF00); 84 McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = MESSAGE_IO_READ_DW (Port, RegAddress); 85 return McD0PciCfg32 (QNC_ACCESS_PORT_MDR); 86} 87 88VOID 89EFIAPI 90QNCPortIOWrite ( 91 UINT8 Port, 92 UINT32 RegAddress, 93 UINT32 WriteValue 94 ) 95{ 96 McD0PciCfg32 (QNC_ACCESS_PORT_MDR) = WriteValue; 97 McD0PciCfg32 (QNC_ACCESS_PORT_MEA) = (RegAddress & 0xFFFFFF00); 98 McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = MESSAGE_IO_WRITE_DW (Port, RegAddress); 99} 100 101RETURN_STATUS 102EFIAPI 103QNCMmIoWrite ( 104 UINT32 MmIoAddress, 105 QNC_MEM_IO_WIDTH Width, 106 UINT32 DataNumber, 107 VOID *pData 108 ) 109/*++ 110 111Routine Description: 112 113 This is for the special consideration for QNC MMIO write, as required by FWG, a reading must be performed after MMIO writing 114to ensure the expected write is processed and data is flushed into chipset 115 116Arguments: 117 118 Row -- row number to be cleared ( start from 1 ) 119 120Returns: 121 122 EFI_SUCCESS 123 124--*/ 125{ 126 RETURN_STATUS Status; 127 UINTN Index; 128 129 Status = RETURN_SUCCESS; 130 131 for (Index =0; Index < DataNumber; Index++) { 132 switch (Width) { 133 case QNCMmioWidthUint8: 134 QNCMmio8 (MmIoAddress, 0) = ((UINT8 *)pData)[Index]; 135 if (QNCMmio8 (MmIoAddress, 0) != ((UINT8*)pData)[Index]) { 136 Status = RETURN_DEVICE_ERROR; 137 break; 138 } 139 break; 140 141 case QNCMmioWidthUint16: 142 QNCMmio16 (MmIoAddress, 0) = ((UINT16 *)pData)[Index]; 143 if (QNCMmio16 (MmIoAddress, 0) != ((UINT16 *)pData)[Index]) { 144 Status = RETURN_DEVICE_ERROR; 145 break; 146 } 147 break; 148 149 case QNCMmioWidthUint32: 150 QNCMmio32 (MmIoAddress, 0) = ((UINT32 *)pData)[Index]; 151 if (QNCMmio32 (MmIoAddress, 0) != ((UINT32 *)pData)[Index]) { 152 Status = RETURN_DEVICE_ERROR; 153 break; 154 } 155 break; 156 157 case QNCMmioWidthUint64: 158 QNCMmio64 (MmIoAddress, 0) = ((UINT64 *)pData)[Index]; 159 if (QNCMmio64 (MmIoAddress, 0) != ((UINT64 *)pData)[Index]) { 160 Status = RETURN_DEVICE_ERROR; 161 break; 162 } 163 break; 164 165 default: 166 break; 167 } 168 } 169 170 return Status; 171} 172 173UINT32 174EFIAPI 175QncHsmmcRead ( 176 VOID 177 ) 178{ 179 return QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HSMMC); 180} 181 182VOID 183EFIAPI 184QncHsmmcWrite ( 185 UINT32 WriteValue 186 ) 187{ 188 UINT16 DeviceId; 189 UINT32 Data32; 190 191 // 192 // Check what Soc we are running on (read Host bridge DeviceId) 193 // 194 DeviceId = QNCMmPci16(0, MC_BUS, MC_DEV, MC_FUN, PCI_DEVICE_ID_OFFSET); 195 196 if (DeviceId == QUARK2_MC_DEVICE_ID) { 197 // 198 // Disable HSMMC configuration 199 // 200 Data32 = QncHsmmcRead (); 201 Data32 &= ~SMM_CTL_EN; 202 QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HSMMC, Data32); 203 204 // 205 // Validate HSMMC configuration is disabled 206 // 207 Data32 = QncHsmmcRead (); 208 ASSERT((Data32 & SMM_CTL_EN) == 0); 209 210 // 211 // Enable HSMMC configuration 212 // 213 WriteValue |= SMM_CTL_EN; 214 } 215 216 // 217 // Write the register value 218 // 219 QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HSMMC, WriteValue); 220 221 if (DeviceId == QUARK2_MC_DEVICE_ID) { 222 // 223 // Validate HSMMC configuration is enabled 224 // 225 Data32 = QncHsmmcRead (); 226 ASSERT((Data32 & SMM_CTL_EN) != 0); 227 } 228} 229 230VOID 231EFIAPI 232QncImrWrite ( 233 UINT32 ImrBaseOffset, 234 UINT32 ImrLow, 235 UINT32 ImrHigh, 236 UINT32 ImrReadMask, 237 UINT32 ImrWriteMask 238 ) 239{ 240 UINT16 DeviceId; 241 UINT32 Data32; 242 243 // 244 // Check what Soc we are running on (read Host bridge DeviceId) 245 // 246 DeviceId = QNCMmPci16(0, MC_BUS, MC_DEV, MC_FUN, PCI_DEVICE_ID_OFFSET); 247 248 // 249 // Disable IMR protection 250 // 251 if (DeviceId == QUARK2_MC_DEVICE_ID) { 252 // 253 // Disable IMR protection 254 // 255 Data32 = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXL); 256 Data32 &= ~IMR_EN; 257 QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXL, Data32); 258 259 // 260 // Validate IMR protection is disabled 261 // 262 Data32 = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXL); 263 ASSERT((Data32 & IMR_EN) == 0); 264 265 // 266 // Update the IMR (IMRXL must be last as it may enable IMR violation checking) 267 // 268 QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXRM, ImrReadMask); 269 QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXWM, ImrWriteMask); 270 QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXH, ImrHigh); 271 QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXL, ImrLow); 272 273 // 274 // Validate IMR protection is enabled/disabled 275 // 276 Data32 = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXL); 277 ASSERT((Data32 & IMR_EN) == (ImrLow & IMR_EN)); 278 } else { 279 // 280 // Disable IMR protection (allow all access) 281 // 282 QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXRM, (UINT32)IMRX_ALL_ACCESS); 283 QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXWM, (UINT32)IMRX_ALL_ACCESS); 284 285 // 286 // Update the IMR (IMRXRM/IMRXWM must be last as they restrict IMR access) 287 // 288 QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXL, (ImrLow & ~IMR_EN)); 289 QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXH, ImrHigh); 290 QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXRM, ImrReadMask); 291 QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXWM, ImrWriteMask); 292 } 293} 294 295VOID 296EFIAPI 297QncIClkAndThenOr ( 298 UINT32 RegAddress, 299 UINT32 AndValue, 300 UINT32 OrValue 301 ) 302{ 303 UINT32 RegValue; 304 // 305 // Whenever an iCLK SB register (Endpoint 32h) is being programmed the access 306 // should always consist of a READ from the address followed by 2 identical 307 // WRITEs to that address. 308 // 309 RegValue = QNCAltPortRead (QUARK_ICLK_SB_PORT_ID, RegAddress); 310 RegValue &= AndValue; 311 RegValue |= OrValue; 312 QNCAltPortWrite (QUARK_ICLK_SB_PORT_ID, RegAddress, RegValue); 313 QNCAltPortWrite (QUARK_ICLK_SB_PORT_ID, RegAddress, RegValue); 314} 315 316VOID 317EFIAPI 318QncIClkOr ( 319 UINT32 RegAddress, 320 UINT32 OrValue 321 ) 322{ 323 UINT32 RegValue; 324 // 325 // Whenever an iCLK SB register (Endpoint 32h) is being programmed the access 326 // should always consist of a READ from the address followed by 2 identical 327 // WRITEs to that address. 328 // 329 RegValue = QNCAltPortRead (QUARK_ICLK_SB_PORT_ID, RegAddress); 330 RegValue |= OrValue; 331 QNCAltPortWrite (QUARK_ICLK_SB_PORT_ID, RegAddress, RegValue); 332 QNCAltPortWrite (QUARK_ICLK_SB_PORT_ID, RegAddress, RegValue); 333} 334