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