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