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