1/** @file
2PCH SPI Runtime Driver implements the SPI Host Controller Compatibility Interface.
3
4Copyright (c) 2013-2015 Intel Corporation.
5
6This program and the accompanying materials
7are licensed and made available under the terms and conditions of the BSD License
8which accompanies this distribution.  The full text of the license may be found at
9http://opensource.org/licenses/bsd-license.php
10
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14**/
15#include "PchSpi.h"
16
17extern EFI_GUID gEfiEventVirtualAddressChangeGuid;
18
19//
20// Global variables
21//
22SPI_INSTANCE  *mSpiInstance;
23CONST UINT32 mSpiRegister[] = {
24  R_QNC_RCRB_SPIS,
25  R_QNC_RCRB_SPIPREOP,
26  R_QNC_RCRB_SPIOPMENU,
27  R_QNC_RCRB_SPIOPMENU + 4
28  };
29
30//
31// Function implementations
32//
33VOID
34PchSpiVirtualddressChangeEvent (
35  IN EFI_EVENT        Event,
36  IN VOID             *Context
37  )
38/*++
39
40Routine Description:
41
42  Fixup internal data pointers so that the services can be called in virtual mode.
43
44Arguments:
45
46  Event     The event registered.
47  Context   Event context. Not used in this event handler.
48
49Returns:
50
51  None.
52
53--*/
54{
55  gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSpiInstance->PchRootComplexBar));
56  gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSpiInstance->SpiProtocol.Init));
57  gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSpiInstance->SpiProtocol.Lock));
58  gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSpiInstance->SpiProtocol.Execute));
59  gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSpiInstance));
60}
61
62EFI_STATUS
63EFIAPI
64InstallPchSpi (
65  IN EFI_HANDLE            ImageHandle,
66  IN EFI_SYSTEM_TABLE      *SystemTable
67  )
68/*++
69
70Routine Description:
71
72  Entry point for the SPI host controller driver.
73
74Arguments:
75
76  ImageHandle       Image handle of this driver.
77  SystemTable       Global system service table.
78
79Returns:
80
81  EFI_SUCCESS           Initialization complete.
82  EFI_UNSUPPORTED       The chipset is unsupported by this driver.
83  EFI_OUT_OF_RESOURCES  Do not have enough resources to initialize the driver.
84  EFI_DEVICE_ERROR      Device error, driver exits abnormally.
85
86--*/
87{
88  EFI_STATUS                      Status;
89  UINT64                          BaseAddress;
90  UINT64                          Length;
91  EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdMemorySpaceDescriptor;
92  UINT64                          Attributes;
93  EFI_EVENT                       Event;
94
95  DEBUG ((DEBUG_INFO, "InstallPchSpi() Start\n"));
96
97  //
98  // Allocate Runtime memory for the SPI protocol instance.
99  //
100  mSpiInstance = AllocateRuntimeZeroPool (sizeof (SPI_INSTANCE));
101  if (mSpiInstance == NULL) {
102    return EFI_OUT_OF_RESOURCES;
103  }
104  //
105  // Initialize the SPI protocol instance
106  //
107  Status = SpiProtocolConstructor (mSpiInstance);
108  if (EFI_ERROR (Status)) {
109    return Status;
110  }
111  //
112  // Install the EFI_SPI_PROTOCOL interface
113  //
114  Status = gBS->InstallMultipleProtocolInterfaces (
115                  &(mSpiInstance->Handle),
116                  &gEfiSpiProtocolGuid,
117                  &(mSpiInstance->SpiProtocol),
118                  NULL
119                  );
120  if (EFI_ERROR (Status)) {
121    FreePool (mSpiInstance);
122    return EFI_DEVICE_ERROR;
123  }
124  //
125  // Set RCBA space in GCD to be RUNTIME so that the range will be supported in
126  // virtual address mode in EFI aware OS runtime.
127  // It will assert if RCBA Memory Space is not allocated
128  // The caller is responsible for the existence and allocation of the RCBA Memory Spaces
129  //
130  BaseAddress = (EFI_PHYSICAL_ADDRESS) (mSpiInstance->PchRootComplexBar);
131  Length      = PcdGet64 (PcdRcbaMmioSize);
132
133  Status      = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdMemorySpaceDescriptor);
134  ASSERT_EFI_ERROR (Status);
135
136  Attributes = GcdMemorySpaceDescriptor.Attributes | EFI_MEMORY_RUNTIME;
137
138  Status = gDS->AddMemorySpace (
139                  EfiGcdMemoryTypeMemoryMappedIo,
140                  BaseAddress,
141                  Length,
142                  EFI_MEMORY_RUNTIME | EFI_MEMORY_UC
143                  );
144  ASSERT_EFI_ERROR(Status);
145
146  Status = gDS->SetMemorySpaceAttributes (
147                  BaseAddress,
148                  Length,
149                  Attributes
150                  );
151  ASSERT_EFI_ERROR (Status);
152
153  Status = gBS->CreateEventEx (
154                  EVT_NOTIFY_SIGNAL,
155                  TPL_NOTIFY,
156                  PchSpiVirtualddressChangeEvent,
157                  NULL,
158                  &gEfiEventVirtualAddressChangeGuid,
159                  &Event
160                  );
161  ASSERT_EFI_ERROR (Status);
162
163  DEBUG ((DEBUG_INFO, "InstallPchSpi() End\n"));
164
165  return EFI_SUCCESS;
166}
167
168VOID
169EFIAPI
170SpiPhaseInit (
171  VOID
172  )
173/*++
174Routine Description:
175
176  This function is a a hook for Spi Dxe phase specific initialization
177
178Arguments:
179
180  None
181
182Returns:
183
184  None
185
186--*/
187{
188  UINTN  Index;
189
190  //
191  // Disable SMM BIOS write protect if it's not a SMM protocol
192  //
193  MmioAnd8 (
194    PciDeviceMmBase (PCI_BUS_NUMBER_QNC,
195    PCI_DEVICE_NUMBER_QNC_LPC,
196    PCI_FUNCTION_NUMBER_QNC_LPC) + R_QNC_LPC_BIOS_CNTL,
197    (UINT8) (~B_QNC_LPC_BIOS_CNTL_SMM_BWP)
198    );
199
200    //
201    // Save SPI Registers for S3 resume usage
202    //
203    for (Index = 0; Index < sizeof (mSpiRegister) / sizeof (UINT32); Index++) {
204    S3BootScriptSaveMemWrite (
205      S3BootScriptWidthUint32,
206        (UINTN) (mSpiInstance->PchRootComplexBar + mSpiRegister[Index]),
207        1,
208        (VOID *) (UINTN) (mSpiInstance->PchRootComplexBar + mSpiRegister[Index])
209        );
210    }
211}
212