1/** @file
2Common Lib function for QNC internal network access.
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
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
26UINT32
27EFIAPI
28QNCPortRead(
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
38VOID
39EFIAPI
40QNCPortWrite (
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
51UINT32
52EFIAPI
53QNCAltPortRead (
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
63VOID
64EFIAPI
65QNCAltPortWrite (
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
76UINT32
77EFIAPI
78QNCPortIORead(
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
88VOID
89EFIAPI
90QNCPortIOWrite (
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
101RETURN_STATUS
102EFIAPI
103QNCMmIoWrite (
104  UINT32             MmIoAddress,
105  QNC_MEM_IO_WIDTH    Width,
106  UINT32             DataNumber,
107  VOID               *pData
108  )
109/*++
110
111Routine 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
114to ensure the expected write is processed and data is flushed into chipset
115
116Arguments:
117
118  Row -- row number to be cleared ( start from 1 )
119
120Returns:
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
173UINT32
174EFIAPI
175QncHsmmcRead (
176  VOID
177  )
178{
179  return QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HSMMC);
180}
181
182VOID
183EFIAPI
184QncHsmmcWrite (
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
230VOID
231EFIAPI
232QncImrWrite (
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
295VOID
296EFIAPI
297QncIClkAndThenOr (
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
316VOID
317EFIAPI
318QncIClkOr (
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