Home | History | Annotate | Download | only in VlvPlatformInitDxe
      1 
      2 /*++
      3 
      4 Copyright (c)  2011  - 2014, Intel Corporation. All rights reserved
      5 
      6   This program and the accompanying materials are licensed and made available under
      8   the terms and conditions of the BSD License that accompanies this distribution.
     10   The full text of the license may be found at
     12   http://opensource.org/licenses/bsd-license.php.
     14 
     16   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     18   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     20 
     22 
     24 
     25 Module Name:
     26 
     27   IgdOpRegion.c
     28 
     29 Abstract:
     30 
     31   This is part of the implementation of an Intel Graphics drivers OpRegion /
     32   Software SCI interface between system BIOS, ASL code, and Graphics drivers.
     33   The code in this file will load the driver and initialize the interface
     34 
     35   Supporting Specifiction: OpRegion / Software SCI SPEC 0.70
     36 
     37   Acronyms:
     38     IGD:        Internal Graphics Device
     39     NVS:        ACPI Non Volatile Storage
     40     OpRegion:   ACPI Operational Region
     41     VBT:        Video BIOS Table (OEM customizable data)
     42 
     43 --*/
     44 
     45 //
     46 // Include files
     47 //
     48 
     49 
     50 #include "IgdOpRegion.h"
     51 #include "VlvPlatformInit.h"
     52 #include <FrameworkDxe.h>
     53 #include <Uefi.h>
     54 #include <PchRegs.h>
     55 
     56 #include <Guid/DataHubRecords.h>
     57 
     58 #include <Protocol/IgdOpRegion.h>
     59 #include <Protocol/FrameworkHii.h>
     60 #include <Protocol/FirmwareVolume.h>
     61 #include <Protocol/PlatformGopPolicy.h>
     62 #include <Protocol/PciIo.h>
     63 #include <Protocol/CpuIo.h>
     64 #include <Protocol/GlobalNvsArea.h>
     65 #include <Protocol/DxeSmmReadyToLock.h>
     66 #include <Protocol/PciRootBridgeIo.h>
     67 
     68 #include <Library/MemoryAllocationLib.h>
     69 #include <Library/BaseLib.h>
     70 #include <Library/S3BootScriptLib.h>
     71 #include <Library/IoLib.h>
     72 #include <Library/DevicePathLib.h>
     73 #include <Protocol/DriverBinding.h>
     74 #include <Library/PrintLib.h>
     75 #include <Library/BaseMemoryLib.h>
     76 
     77 
     78 
     79 UINT8 gSVER[12] = "Intel";
     80 
     81 extern DXE_VLV_PLATFORM_POLICY_PROTOCOL  *DxePlatformSaPolicy;
     82 
     83 //
     84 // Global variables
     85 //
     86 
     87 IGD_OPREGION_PROTOCOL mIgdOpRegion;
     88 EFI_GUID              mMiscSubClass = EFI_MISC_SUBCLASS_GUID;
     89 EFI_EVENT             mConOutEvent;
     90 EFI_EVENT             mSetGOPverEvent;
     91 VOID                  *mConOutReg;
     92 
     93 #define DEFAULT_FORM_BUFFER_SIZE    0xFFFF
     94 #ifndef ECP_FLAG
     95 #if 0
     96 /**
     97 
     98   Get the HII protocol interface
     99 
    100   @param Hii     HII protocol interface
    101 
    102   @retval        Status code
    103 
    104 **/
    105 static
    106 EFI_STATUS
    107 GetHiiInterface (
    108   OUT     EFI_HII_PROTOCOL    **Hii
    109   )
    110 {
    111   EFI_STATUS  Status;
    112 
    113   //
    114   // There should only be one HII protocol
    115   //
    116   Status = gBS->LocateProtocol (
    117                   &gEfiHiiProtocolGuid,
    118                   NULL,
    119                   (VOID **) Hii
    120                   );
    121 
    122   return Status;;
    123 }
    124 #endif
    125 #endif
    126 
    127 /**
    128 
    129   Get VBT data.
    130 
    131   @param[in] VbtFileBuffer    Pointer to VBT data buffer.
    132 
    133   @retval EFI_SUCCESS      VBT data was returned.
    134   @retval EFI_NOT_FOUND    VBT data not found.
    135   @exception EFI_UNSUPPORTED  Invalid signature in VBT data.
    136 
    137 **/
    138 EFI_STATUS
    139 GetIntegratedIntelVbtPtr (
    140   OUT VBIOS_VBT_STRUCTURE **VbtFileBuffer
    141   )
    142 {
    143   EFI_STATUS                    Status;
    144   EFI_PHYSICAL_ADDRESS          VbtAddress = 0;
    145   UINTN                         FvProtocolCount;
    146   EFI_HANDLE                    *FvHandles;
    147   EFI_FIRMWARE_VOLUME_PROTOCOL  *Fv;
    148   UINTN                         Index;
    149   UINT32                        AuthenticationStatus;
    150 
    151   UINT8                         *Buffer;
    152   UINTN                         VbtBufferSize = 0;
    153 
    154   Buffer = 0;
    155   FvHandles      = NULL;
    156   *VbtFileBuffer = NULL;
    157   Status = gBS->LocateHandleBuffer (
    158                   ByProtocol,
    159                   &gEfiFirmwareVolumeProtocolGuid,
    160                   NULL,
    161                   &FvProtocolCount,
    162                   &FvHandles
    163                   );
    164 
    165   if (!EFI_ERROR (Status)) {
    166     for (Index = 0; Index < FvProtocolCount; Index++) {
    167       Status = gBS->HandleProtocol (
    168                       FvHandles[Index],
    169                       &gEfiFirmwareVolumeProtocolGuid,
    170                       (VOID **) &Fv
    171                       );
    172       VbtBufferSize = 0;
    173       Status = Fv->ReadSection (
    174                      Fv,
    175                      &gBmpImageGuid,
    176                      EFI_SECTION_RAW,
    177                      0,
    178                     (void **)&Buffer,
    179                      &VbtBufferSize,
    180                      &AuthenticationStatus
    181                      );
    182 
    183       if (!EFI_ERROR (Status)) {
    184         VbtAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
    185         Status = EFI_SUCCESS;
    186         break;
    187       }
    188     }
    189   } else {
    190     Status = EFI_NOT_FOUND;
    191   }
    192 
    193   if (FvHandles != NULL) {
    194     FreePool(FvHandles);
    195     FvHandles = NULL;
    196   }
    197 
    198 
    199   //
    200   // Check VBT signature
    201   //
    202   *VbtFileBuffer = (VBIOS_VBT_STRUCTURE *) (UINTN) VbtAddress;
    203   if (*VbtFileBuffer != NULL) {
    204     if ((*((UINT32 *) ((*VbtFileBuffer)->HeaderSignature))) != VBT_SIGNATURE) {
    205       if (*VbtFileBuffer != NULL) {
    206         *VbtFileBuffer = NULL;
    207       }
    208       return EFI_UNSUPPORTED;
    209     }
    210     //
    211     // Check VBT size
    212     //
    213     if ((*VbtFileBuffer)->HeaderVbtSize > VbtBufferSize) {
    214       (*VbtFileBuffer)->HeaderVbtSize = (UINT16) VbtBufferSize;
    215     }
    216   }
    217 
    218   return EFI_SUCCESS;
    219 }
    220 
    221 //
    222 // Function implementations.
    223 //
    224 /**
    225 
    226   Get a pointer to an uncompressed image of the Intel video BIOS.
    227 
    228   Note: This function would only be called if the video BIOS at 0xC000 is
    229         missing or not an Intel video BIOS.  It may not be an Intel video BIOS
    230         if the Intel graphic contoller is considered a secondary adapter.
    231 
    232 
    233   @param VBiosROMImage  Pointer to an uncompressed Intel video BIOS.  This pointer must
    234                         be set to NULL if an uncompressed image of the Intel Video BIOS
    235                         is not obtainable.
    236 
    237 
    238   @retval EFI_SUCCESS   VBiosPtr is updated.
    239 
    240 **/
    241 EFI_STATUS
    242 GetIntegratedIntelVBiosPtr (
    243   INTEL_VBIOS_OPTION_ROM_HEADER **VBiosImage
    244   )
    245 {
    246   EFI_HANDLE                  *HandleBuffer;
    247   UINTN                       HandleCount;
    248   UINTN                       Index;
    249   INTEL_VBIOS_PCIR_STRUCTURE  *PcirBlockPtr;
    250   EFI_STATUS                  Status;
    251   EFI_PCI_IO_PROTOCOL         *PciIo;
    252   INTEL_VBIOS_OPTION_ROM_HEADER *VBiosRomImage;
    253 
    254   //
    255   // Set as if an umcompressed Intel video BIOS image was not obtainable.
    256   //
    257   VBiosRomImage = NULL;
    258   *VBiosImage = NULL;
    259 
    260   //
    261   // Get all PCI IO protocols
    262   //
    263   Status = gBS->LocateHandleBuffer (
    264                   ByProtocol,
    265                   &gEfiPciIoProtocolGuid,
    266                   NULL,
    267                   &HandleCount,
    268                   &HandleBuffer
    269                   );
    270   ASSERT_EFI_ERROR (Status);
    271 
    272   //
    273   // Find the video BIOS by checking each PCI IO handle for an Intel video
    274   // BIOS OPROM.
    275   //
    276   for (Index = 0; Index < HandleCount; Index++) {
    277     Status = gBS->HandleProtocol (
    278                     HandleBuffer[Index],
    279                     &gEfiPciIoProtocolGuid,
    280                     (void **)&PciIo
    281                     );
    282     ASSERT_EFI_ERROR (Status);
    283 
    284     VBiosRomImage = PciIo->RomImage;
    285 
    286     //
    287     // If this PCI device doesn't have a ROM image, skip to the next device.
    288     //
    289     if (!VBiosRomImage) {
    290       continue;
    291     }
    292 
    293     //
    294     // Get pointer to PCIR structure
    295     //
    296     PcirBlockPtr = (INTEL_VBIOS_PCIR_STRUCTURE *)((UINT8 *) VBiosRomImage + VBiosRomImage->PcirOffset);
    297 
    298     //
    299     // Check if we have an Intel video BIOS OPROM.
    300     //
    301     if ((VBiosRomImage->Signature == OPTION_ROM_SIGNATURE) &&
    302         (PcirBlockPtr->VendorId == IGD_VID) &&
    303         (PcirBlockPtr->ClassCode[0] == 0x00) &&
    304         (PcirBlockPtr->ClassCode[1] == 0x00) &&
    305         (PcirBlockPtr->ClassCode[2] == 0x03)
    306        ) {
    307       //
    308       // Found Intel video BIOS.
    309       //
    310       *VBiosImage = VBiosRomImage;
    311       return EFI_SUCCESS;
    312     }
    313   }
    314 
    315   //
    316   // No Intel video BIOS found.
    317   //
    318 
    319   //
    320   // Free any allocated buffers
    321   //
    322   return EFI_UNSUPPORTED;
    323 }
    324 
    325 EFI_STATUS
    326 SearchChildHandle(
    327   EFI_HANDLE Father,
    328   EFI_HANDLE *Child
    329   )
    330 {
    331   EFI_STATUS            Status;
    332   UINTN                 HandleIndex;
    333   EFI_GUID              **ProtocolGuidArray = NULL;
    334   UINTN                 ArrayCount;
    335   UINTN                 ProtocolIndex;
    336   UINTN                 OpenInfoCount;
    337   UINTN                 OpenInfoIndex;
    338   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY  *OpenInfo = NULL;
    339   UINTN                 mHandleCount;
    340   EFI_HANDLE            *mHandleBuffer= NULL;
    341 
    342   //
    343   // Retrieve the list of all handles from the handle database
    344   //
    345   Status = gBS->LocateHandleBuffer (
    346                   AllHandles,
    347                   NULL,
    348                   NULL,
    349                   &mHandleCount,
    350                   &mHandleBuffer
    351                   );
    352 
    353   for (HandleIndex = 0; HandleIndex < mHandleCount; HandleIndex++) {
    354     //
    355     // Retrieve the list of all the protocols on each handle
    356     //
    357     Status = gBS->ProtocolsPerHandle (
    358                     mHandleBuffer[HandleIndex],
    359                     &ProtocolGuidArray,
    360                     &ArrayCount
    361                     );
    362     if (!EFI_ERROR (Status)) {
    363       for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) {
    364         Status = gBS->OpenProtocolInformation (
    365                         mHandleBuffer[HandleIndex],
    366                         ProtocolGuidArray[ProtocolIndex],
    367                         &OpenInfo,
    368                         &OpenInfoCount
    369                         );
    370         if (!EFI_ERROR (Status)) {
    371           for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) {
    372             if(OpenInfo[OpenInfoIndex].AgentHandle == Father) {
    373               if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) == EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
    374                 *Child = mHandleBuffer[HandleIndex];
    375                 Status = EFI_SUCCESS;
    376                 goto TryReturn;
    377               }
    378             }
    379           }
    380           Status = EFI_NOT_FOUND;
    381         }
    382       }
    383       if(OpenInfo != NULL) {
    384         FreePool(OpenInfo);
    385         OpenInfo = NULL;
    386       }
    387     }
    388     FreePool (ProtocolGuidArray);
    389     ProtocolGuidArray = NULL;
    390   }
    391 TryReturn:
    392   if(OpenInfo != NULL) {
    393     FreePool (OpenInfo);
    394     OpenInfo = NULL;
    395   }
    396   if(ProtocolGuidArray != NULL) {
    397     FreePool(ProtocolGuidArray);
    398     ProtocolGuidArray = NULL;
    399   }
    400   if(mHandleBuffer != NULL) {
    401     FreePool (mHandleBuffer);
    402     mHandleBuffer = NULL;
    403   }
    404   return Status;
    405 }
    406 
    407 EFI_STATUS
    408 JudgeHandleIsPCIDevice(
    409   EFI_HANDLE            Handle,
    410   UINT8                 Device,
    411   UINT8                 Funs
    412   )
    413 {
    414   EFI_STATUS  Status;
    415   EFI_DEVICE_PATH   *DPath;
    416 
    417   Status = gBS->HandleProtocol (
    418                   Handle,
    419                   &gEfiDevicePathProtocolGuid,
    420                   (VOID **) &DPath
    421                   );
    422   if(!EFI_ERROR(Status)) {
    423     while(!IsDevicePathEnd(DPath)) {
    424       if((DPath->Type == HARDWARE_DEVICE_PATH) && (DPath->SubType == HW_PCI_DP)) {
    425         PCI_DEVICE_PATH   *PCIPath;
    426 
    427         PCIPath = (PCI_DEVICE_PATH*) DPath;
    428         DPath = NextDevicePathNode(DPath);
    429         if(IsDevicePathEnd(DPath) && (PCIPath->Device == Device) && (PCIPath->Function == Funs)) {
    430           return EFI_SUCCESS;
    431         }
    432       } else {
    433         DPath = NextDevicePathNode(DPath);
    434       }
    435     }
    436   }
    437   return EFI_UNSUPPORTED;
    438 }
    439 
    440 EFI_STATUS
    441 GetDriverName(
    442   EFI_HANDLE   Handle,
    443   CHAR16         *GopVersion
    444   )
    445 {
    446   EFI_DRIVER_BINDING_PROTOCOL           *BindHandle = NULL;
    447   EFI_STATUS                            Status;
    448   UINT32                                Version;
    449   UINT16                                *Ptr;
    450 
    451   Status = gBS->OpenProtocol(
    452                   Handle,
    453                   &gEfiDriverBindingProtocolGuid,
    454                   (VOID**)&BindHandle,
    455                   NULL,
    456                   NULL,
    457                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    458                   );
    459   if (EFI_ERROR(Status)) {
    460     return EFI_NOT_FOUND;
    461   }
    462 
    463   Version = BindHandle->Version;
    464   Ptr = (UINT16*)&Version;
    465   UnicodeSPrint(GopVersion, 40, L"7.0.%04d", *(Ptr));
    466   return EFI_SUCCESS;
    467 }
    468 
    469 EFI_STATUS
    470 GetGOPDriverVersion(
    471   CHAR16 *GopVersion
    472   )
    473 {
    474   UINTN                 HandleCount;
    475   EFI_HANDLE            *Handles= NULL;
    476   UINTN                 Index;
    477   EFI_STATUS            Status;
    478   EFI_HANDLE            Child = 0;
    479 
    480   Status = gBS->LocateHandleBuffer(
    481                   ByProtocol,
    482                   &gEfiDriverBindingProtocolGuid,
    483                   NULL,
    484                   &HandleCount,
    485                   &Handles
    486                   );
    487   for (Index = 0; Index < HandleCount ; Index++) {
    488     Status = SearchChildHandle(Handles[Index], &Child);
    489     if(!EFI_ERROR(Status)) {
    490       Status = JudgeHandleIsPCIDevice(Child, 0x02, 0x00);
    491       if(!EFI_ERROR(Status)) {
    492         return GetDriverName(Handles[Index], GopVersion);
    493       }
    494     }
    495   }
    496   return EFI_UNSUPPORTED;
    497 }
    498 
    499 
    500 /**
    501   Get Intel GOP driver version and copy it into IGD OpRegion GVER. This version
    502   is picked up by IGD driver and displayed in CUI.
    503 
    504   @param  Event             A pointer to the Event that triggered the callback.
    505   @param  Context           A pointer to private data registered with the callback function.
    506 
    507   @retval EFI_SUCCESS       Video BIOS VBT information returned.
    508   @retval EFI_UNSUPPORTED   Could not find VBT information (*VBiosVbtPtr = NULL).
    509 
    510 **/
    511 EFI_STATUS
    512 EFIAPI
    513 SetGOPVersionCallback (
    514   IN EFI_EVENT Event,
    515   IN VOID      *Context
    516   )
    517 {
    518   CHAR16                GopVersion[16] = {0};
    519   EFI_STATUS            Status;
    520 
    521   Status = GetGOPDriverVersion(GopVersion);
    522   if(!EFI_ERROR(Status)) {
    523     StrCpy((CHAR16*)&(mIgdOpRegion.OpRegion->Header.GOPV[0]), GopVersion);
    524     return Status;
    525   }
    526   return EFI_UNSUPPORTED;
    527 }
    528 
    529 /**
    530   Get Intel video BIOS VBT information (i.e. Pointer to VBT and VBT size).
    531   The VBT (Video BIOS Table) is a block of customizable data that is built
    532   within the video BIOS and edited by customers.
    533 
    534   @param  Event             A pointer to the Event that triggered the callback.
    535   @param  Context           A pointer to private data registered with the callback function.
    536 
    537   @retval EFI_SUCCESS       Video BIOS VBT information returned.
    538   @retval EFI_UNSUPPORTED   Could not find VBT information (*VBiosVbtPtr = NULL).
    539 
    540 **/
    541 EFI_STATUS
    542 GetVBiosVbtCallback (
    543   IN EFI_EVENT Event,
    544   IN VOID      *Context
    545   )
    546 {
    547   INTEL_VBIOS_PCIR_STRUCTURE    *PcirBlockPtr;
    548   UINT16                        PciVenderId;
    549   UINT16                        PciDeviceId;
    550   INTEL_VBIOS_OPTION_ROM_HEADER *VBiosPtr;
    551   VBIOS_VBT_STRUCTURE           *VBiosVbtPtr;
    552   VBIOS_VBT_STRUCTURE           *VbtFileBuffer = NULL;
    553 
    554   VBiosPtr = (INTEL_VBIOS_OPTION_ROM_HEADER *)(UINTN)(VBIOS_LOCATION_PRIMARY);
    555   PcirBlockPtr = (INTEL_VBIOS_PCIR_STRUCTURE *)((UINT8 *)VBiosPtr + VBiosPtr->PcirOffset);
    556   PciVenderId = PcirBlockPtr->VendorId;
    557   PciDeviceId = PcirBlockPtr->DeviceId;
    558 
    559   //
    560   // If the video BIOS is not at 0xC0000 or it is not an Intel video BIOS get
    561   // the integrated Intel video BIOS (must be uncompressed).
    562   //
    563   if ((VBiosPtr->Signature != OPTION_ROM_SIGNATURE) || (PciVenderId != IGD_VID) || (PciDeviceId != IGD_DID_VLV)) {
    564     GetIntegratedIntelVBiosPtr (&VBiosPtr);
    565 
    566     if(VBiosPtr) {
    567       //
    568       // Video BIOS found.
    569       //
    570       PcirBlockPtr = (INTEL_VBIOS_PCIR_STRUCTURE *)((UINT8 *)VBiosPtr + VBiosPtr->PcirOffset);
    571       PciVenderId = PcirBlockPtr->VendorId;
    572       if( (VBiosPtr->Signature != OPTION_ROM_SIGNATURE) || (PciVenderId != IGD_VID)) {
    573         //
    574         // Intel video BIOS not found.
    575         //
    576         VBiosVbtPtr = NULL;
    577         return EFI_UNSUPPORTED;
    578       }
    579     } else {
    580       //
    581       // No Video BIOS found, try to get VBT from FV.
    582       //
    583       GetIntegratedIntelVbtPtr (&VbtFileBuffer);
    584       if (VbtFileBuffer != NULL) {
    585         //
    586         // Video BIOS not found, use VBT from FV
    587         //
    588         DEBUG ((EFI_D_ERROR, "VBT data found\n"));
    589         (gBS->CopyMem) (
    590                 mIgdOpRegion.OpRegion->VBT.GVD1,
    591                 VbtFileBuffer,
    592                 VbtFileBuffer->HeaderVbtSize
    593                 );
    594         FreePool (VbtFileBuffer);
    595         return EFI_SUCCESS;
    596       }
    597     }
    598     if ((VBiosPtr == NULL) ) {
    599       //
    600       // Intel video BIOS not found.
    601       //
    602       VBiosVbtPtr = NULL;
    603       return EFI_UNSUPPORTED;
    604     }
    605   }
    606 
    607   DEBUG ((EFI_D_ERROR, "VBIOS found at 0x%X\n", VBiosPtr));
    608   VBiosVbtPtr = (VBIOS_VBT_STRUCTURE *) ((UINT8 *) VBiosPtr + VBiosPtr->VbtOffset);
    609 
    610   if ((*((UINT32 *) (VBiosVbtPtr->HeaderSignature))) != VBT_SIGNATURE) {
    611     return EFI_UNSUPPORTED;
    612   }
    613 
    614   //
    615   // Initialize Video BIOS version with its build number.
    616   //
    617   mIgdOpRegion.OpRegion->Header.VVER[0] = VBiosVbtPtr->CoreBlockBiosBuild[0];
    618   mIgdOpRegion.OpRegion->Header.VVER[1] = VBiosVbtPtr->CoreBlockBiosBuild[1];
    619   mIgdOpRegion.OpRegion->Header.VVER[2] = VBiosVbtPtr->CoreBlockBiosBuild[2];
    620   mIgdOpRegion.OpRegion->Header.VVER[3] = VBiosVbtPtr->CoreBlockBiosBuild[3];
    621   (gBS->CopyMem) (
    622           mIgdOpRegion.OpRegion->VBT.GVD1,
    623           VBiosVbtPtr,
    624           VBiosVbtPtr->HeaderVbtSize
    625           );
    626 
    627   //
    628   // Return final status
    629   //
    630   return EFI_SUCCESS;
    631 }
    632 
    633 /**
    634   Graphics OpRegion / Software SCI driver installation function.
    635 
    636   @param ImageHandle     Handle for this drivers loaded image protocol.
    637   @param SystemTable     EFI system table.
    638 
    639   @retval EFI_SUCCESS    The driver installed without error.
    640   @retval EFI_ABORTED    The driver encountered an error and could not complete
    641                          installation of the ACPI tables.
    642 
    643 **/
    644 EFI_STATUS
    645 IgdOpRegionInit (
    646   void
    647   )
    648 {
    649   EFI_HANDLE                    Handle;
    650   EFI_STATUS                    Status;
    651   EFI_GLOBAL_NVS_AREA_PROTOCOL  *GlobalNvsArea;
    652   UINT32                        DwordData;
    653   EFI_CPU_IO_PROTOCOL           *CpuIo;
    654   UINT16                        Data16;
    655   UINT16                        AcpiBase;
    656   VOID                          *gConOutNotifyReg;
    657 
    658 
    659   //
    660   //  Locate the Global NVS Protocol.
    661   //
    662   Status = gBS->LocateProtocol (
    663                   &gEfiGlobalNvsAreaProtocolGuid,
    664                   NULL,
    665                   (void **)&GlobalNvsArea
    666                   );
    667   ASSERT_EFI_ERROR (Status);
    668 
    669   //
    670   // Allocate an ACPI NVS memory buffer as the IGD OpRegion, zero initialize
    671   // the first 1K, and set the IGD OpRegion pointer in the Global NVS
    672   // area structure.
    673   //
    674   Status = (gBS->AllocatePool) (
    675                    EfiACPIMemoryNVS,
    676                    sizeof (IGD_OPREGION_STRUC),
    677                   (void **)&mIgdOpRegion.OpRegion
    678                    );
    679   ASSERT_EFI_ERROR (Status);
    680   (gBS->SetMem) (
    681           mIgdOpRegion.OpRegion,
    682           sizeof (IGD_OPREGION_STRUC),
    683           0
    684           );
    685   GlobalNvsArea->Area->IgdOpRegionAddress = (UINT32)(UINTN)(mIgdOpRegion.OpRegion);
    686 
    687   //
    688   // If IGD is disabled return
    689   //
    690   if (IgdMmPci32 (0) == 0xFFFFFFFF) {
    691     return EFI_SUCCESS;
    692   }
    693 
    694   //
    695   // Initialize OpRegion Header
    696   //
    697 
    698   (gBS->CopyMem) (
    699           mIgdOpRegion.OpRegion->Header.SIGN,
    700           HEADER_SIGNATURE,
    701           sizeof(HEADER_SIGNATURE)
    702           );
    703 
    704 
    705   //
    706   // Set OpRegion Size in KBs
    707   //
    708   mIgdOpRegion.OpRegion->Header.SIZE = HEADER_SIZE/1024;
    709 
    710   //
    711   // FIXME: Need to check Header OVER Field and the supported version.
    712   //
    713   mIgdOpRegion.OpRegion->Header.OVER = (UINT32) (LShiftU64 (HEADER_OPREGION_VER, 16) + LShiftU64 (HEADER_OPREGION_REV, 8));
    714 #ifdef ECP_FLAG
    715   CopyMem(mIgdOpRegion.OpRegion->Header.SVER, gSVER, sizeof(gSVER));
    716 #else
    717   gBS->CopyMem(
    718          mIgdOpRegion.OpRegion->Header.SVER,
    719          gSVER,
    720          sizeof(gSVER)
    721          );
    722 #endif
    723   DEBUG ((EFI_D_ERROR, "System BIOS ID is %a\n", mIgdOpRegion.OpRegion->Header.SVER));
    724 
    725 
    726   mIgdOpRegion.OpRegion->Header.MBOX = HEADER_MBOX_SUPPORT;
    727 
    728   if( 1 == DxePlatformSaPolicy->IdleReserve) {
    729     mIgdOpRegion.OpRegion->Header.PCON = (mIgdOpRegion.OpRegion->Header.PCON & 0xFFFC) | BIT1;
    730   } else {
    731     mIgdOpRegion.OpRegion->Header.PCON = (mIgdOpRegion.OpRegion->Header.PCON & 0xFFFC) | (BIT1 | BIT0);
    732   }
    733 
    734   //
    735   //For graphics driver to identify if LPE Audio/HD Audio is enabled on the platform
    736   //
    737   mIgdOpRegion.OpRegion->Header.PCON &= AUDIO_TYPE_SUPPORT_MASK;
    738   mIgdOpRegion.OpRegion->Header.PCON &= AUDIO_TYPE_FIELD_MASK;
    739   if ( 1 == DxePlatformSaPolicy->AudioTypeSupport ) {
    740     mIgdOpRegion.OpRegion->Header.PCON = HD_AUDIO_SUPPORT;
    741     mIgdOpRegion.OpRegion->Header.PCON |= AUDIO_TYPE_FIELD_VALID;
    742   }
    743 
    744   //
    745   // Initialize OpRegion Mailbox 1 (Public ACPI Methods).
    746   //
    747   //<TODO> The initial setting of mailbox 1 fields is implementation specific.
    748   // Adjust them as needed many even coming from user setting in setup.
    749   //
    750   //Workaround to solve LVDS is off after entering OS in desktop platform
    751   //
    752   mIgdOpRegion.OpRegion->MBox1.CLID = DxePlatformSaPolicy->IgdPanelFeatures.LidStatus;
    753 
    754   //
    755   // Initialize OpRegion Mailbox 3 (ASLE Interrupt and Power Conservation).
    756   //
    757   //<TODO> The initial setting of mailbox 3 fields is implementation specific.
    758   // Adjust them as needed many even coming from user setting in setup.
    759   //
    760 
    761   //
    762   // Do not initialize TCHE. This field is written by the graphics driver only.
    763   //
    764 
    765   //
    766   // The ALSI field is generally initialized by ASL code by reading the embedded controller.
    767   //
    768 
    769   mIgdOpRegion.OpRegion->MBox3.BCLP = BACKLIGHT_BRIGHTNESS;
    770 
    771   mIgdOpRegion.OpRegion->MBox3.PFIT = (FIELD_VALID_BIT | PFIT_STRETCH);
    772   if ( DxePlatformSaPolicy->IgdPanelFeatures.PFITStatus == 2) {
    773   	//
    774     // Center
    775     //
    776     mIgdOpRegion.OpRegion->MBox3.PFIT = (FIELD_VALID_BIT | PFIT_CENTER);
    777   } else if (DxePlatformSaPolicy->IgdPanelFeatures.PFITStatus == 1) {
    778   	//
    779     // Stretch
    780     //
    781     mIgdOpRegion.OpRegion->MBox3.PFIT = (FIELD_VALID_BIT | PFIT_STRETCH);
    782   } else {
    783   	//
    784     // Auto
    785     //
    786     mIgdOpRegion.OpRegion->MBox3.PFIT = (FIELD_VALID_BIT | PFIT_SETUP_AUTO);
    787   }
    788 
    789   //
    790   // Set Initial current Brightness
    791   //
    792   mIgdOpRegion.OpRegion->MBox3.CBLV = (INIT_BRIGHT_LEVEL | FIELD_VALID_BIT);
    793 
    794   //
    795   // <EXAMPLE> Create a static Backlight Brightness Level Duty cycle Mapping Table
    796   // Possible 20 entries (example used 10), each 16 bits as follows:
    797   // [15] = Field Valid bit, [14:08] = Level in Percentage (0-64h), [07:00] = Desired duty cycle (0 - FFh).
    798   //
    799   //                                             %            Brightness
    800   mIgdOpRegion.OpRegion->MBox3.BCLM[0]   = ( (  0 << 8 ) + ( 0xFF - 0xFC ) + WORD_FIELD_VALID_BIT);
    801   mIgdOpRegion.OpRegion->MBox3.BCLM[1]   = ( (  1 << 8 ) + ( 0xFF - 0xFC ) + WORD_FIELD_VALID_BIT);
    802   mIgdOpRegion.OpRegion->MBox3.BCLM[2]   = ( ( 10 << 8 ) + ( 0xFF - 0xE5 ) + WORD_FIELD_VALID_BIT);
    803   mIgdOpRegion.OpRegion->MBox3.BCLM[3]   = ( ( 19 << 8 ) + ( 0xFF - 0xCE ) + WORD_FIELD_VALID_BIT);
    804   mIgdOpRegion.OpRegion->MBox3.BCLM[4]   = ( ( 28 << 8 ) + ( 0xFF - 0xB7 ) + WORD_FIELD_VALID_BIT);
    805   mIgdOpRegion.OpRegion->MBox3.BCLM[5]   = ( ( 37 << 8 ) + ( 0xFF - 0xA0 ) + WORD_FIELD_VALID_BIT);
    806   mIgdOpRegion.OpRegion->MBox3.BCLM[6]   = ( ( 46 << 8 ) + ( 0xFF - 0x89 ) + WORD_FIELD_VALID_BIT);
    807   mIgdOpRegion.OpRegion->MBox3.BCLM[7]   = ( ( 55 << 8 ) + ( 0xFF - 0x72 ) + WORD_FIELD_VALID_BIT);
    808   mIgdOpRegion.OpRegion->MBox3.BCLM[8]   = ( ( 64 << 8 ) + ( 0xFF - 0x5B ) + WORD_FIELD_VALID_BIT);
    809   mIgdOpRegion.OpRegion->MBox3.BCLM[9]   = ( ( 73 << 8 ) + ( 0xFF - 0x44 ) + WORD_FIELD_VALID_BIT);
    810   mIgdOpRegion.OpRegion->MBox3.BCLM[10]  = ( ( 82 << 8 ) + ( 0xFF - 0x2D ) + WORD_FIELD_VALID_BIT);
    811   mIgdOpRegion.OpRegion->MBox3.BCLM[11]  = ( ( 91 << 8 ) + ( 0xFF - 0x16 ) + WORD_FIELD_VALID_BIT);
    812   mIgdOpRegion.OpRegion->MBox3.BCLM[12]  = ( (100 << 8 ) + ( 0xFF - 0x00 ) + WORD_FIELD_VALID_BIT);
    813 
    814   mIgdOpRegion.OpRegion->MBox3.PCFT = ((UINT32) GlobalNvsArea->Area->IgdPowerConservation) | BIT31;
    815   //
    816   // Create the notification and register callback function on the PciIo installation,
    817   //
    818   //
    819   Status = gBS->CreateEvent (
    820                   EVT_NOTIFY_SIGNAL,
    821                   TPL_CALLBACK,
    822                   (EFI_EVENT_NOTIFY)GetVBiosVbtCallback,
    823                   NULL,
    824                   &mConOutEvent
    825                   );
    826 
    827   ASSERT_EFI_ERROR (Status);
    828   if (EFI_ERROR (Status)) {
    829     return Status;
    830 
    831   }
    832 
    833   Status = gBS->RegisterProtocolNotify (
    834 #ifdef ECP_FLAG
    835                   &gExitPmAuthProtocolGuid,
    836 #else
    837                   &gEfiDxeSmmReadyToLockProtocolGuid,
    838 #endif
    839                   mConOutEvent,
    840                   &gConOutNotifyReg
    841                   );
    842 
    843   Status = gBS->CreateEvent (
    844                   EVT_NOTIFY_SIGNAL,
    845                   TPL_CALLBACK,
    846                   (EFI_EVENT_NOTIFY)SetGOPVersionCallback,
    847                   NULL,
    848                   &mSetGOPverEvent
    849                   );
    850 
    851   ASSERT_EFI_ERROR (Status);
    852   if (EFI_ERROR (Status)) {
    853     return Status;
    854   }
    855 
    856   Status = gBS->RegisterProtocolNotify (
    857                   &gEfiGraphicsOutputProtocolGuid,
    858                   mSetGOPverEvent,
    859                   &gConOutNotifyReg
    860                   );
    861 
    862 
    863   //
    864   // Initialize hardware state:
    865   //   Set ASLS Register to the OpRegion physical memory address.
    866   //   Set SWSCI register bit 15 to a "1" to activate SCI interrupts.
    867   //
    868 
    869   IgdMmPci32 (IGD_ASLS_OFFSET) = (UINT32)(UINTN)(mIgdOpRegion.OpRegion);
    870   IgdMmPci16AndThenOr (IGD_SWSCI_OFFSET, ~(BIT0), BIT15);
    871 
    872   DwordData = IgdMmPci32 (IGD_ASLS_OFFSET);
    873   S3BootScriptSavePciCfgWrite (
    874     S3BootScriptWidthUint32,
    875     (UINTN) (EFI_PCI_ADDRESS  (IGD_BUS, IGD_DEV, IGD_FUN_0, IGD_ASLS_OFFSET)),
    876     1,
    877     &DwordData
    878     );
    879 
    880 
    881   DwordData = IgdMmPci32 (IGD_SWSCI_OFFSET);
    882   S3BootScriptSavePciCfgWrite (
    883     S3BootScriptWidthUint32,
    884     (UINTN) (EFI_PCI_ADDRESS  (IGD_BUS, IGD_DEV, IGD_FUN_0, IGD_SWSCI_OFFSET)),
    885     1,
    886     &DwordData
    887     );
    888 
    889   AcpiBase =  MmPci16 (
    890                 0,
    891                 DEFAULT_PCI_BUS_NUMBER_PCH,
    892                 PCI_DEVICE_NUMBER_PCH_LPC,
    893                 PCI_FUNCTION_NUMBER_PCH_LPC,
    894                 R_PCH_LPC_ACPI_BASE
    895                 ) & B_PCH_LPC_ACPI_BASE_BAR;
    896 
    897   //
    898   // Find the CPU I/O Protocol.  ASSERT if not found.
    899   //
    900   Status = gBS->LocateProtocol (
    901                   &gEfiCpuIoProtocolGuid,
    902                   NULL,
    903                   (void **)&CpuIo
    904                   );
    905   ASSERT_EFI_ERROR (Status);
    906 
    907   CpuIo->Io.Read (
    908               CpuIo,
    909               EfiCpuIoWidthUint16,
    910               AcpiBase + R_PCH_ACPI_GPE0a_STS,
    911               1,
    912               &Data16
    913               );
    914   //
    915   // Clear the B_PCH_ACPI_GPE0a_STS_GUNIT_SCI bit in R_PCH_ACPI_GPE0a_STS by writing a '1'.
    916   //
    917   Data16 |= B_PCH_ACPI_GPE0a_STS_GUNIT_SCI;
    918 
    919   CpuIo->Io.Write (
    920               CpuIo,
    921               EfiCpuIoWidthUint16,
    922               AcpiBase + R_PCH_ACPI_GPE0a_STS,
    923               1,
    924               &Data16
    925               );
    926 
    927   //
    928   // Install OpRegion / Software SCI protocol
    929   //
    930   Handle = NULL;
    931   Status = gBS->InstallMultipleProtocolInterfaces (
    932                   &Handle,
    933                   &gIgdOpRegionProtocolGuid,
    934                   &mIgdOpRegion,
    935                   NULL
    936                   );
    937   ASSERT_EFI_ERROR (Status);
    938 
    939   //
    940   // Return final status
    941   //
    942   return EFI_SUCCESS;
    943 }
    944