1 /** @file 2 ACPISMM Driver implementation file. 3 4 This is QNC Smm platform driver 5 6 Copyright (c) 2013-2016 Intel Corporation. 7 8 This program and the accompanying materials 9 are licensed and made available under the terms and conditions of the BSD License 10 which accompanies this distribution. The full text of the license may be found at 11 http://opensource.org/licenses/bsd-license.php 12 13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 15 16 17 **/ 18 19 #include <AcpiSmmPlatform.h> 20 21 #define PCILIB_TO_COMMON_ADDRESS(Address) \ 22 ((UINT64) ((((UINTN) ((Address>>20) & 0xff)) << 24) + (((UINTN) ((Address>>15) & 0x1f)) << 16) + (((UINTN) ((Address>>12) & 0x07)) << 8) + ((UINTN) (Address & 0xfff )))) 23 24 // 25 // Modular variables needed by this driver 26 // 27 EFI_ACPI_SMM_DEV mAcpiSmm; 28 29 UINT8 mPciCfgRegTable[] = { 30 // 31 // Logic to decode the table masks to arrive at the registers saved 32 // Dword Registers are saved. For a given mask, the Base+offset register 33 // will be saved as in the table below. 34 // (example) To save register 0x24, 0x28 the mask at the Base 0x20 will be 0x06 35 // Base 0x00 0x20 0x40 0x60 0x80 0xA0 0xC0 0xE0 36 // Mask offset 37 // 0x01 0x00 38 // 0x02 0x04 39 // 0x04 0x08 40 // 0x08 0x0C 41 // 0x10 0x10 42 // 0x20 0x14 43 // 0x40 0x18 44 // 0x80 0x1C 45 // 46 47 // 48 // Bus, Dev, Func, 49 // 00-1F, 20-3F, 40-5F, 60-7F, 80-9F, A0-BF, C0-DF, E0-FF 50 // Only Bus 0 device is supported now 51 // 52 53 // 54 // Quark South Cluster devices 55 // 56 PCI_DEVICE (0, 20, 0), 57 PCI_REG_MASK (0x18, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 58 59 PCI_DEVICE (0, 20, 1), 60 PCI_REG_MASK (0x38, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 61 62 PCI_DEVICE (0, 20, 2), 63 PCI_REG_MASK (0x18, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 64 65 PCI_DEVICE (0, 20, 3), 66 PCI_REG_MASK (0x18, 0x98, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00), 67 68 PCI_DEVICE (0, 20, 4), 69 PCI_REG_MASK (0x18, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 70 71 PCI_DEVICE (0, 20, 5), 72 PCI_REG_MASK (0x38, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 73 74 PCI_DEVICE (0, 20, 6), 75 PCI_REG_MASK (0x18, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 76 77 PCI_DEVICE (0, 20, 7), 78 PCI_REG_MASK (0x18, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 79 80 PCI_DEVICE (0, 21, 0), 81 PCI_REG_MASK (0x18, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 82 83 PCI_DEVICE (0, 21, 1), 84 PCI_REG_MASK (0x18, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 85 86 PCI_DEVICE (0, 21, 2), 87 PCI_REG_MASK (0x38, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 88 89 // 90 // Quark North Cluster devices 91 // 92 PCI_DEVICE (0, 0, 0), 93 PCI_REG_MASK (0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 94 95 PCI_DEVICE (0, 23, 0), 96 PCI_REG_MASK (0xC0, 0x8F, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00), 97 98 PCI_DEVICE (0, 23, 1), 99 PCI_REG_MASK (0xC0, 0x8F, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00), 100 101 PCI_DEVICE (0, 31, 0), 102 PCI_REG_MASK (0x00, 0x08, 0x4E, 0x03, 0x02, 0x00, 0x60, 0x10), 103 104 PCI_DEVICE_END 105 }; 106 107 EFI_PLATFORM_TYPE mPlatformType; 108 109 // These registers have to set in byte order 110 const UINT8 QNCS3SaveExtReg[] = { 111 QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HSMMC, // SMRAM settings 112 113 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXL, 114 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXH, 115 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXRM, 116 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXWM, 117 118 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR1+QUARK_NC_MEMORY_MANAGER_IMRXL, 119 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR1+QUARK_NC_MEMORY_MANAGER_IMRXH, 120 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR1+QUARK_NC_MEMORY_MANAGER_IMRXRM, 121 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR1+QUARK_NC_MEMORY_MANAGER_IMRXWM, 122 123 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR2+QUARK_NC_MEMORY_MANAGER_IMRXL, 124 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR2+QUARK_NC_MEMORY_MANAGER_IMRXH, 125 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR2+QUARK_NC_MEMORY_MANAGER_IMRXRM, 126 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR2+QUARK_NC_MEMORY_MANAGER_IMRXWM, 127 128 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR3+QUARK_NC_MEMORY_MANAGER_IMRXL, 129 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR3+QUARK_NC_MEMORY_MANAGER_IMRXH, 130 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR3+QUARK_NC_MEMORY_MANAGER_IMRXRM, 131 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR3+QUARK_NC_MEMORY_MANAGER_IMRXWM, 132 133 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR4+QUARK_NC_MEMORY_MANAGER_IMRXL, 134 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR4+QUARK_NC_MEMORY_MANAGER_IMRXH, 135 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR4+QUARK_NC_MEMORY_MANAGER_IMRXRM, 136 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR4+QUARK_NC_MEMORY_MANAGER_IMRXWM, 137 138 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR5+QUARK_NC_MEMORY_MANAGER_IMRXL, 139 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR5+QUARK_NC_MEMORY_MANAGER_IMRXH, 140 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR5+QUARK_NC_MEMORY_MANAGER_IMRXRM, 141 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR5+QUARK_NC_MEMORY_MANAGER_IMRXWM, 142 143 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR6+QUARK_NC_MEMORY_MANAGER_IMRXL, 144 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR6+QUARK_NC_MEMORY_MANAGER_IMRXH, 145 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR6+QUARK_NC_MEMORY_MANAGER_IMRXRM, 146 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR6+QUARK_NC_MEMORY_MANAGER_IMRXWM, 147 148 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXL, 149 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXH, 150 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXRM, 151 QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXWM, 152 153 QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_END_MEM_REG, // ECC Scrub settings 154 QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_START_MEM_REG, 155 QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_NEXT_READ_REG, 156 QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_CONFIG_REG, 157 158 0xFF 159 }; 160 161 /** 162 Allocate EfiACPIMemoryNVS below 4G memory address. 163 164 This function allocates EfiACPIMemoryNVS below 4G memory address. 165 166 @param Size Size of memory to allocate. 167 168 @return Allocated address for output. 169 170 **/ 171 VOID* 172 AllocateAcpiNvsMemoryBelow4G ( 173 IN UINTN Size 174 ) 175 { 176 UINTN Pages; 177 EFI_PHYSICAL_ADDRESS Address; 178 EFI_STATUS Status; 179 VOID* Buffer; 180 181 Pages = EFI_SIZE_TO_PAGES (Size); 182 Address = 0xffffffff; 183 184 Status = gBS->AllocatePages ( 185 AllocateMaxAddress, 186 EfiACPIMemoryNVS, 187 Pages, 188 &Address 189 ); 190 if (EFI_ERROR (Status)) { 191 return NULL; 192 } 193 194 Buffer = (VOID *) (UINTN) Address; 195 ZeroMem (Buffer, Size); 196 197 return Buffer; 198 } 199 200 EFI_STATUS 201 EFIAPI 202 ReservedS3Memory ( 203 UINTN SystemMemoryLength 204 205 ) 206 /*++ 207 208 Routine Description: 209 210 Reserved S3 memory for InstallS3Memory 211 212 Arguments: 213 214 215 Returns: 216 217 EFI_OUT_OF_RESOURCES - Insufficient resources to complete function. 218 EFI_SUCCESS - Function has completed successfully. 219 220 --*/ 221 { 222 223 VOID *GuidHob; 224 EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *DescriptorBlock; 225 VOID *AcpiReservedBase; 226 227 UINTN TsegIndex; 228 UINTN TsegSize; 229 UINTN TsegBase; 230 RESERVED_ACPI_S3_RANGE *AcpiS3Range; 231 // 232 // Get Hob list for SMRAM desc 233 // 234 GuidHob = GetFirstGuidHob (&gEfiSmmPeiSmramMemoryReserveGuid); 235 ASSERT (GuidHob); 236 DescriptorBlock = GET_GUID_HOB_DATA (GuidHob); 237 ASSERT (DescriptorBlock); 238 239 // 240 // Use the hob to get SMRAM capabilities 241 // 242 TsegIndex = DescriptorBlock->NumberOfSmmReservedRegions - 1; 243 ASSERT (TsegIndex <= (MAX_SMRAM_RANGES - 1)); 244 TsegBase = (UINTN)DescriptorBlock->Descriptor[TsegIndex].PhysicalStart; 245 TsegSize = (UINTN)DescriptorBlock->Descriptor[TsegIndex].PhysicalSize; 246 247 DEBUG ((EFI_D_INFO, "SMM Base: %08X\n", TsegBase)); 248 DEBUG ((EFI_D_INFO, "SMM Size: %08X\n", TsegSize)); 249 250 // 251 // Now find the location of the data structure that is used to store the address 252 // of the S3 reserved memory. 253 // 254 AcpiS3Range = (RESERVED_ACPI_S3_RANGE*) (UINTN) (TsegBase + RESERVED_ACPI_S3_RANGE_OFFSET); 255 256 // 257 // Allocate reserved ACPI memory for S3 resume. Pointer to this region is 258 // stored in SMRAM in the first page of TSEG. 259 // 260 AcpiReservedBase = AllocateAcpiNvsMemoryBelow4G (PcdGet32 (PcdS3AcpiReservedMemorySize)); 261 if (AcpiReservedBase != NULL) { 262 AcpiS3Range->AcpiReservedMemoryBase = (UINT32)(UINTN) AcpiReservedBase; 263 AcpiS3Range->AcpiReservedMemorySize = PcdGet32 (PcdS3AcpiReservedMemorySize); 264 } 265 AcpiS3Range->SystemMemoryLength = (UINT32)SystemMemoryLength; 266 267 DEBUG ((EFI_D_INFO, "S3 Memory Base: %08X\n", AcpiS3Range->AcpiReservedMemoryBase)); 268 DEBUG ((EFI_D_INFO, "S3 Memory Size: %08X\n", AcpiS3Range->AcpiReservedMemorySize)); 269 DEBUG ((EFI_D_INFO, "S3 SysMemoryLength: %08X\n", AcpiS3Range->SystemMemoryLength)); 270 271 return EFI_SUCCESS; 272 } 273 274 275 EFI_STATUS 276 EFIAPI 277 InitAcpiSmmPlatform ( 278 IN EFI_HANDLE ImageHandle, 279 IN EFI_SYSTEM_TABLE *SystemTable 280 ) 281 /*++ 282 283 Routine Description: 284 285 Initializes the SMM S3 Handler Driver. 286 287 Arguments: 288 289 ImageHandle - The image handle of Sleep State Wake driver. 290 SystemTable - The starndard EFI system table. 291 292 Returns: 293 294 EFI_OUT_OF_RESOURCES - Insufficient resources to complete function. 295 EFI_SUCCESS - Function has completed successfully. 296 Other - Error occured during execution. 297 298 --*/ 299 { 300 EFI_STATUS Status; 301 EFI_GLOBAL_NVS_AREA_PROTOCOL *AcpiNvsProtocol = NULL; 302 UINTN MemoryLength; 303 EFI_PEI_HOB_POINTERS Hob; 304 305 Status = gBS->LocateProtocol ( 306 &gEfiGlobalNvsAreaProtocolGuid, 307 NULL, 308 (VOID **) &AcpiNvsProtocol 309 ); 310 ASSERT_EFI_ERROR (Status); 311 312 mAcpiSmm.BootScriptSaved = 0; 313 314 mPlatformType = (EFI_PLATFORM_TYPE)PcdGet16 (PcdPlatformType); 315 316 // 317 // Calculate the system memory length by memory hobs 318 // 319 MemoryLength = 0x100000; 320 Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR); 321 ASSERT (Hob.Raw != NULL); 322 while ((Hob.Raw != NULL) && (!END_OF_HOB_LIST (Hob))) { 323 if (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) { 324 // 325 // Skip the memory region below 1MB 326 // 327 if (Hob.ResourceDescriptor->PhysicalStart >= 0x100000) { 328 MemoryLength += (UINTN)Hob.ResourceDescriptor->ResourceLength; 329 } 330 } 331 Hob.Raw = GET_NEXT_HOB (Hob); 332 Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw); 333 } 334 335 ReservedS3Memory(MemoryLength); 336 337 // 338 // Locate and Register to Parent driver 339 // 340 Status = RegisterToDispatchDriver (); 341 ASSERT_EFI_ERROR (Status); 342 343 return EFI_SUCCESS; 344 } 345 346 EFI_STATUS 347 RegisterToDispatchDriver ( 348 VOID 349 ) 350 /*++ 351 352 Routine Description: 353 354 Register to dispatch driver. 355 356 Arguments: 357 358 None. 359 360 Returns: 361 362 EFI_SUCCESS - Successfully init the device. 363 Other - Error occured whening calling Dxe lib functions. 364 365 --*/ 366 { 367 UINTN Length; 368 EFI_STATUS Status; 369 EFI_SMM_SX_DISPATCH2_PROTOCOL *SxDispatch; 370 EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch; 371 EFI_SMM_SX_REGISTER_CONTEXT *EntryDispatchContext; 372 EFI_SMM_SX_REGISTER_CONTEXT *EntryS1DispatchContext; 373 EFI_SMM_SX_REGISTER_CONTEXT *EntryS3DispatchContext; 374 EFI_SMM_SX_REGISTER_CONTEXT *EntryS4DispatchContext; 375 EFI_SMM_SX_REGISTER_CONTEXT *EntryS5DispatchContext; 376 EFI_SMM_SW_REGISTER_CONTEXT *SwContext; 377 EFI_SMM_SW_REGISTER_CONTEXT *AcpiDisableSwContext; 378 EFI_SMM_SW_REGISTER_CONTEXT *AcpiEnableSwContext; 379 380 Status = gSmst->SmmLocateProtocol ( 381 &gEfiSmmSxDispatch2ProtocolGuid, 382 NULL, 383 (VOID **) &SxDispatch 384 ); 385 if (EFI_ERROR (Status)) { 386 return Status; 387 } 388 389 Status = gSmst->SmmLocateProtocol ( 390 &gEfiSmmSwDispatch2ProtocolGuid, 391 NULL, 392 (VOID **) &SwDispatch 393 ); 394 if (EFI_ERROR (Status)) { 395 return Status; 396 } 397 398 Length = sizeof (EFI_SMM_SX_REGISTER_CONTEXT) * 4 + sizeof (EFI_SMM_SW_REGISTER_CONTEXT) * 2; 399 Status = gSmst->SmmAllocatePool ( 400 EfiRuntimeServicesData, 401 Length, 402 (VOID **) &EntryDispatchContext 403 ); 404 if (EFI_ERROR (Status)) { 405 return Status; 406 } 407 408 SetMem (EntryDispatchContext, Length, 0); 409 410 EntryS1DispatchContext = EntryDispatchContext++; 411 EntryS3DispatchContext = EntryDispatchContext++; 412 EntryS4DispatchContext = EntryDispatchContext++; 413 EntryS5DispatchContext = EntryDispatchContext++; 414 415 SwContext = (EFI_SMM_SW_REGISTER_CONTEXT *)EntryDispatchContext; 416 AcpiDisableSwContext = SwContext++; 417 AcpiEnableSwContext = SwContext++; 418 419 // 420 // Register the enable handler 421 // 422 AcpiEnableSwContext->SwSmiInputValue = EFI_ACPI_ACPI_ENABLE; 423 Status = SwDispatch->Register ( 424 SwDispatch, 425 EnableAcpiCallback, 426 AcpiEnableSwContext, 427 &(mAcpiSmm.DisableAcpiHandle) 428 ); 429 430 // 431 // Register the disable handler 432 // 433 AcpiDisableSwContext->SwSmiInputValue = EFI_ACPI_ACPI_DISABLE; 434 Status = SwDispatch->Register ( 435 SwDispatch, 436 DisableAcpiCallback, 437 AcpiDisableSwContext, 438 &(mAcpiSmm.EnableAcpiHandle) 439 ); 440 441 442 // 443 // Register entry phase call back function for S1 444 // 445 EntryS1DispatchContext->Type = SxS1; 446 EntryS1DispatchContext->Phase = SxEntry; 447 Status = SxDispatch->Register ( 448 SxDispatch, 449 SxSleepEntryCallBack, 450 EntryS1DispatchContext, 451 &(mAcpiSmm.S1SleepEntryHandle) 452 ); 453 454 // 455 // Register entry phase call back function 456 // 457 EntryS3DispatchContext->Type = SxS3; 458 EntryS3DispatchContext->Phase = SxEntry; 459 Status = SxDispatch->Register ( 460 SxDispatch, 461 SxSleepEntryCallBack, 462 EntryS3DispatchContext, 463 &(mAcpiSmm.S3SleepEntryHandle) 464 ); 465 466 // 467 // Register entry phase call back function for S4 468 // 469 EntryS4DispatchContext->Type = SxS4; 470 EntryS4DispatchContext->Phase = SxEntry; 471 Status = SxDispatch->Register ( 472 SxDispatch, 473 SxSleepEntryCallBack, 474 EntryS4DispatchContext, 475 &(mAcpiSmm.S4SleepEntryHandle) 476 ); 477 478 // 479 // Register callback for S5 in order to workaround the LAN shutdown issue 480 // 481 EntryS5DispatchContext->Type = SxS5; 482 EntryS5DispatchContext->Phase = SxEntry; 483 Status = SxDispatch->Register ( 484 SxDispatch, 485 SxSleepEntryCallBack, 486 EntryS5DispatchContext, 487 &(mAcpiSmm.S5SoftOffEntryHandle) 488 ); 489 490 return Status; 491 } 492 493 494 EFI_STATUS 495 RestoreQncS3SwCallback ( 496 IN EFI_HANDLE DispatchHandle, 497 IN CONST VOID *DispatchContext, 498 IN OUT VOID *CommBuffer, 499 IN OUT UINTN *CommBufferSize 500 ) 501 /*++ 502 503 Routine Description: 504 SMI handler to restore QncS3 code & context for S3 path 505 This will be only triggered when BootScript got executed during resume 506 507 Arguments: 508 DispatchHandle - EFI Handle 509 DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT 510 511 Returns: 512 Nothing 513 514 --*/ 515 { 516 // 517 // Restore to original address by default 518 // 519 RestoreLockBox(&gQncS3CodeInLockBoxGuid, NULL, NULL); 520 RestoreLockBox(&gQncS3ContextInLockBoxGuid, NULL, NULL); 521 return EFI_SUCCESS; 522 } 523 524 EFI_STATUS 525 DisableAcpiCallback ( 526 IN EFI_HANDLE DispatchHandle, 527 IN CONST VOID *DispatchContext, 528 IN OUT VOID *CommBuffer, 529 IN OUT UINTN *CommBufferSize 530 ) 531 /*++ 532 533 Routine Description: 534 SMI handler to disable ACPI mode 535 536 Dispatched on reads from APM port with value 0xA1 537 538 ACPI events are disabled and ACPI event status is cleared. 539 SCI mode is then disabled. 540 Clear all ACPI event status and disable all ACPI events 541 Disable PM sources except power button 542 Clear status bits 543 Disable GPE0 sources 544 Clear status bits 545 Disable GPE1 sources 546 Clear status bits 547 Disable SCI 548 549 Arguments: 550 DispatchHandle - EFI Handle 551 DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT 552 553 Returns: 554 Nothing 555 556 --*/ 557 { 558 EFI_STATUS Status; 559 UINT16 Pm1Cnt; 560 561 Status = GetAllQncPmBase (gSmst); 562 ASSERT_EFI_ERROR (Status); 563 Pm1Cnt = IoRead16 (mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1C); 564 565 // 566 // Disable SCI 567 // 568 Pm1Cnt &= ~B_QNC_PM1BLK_PM1C_SCIEN; 569 570 IoWrite16 (mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1C, Pm1Cnt); 571 572 return EFI_SUCCESS; 573 } 574 575 EFI_STATUS 576 EnableAcpiCallback ( 577 IN EFI_HANDLE DispatchHandle, 578 IN CONST VOID *DispatchContext, 579 IN OUT VOID *CommBuffer, 580 IN OUT UINTN *CommBufferSize 581 ) 582 /*++ 583 584 Routine Description: 585 SMI handler to enable ACPI mode 586 587 Dispatched on reads from APM port with value 0xA0 588 589 Disables the SW SMI Timer. 590 ACPI events are disabled and ACPI event status is cleared. 591 SCI mode is then enabled. 592 593 Disable SW SMI Timer 594 595 Clear all ACPI event status and disable all ACPI events 596 Disable PM sources except power button 597 Clear status bits 598 599 Disable GPE0 sources 600 Clear status bits 601 602 Disable GPE1 sources 603 Clear status bits 604 605 Guarantee day-of-month alarm is invalid (ACPI 1.0 section 4.7.2.4) 606 607 Enable SCI 608 609 Arguments: 610 DispatchHandle - EFI Handle 611 DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT 612 613 Returns: 614 Nothing 615 616 --*/ 617 { 618 EFI_STATUS Status; 619 UINT32 SmiEn; 620 UINT16 Pm1Cnt; 621 UINT8 Data8; 622 623 Status = GetAllQncPmBase (gSmst); 624 ASSERT_EFI_ERROR (Status); 625 626 SmiEn = IoRead32 (mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_SMIE); 627 628 // 629 // Disable SW SMI Timer 630 // 631 SmiEn &= ~(B_QNC_GPE0BLK_SMIE_SWT); 632 IoWrite32 (mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_SMIE, SmiEn); 633 634 // 635 // Guarantee day-of-month alarm is invalid (ACPI 1.0 section 4.7.2.4) 636 // 637 Data8 = RTC_ADDRESS_REGISTER_D; 638 IoWrite8 (R_IOPORT_CMOS_STANDARD_INDEX, Data8); 639 Data8 = 0x0; 640 IoWrite8 (R_IOPORT_CMOS_STANDARD_DATA, Data8); 641 642 // 643 // Enable SCI 644 // 645 Pm1Cnt = IoRead16 (mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1C); 646 Pm1Cnt |= B_QNC_PM1BLK_PM1C_SCIEN; 647 IoWrite16 (mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1C, Pm1Cnt); 648 649 // 650 // Do platform specific stuff for ACPI enable SMI 651 // 652 653 654 return EFI_SUCCESS; 655 } 656 657 EFI_STATUS 658 SxSleepEntryCallBack ( 659 IN EFI_HANDLE DispatchHandle, 660 IN CONST VOID *DispatchContext, 661 IN OUT VOID *CommBuffer, 662 IN OUT UINTN *CommBufferSize 663 ) 664 /*++ 665 666 Routine Description: 667 668 Callback function entry for Sx sleep state. 669 670 Arguments: 671 672 DispatchHandle - The handle of this callback, obtained when registering. 673 DispatchContext - The predefined context which contained sleep type and phase. 674 675 Returns: 676 677 EFI_SUCCESS - Operation successfully performed. 678 EFI_INVALID_PARAMETER - Invalid parameter passed in. 679 680 --*/ 681 { 682 EFI_STATUS Status; 683 UINT8 Data8; 684 UINT16 Data16; 685 UINT32 Data32; 686 687 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeS3SuspendStart)); 688 689 // 690 // Reget QNC power mgmr regs base in case of OS changing it at runtime 691 // 692 Status = GetAllQncPmBase (gSmst); 693 694 // 695 // Clear RTC Alarm (if set) 696 // 697 Data8 = RTC_ADDRESS_REGISTER_C; 698 IoWrite8 (R_IOPORT_CMOS_STANDARD_INDEX, Data8); 699 Data8 = IoRead8 (R_IOPORT_CMOS_STANDARD_DATA); 700 701 // 702 // Clear all ACPI status bits 703 // 704 Data32 = B_QNC_GPE0BLK_GPE0S_ALL; 705 Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT32, mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_GPE0S, 1, &Data32 ); 706 Data16 = B_QNC_PM1BLK_PM1S_ALL; 707 Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT16, mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1S, 1, &Data16 ); 708 709 // 710 // Handling S1 - setting appropriate wake bits in GPE0_EN 711 // 712 if ((DispatchHandle == mAcpiSmm.S1SleepEntryHandle) && (((EFI_SMM_SX_REGISTER_CONTEXT *)DispatchContext)->Type == SxS1)) { 713 // 714 // Enable bit13 (EGPE), 14 (GPIO) ,17 (PCIE) in GPE0_EN 715 // 716 Status = gSmst->SmmIo.Io.Read( &gSmst->SmmIo, SMM_IO_UINT32, mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_GPE0E, 1, &Data32 ); 717 Data32 |= (B_QNC_GPE0BLK_GPE0E_EGPE | B_QNC_GPE0BLK_GPE0E_GPIO | B_QNC_GPE0BLK_GPE0E_PCIE); 718 Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT32, mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_GPE0E, 1, &Data32 ); 719 720 // 721 // Enable bit10 (RTC) in PM1E 722 // 723 Status = gSmst->SmmIo.Io.Read( &gSmst->SmmIo, SMM_IO_UINT16, mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1E, 1, &Data16 ); 724 Data16 |= B_QNC_PM1BLK_PM1E_RTC; 725 Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT16, mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1E, 1, &Data16 ); 726 727 return EFI_SUCCESS; 728 } 729 730 // 731 // Handling S4, S5 and WOL - setting appropriate wake bits in GPE0_EN 732 // 733 if (((DispatchHandle == mAcpiSmm.S4SleepEntryHandle) && (((EFI_SMM_SX_REGISTER_CONTEXT *)DispatchContext)->Type == SxS4)) || 734 ((DispatchHandle == mAcpiSmm.S5SoftOffEntryHandle) && (((EFI_SMM_SX_REGISTER_CONTEXT *)DispatchContext)->Type == SxS5)) 735 ) { 736 // 737 // Enable bit13 (EGPE), 14 (GPIO) ,17 (PCIE) in GPE0_EN 738 // Enable the WOL bits in GPE0_EN reg here for PME 739 // 740 Status = gSmst->SmmIo.Io.Read( &gSmst->SmmIo, SMM_IO_UINT32, mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_GPE0E, 1, &Data32 ); 741 Data32 |= (B_QNC_GPE0BLK_GPE0E_EGPE | B_QNC_GPE0BLK_GPE0E_GPIO | B_QNC_GPE0BLK_GPE0E_PCIE); 742 Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT32, mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_GPE0E, 1, &Data32 ); 743 744 // 745 // Enable bit10 (RTC) in PM1E 746 // 747 Status = gSmst->SmmIo.Io.Read( &gSmst->SmmIo, SMM_IO_UINT16, mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1E, 1, &Data16 ); 748 Data16 |= B_QNC_PM1BLK_PM1E_RTC; 749 Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT16, mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1E, 1, &Data16 ); 750 751 } else { 752 753 if ((DispatchHandle != mAcpiSmm.S3SleepEntryHandle) || (((EFI_SMM_SX_REGISTER_CONTEXT *)DispatchContext)->Type != SxS3)) { 754 return EFI_INVALID_PARAMETER; 755 } 756 757 Status = SaveRuntimeScriptTable (gSmst); 758 if (EFI_ERROR (Status)) { 759 return Status; 760 } 761 762 // 763 // Enable bit13 (EGPE), 14 (GPIO), 17 (PCIE) in GPE0_EN 764 // Enable the WOL bits in GPE0_EN reg here for PME 765 // 766 Status = gSmst->SmmIo.Io.Read( &gSmst->SmmIo, SMM_IO_UINT32, mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_GPE0E, 1, &Data32 ); 767 Data32 |= (B_QNC_GPE0BLK_GPE0E_EGPE | B_QNC_GPE0BLK_GPE0E_GPIO | B_QNC_GPE0BLK_GPE0E_PCIE); 768 Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT32, mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_GPE0E, 1, &Data32 ); 769 770 // 771 // Enable bit10 (RTC) in PM1E 772 // 773 Status = gSmst->SmmIo.Io.Read( &gSmst->SmmIo, SMM_IO_UINT16, mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1E, 1, &Data16 ); 774 Data16 |= B_QNC_PM1BLK_PM1E_RTC; 775 Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT16, mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1E, 1, &Data16 ); 776 } 777 778 // 779 // When entering a power-managed state like S3, 780 // PERST# must be asserted in advance of power-off. 781 // 782 PlatformPERSTAssert (mPlatformType); 783 784 return EFI_SUCCESS; 785 } 786 787 EFI_STATUS 788 GetAllQncPmBase ( 789 IN EFI_SMM_SYSTEM_TABLE2 *Smst 790 ) 791 /*++ 792 793 Routine Description: 794 795 Get QNC chipset LPC Power Management I/O Base at runtime. 796 797 Arguments: 798 799 Smst - The standard SMM system table. 800 801 Returns: 802 803 EFI_SUCCESS - Successfully init the device. 804 Other - Error occured whening calling Dxe lib functions. 805 806 --*/ 807 { 808 mAcpiSmm.QncPmBase = PciRead16 (PCI_LIB_ADDRESS(PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, R_QNC_LPC_PM1BLK)) & B_QNC_LPC_PM1BLK_MASK; 809 mAcpiSmm.QncGpe0Base = PciRead16 (PCI_LIB_ADDRESS(PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, R_QNC_LPC_GPE0BLK)) & B_QNC_LPC_GPE0BLK_MASK; 810 811 // 812 // Quark does not support Changing Primary SoC IOBARs from what was 813 // setup in SEC/PEI UEFI stages. 814 // 815 ASSERT (mAcpiSmm.QncPmBase == (UINT32) PcdGet16 (PcdPm1blkIoBaseAddress)); 816 ASSERT (mAcpiSmm.QncGpe0Base == (UINT32) PcdGet16 (PcdGpe0blkIoBaseAddress)); 817 return EFI_SUCCESS; 818 } 819 820 EFI_STATUS 821 SaveRuntimeScriptTable ( 822 IN EFI_SMM_SYSTEM_TABLE2 *Smst 823 ) 824 { 825 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress; 826 UINT32 Data32; 827 UINT16 Data16; 828 UINT8 Mask; 829 UINTN Index; 830 UINTN Offset; 831 UINT16 DeviceId; 832 833 // 834 // Check what Soc we are running on (read Host bridge DeviceId) 835 // 836 DeviceId = QncGetSocDeviceId(); 837 838 // 839 // Save PCI-Host bridge settings (0, 0, 0). 0x90, 94 and 9c are changed by CSM 840 // and vital to S3 resume. That's why we put save code here 841 // 842 Index = 0; 843 while (mPciCfgRegTable[Index] != PCI_DEVICE_END) { 844 845 PciAddress.Bus = mPciCfgRegTable[Index++]; 846 PciAddress.Device = mPciCfgRegTable[Index++]; 847 PciAddress.Function = mPciCfgRegTable[Index++]; 848 PciAddress.Register = 0; 849 PciAddress.ExtendedRegister = 0; 850 851 Data16 = PciRead16 (PCI_LIB_ADDRESS(PciAddress.Bus, PciAddress.Device, PciAddress.Function, PciAddress.Register)); 852 if (Data16 == 0xFFFF) { 853 Index += 8; 854 continue; 855 } 856 857 for (Offset = 0, Mask = 0x01; Offset < 256; Offset += 4, Mask <<= 1) { 858 859 if (Mask == 0x00) { 860 Mask = 0x01; 861 } 862 863 if (mPciCfgRegTable[Index + Offset / 32] & Mask) { 864 865 PciAddress.Register = (UINT8) Offset; 866 Data32 = PciRead32 (PCI_LIB_ADDRESS(PciAddress.Bus, PciAddress.Device, PciAddress.Function, PciAddress.Register)); 867 868 869 // 870 // Save latest settings to runtime script table 871 // 872 S3BootScriptSavePciCfgWrite ( 873 S3BootScriptWidthUint32, 874 PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(PciAddress.Bus, PciAddress.Device, PciAddress.Function, PciAddress.Register)), 875 1, 876 &Data32 877 ); 878 } 879 } 880 881 Index += 8; 882 883 } 884 885 // 886 // Save message bus registers 887 // 888 Index = 0; 889 while (QNCS3SaveExtReg[Index] != 0xFF) { 890 Data32 = QNCPortRead (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]); 891 892 // 893 // Save IMR settings with IMR protection disabled initially 894 // HMBOUND and IMRs will be locked just before jumping to the OS waking vector 895 // 896 if (QNCS3SaveExtReg[Index] == QUARK_NC_MEMORY_MANAGER_SB_PORT_ID) { 897 if ((QNCS3SaveExtReg[Index + 1] >= (QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXL)) && (QNCS3SaveExtReg[Index + 1] <= (QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXWM)) && ((QNCS3SaveExtReg[Index + 1] & 0x03) == QUARK_NC_MEMORY_MANAGER_IMRXL)) { 898 Data32 &= ~IMR_LOCK; 899 if (DeviceId == QUARK2_MC_DEVICE_ID) { 900 Data32 &= ~IMR_EN; 901 } 902 } 903 if ((QNCS3SaveExtReg[Index + 1] >= (QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXRM)) && (QNCS3SaveExtReg[Index + 1] <= (QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXWM)) && ((QNCS3SaveExtReg[Index + 1] & 0x03) >= QUARK_NC_MEMORY_MANAGER_IMRXRM)) { 904 Data32 = (UINT32)IMRX_ALL_ACCESS; 905 } 906 } 907 908 // 909 // Save latest settings to runtime script table 910 // 911 S3BootScriptSavePciCfgWrite ( 912 S3BootScriptWidthUint32, 913 PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MDR)), 914 1, 915 &Data32 916 ); 917 918 Data32 = MESSAGE_WRITE_DW (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]); 919 920 S3BootScriptSavePciCfgWrite ( 921 S3BootScriptWidthUint32, 922 PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MCR)), 923 1, 924 &Data32 925 ); 926 Index += 2; 927 } 928 929 Index = 0; 930 while (QNCS3SaveExtReg[Index] != 0xFF) { 931 // 932 // Save IMR settings with IMR protection enabled (above script was to handle restoring all settings first - now we want to enable) 933 // 934 if (QNCS3SaveExtReg[Index] == QUARK_NC_MEMORY_MANAGER_SB_PORT_ID) { 935 if (DeviceId == QUARK2_MC_DEVICE_ID) { 936 if ((QNCS3SaveExtReg[Index + 1] >= (QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXL)) && (QNCS3SaveExtReg[Index + 1] <= (QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXWM)) && ((QNCS3SaveExtReg[Index + 1] & 0x03) == QUARK_NC_MEMORY_MANAGER_IMRXL)) { 937 Data32 = QNCPortRead (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]); 938 Data32 &= ~IMR_LOCK; 939 940 // 941 // Save latest settings to runtime script table 942 // 943 S3BootScriptSavePciCfgWrite ( 944 S3BootScriptWidthUint32, 945 PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MDR)), 946 1, 947 &Data32 948 ); 949 950 Data32 = MESSAGE_WRITE_DW (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]); 951 952 S3BootScriptSavePciCfgWrite ( 953 S3BootScriptWidthUint32, 954 PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MCR)), 955 1, 956 &Data32 957 ); 958 } 959 } else { 960 if ((QNCS3SaveExtReg[Index + 1] >= (QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXRM)) && (QNCS3SaveExtReg[Index + 1] <= (QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXWM)) && ((QNCS3SaveExtReg[Index + 1] & 0x03) >= QUARK_NC_MEMORY_MANAGER_IMRXRM)) { 961 Data32 = QNCPortRead (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]); 962 963 // 964 // Save latest settings to runtime script table 965 // 966 S3BootScriptSavePciCfgWrite ( 967 S3BootScriptWidthUint32, 968 PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MDR)), 969 1, 970 &Data32 971 ); 972 973 Data32 = MESSAGE_WRITE_DW (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]); 974 975 S3BootScriptSavePciCfgWrite ( 976 S3BootScriptWidthUint32, 977 PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MCR)), 978 1, 979 &Data32 980 ); 981 } 982 } 983 } 984 Index += 2; 985 } 986 987 // Check if ECC scrub enabled and need re-enabling on resume 988 // All scrub related configuration registers are saved on suspend 989 // as part of QNCS3SaveExtReg configuration table script. 990 // The code below extends the S3 resume script with scrub reactivation 991 // message (if needed only) 992 Data32 = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_CONFIG_REG); 993 if( 0 != (Data32 & SCRUB_CFG_ACTIVE)) { 994 995 Data32 = SCRUB_RESUME_MSG(); 996 997 S3BootScriptSavePciCfgWrite ( 998 S3BootScriptWidthUint32, 999 PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MCR)), 1000 1, 1001 &Data32 1002 ); 1003 } 1004 1005 // 1006 // Save I/O ports to S3 script table 1007 // 1008 1009 // 1010 // Important to trap Sx for SMM 1011 // 1012 Data32 = IoRead32 (mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_SMIE); 1013 S3BootScriptSaveIoWrite(S3BootScriptWidthUint32, (mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_SMIE), 1, &Data32); 1014 1015 return EFI_SUCCESS; 1016 } 1017 1018