1 /** @file
2 Helper routines with common PEI / DXE implementation.
3
4 Copyright (c) 2013-2016 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 #include "CommonHeader.h"
17 #include <Library/I2cLib.h>
18
19 CHAR16 *mPlatTypeNameTable[] = { EFI_PLATFORM_TYPE_NAME_TABLE_DEFINITION };
20 UINTN mPlatTypeNameTableLen = ((sizeof(mPlatTypeNameTable)) / sizeof (CHAR16 *));
21
22 //
23 // Routines defined in other source modules of this component.
24 //
25
26 //
27 // Routines local to this source module.
28 //
29
30 //
31 // Routines shared with other souce modules in this component.
32 //
33
34 EFI_STATUS
WriteFirstFreeSpiProtect(IN CONST UINT32 PchRootComplexBar,IN CONST UINT32 DirectValue,IN CONST UINT32 BaseAddress,IN CONST UINT32 Length,OUT UINT32 * OffsetPtr)35 WriteFirstFreeSpiProtect (
36 IN CONST UINT32 PchRootComplexBar,
37 IN CONST UINT32 DirectValue,
38 IN CONST UINT32 BaseAddress,
39 IN CONST UINT32 Length,
40 OUT UINT32 *OffsetPtr
41 )
42 {
43 UINT32 RegVal;
44 UINT32 Offset;
45 UINT32 StepLen;
46
47 ASSERT (PchRootComplexBar > 0);
48
49 Offset = 0;
50 if (OffsetPtr != NULL) {
51 *OffsetPtr = Offset;
52 }
53 if (MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR0) == 0) {
54 Offset = R_QNC_RCRB_SPIPBR0;
55 } else {
56 if (MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR1) == 0) {
57 Offset = R_QNC_RCRB_SPIPBR1;
58 } else {
59 if (MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR2) == 0) {
60 Offset = R_QNC_RCRB_SPIPBR2;
61 }
62 }
63 }
64 if (Offset != 0) {
65 if (DirectValue == 0) {
66 StepLen = ALIGN_VALUE (Length,SIZE_4KB); // Bring up to 4K boundary.
67 RegVal = BaseAddress + StepLen - 1;
68 RegVal &= 0x00FFF000; // Set EDS Protected Range Limit (PRL).
69 RegVal |= ((BaseAddress >> 12) & 0xfff); // or in EDS Protected Range Base (PRB).
70 } else {
71 RegVal = DirectValue;
72 }
73 //
74 // Enable protection.
75 //
76 RegVal |= B_QNC_RCRB_SPIPBRn_WPE;
77 MmioWrite32 (PchRootComplexBar + Offset, RegVal);
78 if (RegVal == MmioRead32 (PchRootComplexBar + Offset)) {
79 if (OffsetPtr != NULL) {
80 *OffsetPtr = Offset;
81 }
82 return EFI_SUCCESS;
83 }
84 return EFI_DEVICE_ERROR;
85 }
86 return EFI_NOT_FOUND;
87 }
88
89 //
90 // Routines exported by this component.
91 //
92
93 /**
94 Clear SPI Protect registers.
95
96 @retval EFI_SUCCESS SPI protect registers cleared.
97 @retval EFI_ACCESS_DENIED Unable to clear SPI protect registers.
98 **/
99
100 EFI_STATUS
101 EFIAPI
PlatformClearSpiProtect(VOID)102 PlatformClearSpiProtect (
103 VOID
104 )
105 {
106 UINT32 PchRootComplexBar;
107
108 PchRootComplexBar = QNC_RCRB_BASE;
109 //
110 // Check if the SPI interface has been locked-down.
111 //
112 if ((MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS) & B_QNC_RCRB_SPIS_SCL) != 0) {
113 return EFI_ACCESS_DENIED;
114 }
115 MmioWrite32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR0, 0);
116 if (MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR0) != 0) {
117 return EFI_ACCESS_DENIED;
118 }
119 MmioWrite32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR1, 0);
120 if (MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR0) != 0) {
121 return EFI_ACCESS_DENIED;
122 }
123 MmioWrite32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR2, 0);
124 if (MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR0) != 0) {
125 return EFI_ACCESS_DENIED;
126 }
127 return EFI_SUCCESS;
128 }
129
130 /**
131 Determine if an SPI address range is protected.
132
133 @param SpiBaseAddress Base of SPI range.
134 @param Length Length of SPI range.
135
136 @retval TRUE Range is protected.
137 @retval FALSE Range is not protected.
138 **/
139 BOOLEAN
140 EFIAPI
PlatformIsSpiRangeProtected(IN CONST UINT32 SpiBaseAddress,IN CONST UINT32 Length)141 PlatformIsSpiRangeProtected (
142 IN CONST UINT32 SpiBaseAddress,
143 IN CONST UINT32 Length
144 )
145 {
146 UINT32 RegVal;
147 UINT32 Offset;
148 UINT32 Limit;
149 UINT32 ProtectedBase;
150 UINT32 ProtectedLimit;
151 UINT32 PchRootComplexBar;
152
153 PchRootComplexBar = QNC_RCRB_BASE;
154
155 if (Length > 0) {
156 Offset = R_QNC_RCRB_SPIPBR0;
157 Limit = SpiBaseAddress + (Length - 1);
158 do {
159 RegVal = MmioRead32 (PchRootComplexBar + Offset);
160 if ((RegVal & B_QNC_RCRB_SPIPBRn_WPE) != 0) {
161 ProtectedBase = (RegVal & 0xfff) << 12;
162 ProtectedLimit = (RegVal & 0x00fff000) + 0xfff;
163 if (SpiBaseAddress >= ProtectedBase && Limit <= ProtectedLimit) {
164 return TRUE;
165 }
166 }
167 if (Offset == R_QNC_RCRB_SPIPBR0) {
168 Offset = R_QNC_RCRB_SPIPBR1;
169 } else if (Offset == R_QNC_RCRB_SPIPBR1) {
170 Offset = R_QNC_RCRB_SPIPBR2;
171 } else {
172 break;
173 }
174 } while (TRUE);
175 }
176 return FALSE;
177 }
178
179 /**
180 Set Legacy GPIO Level
181
182 @param LevelRegOffset GPIO level register Offset from GPIO Base Address.
183 @param GpioNum GPIO bit to change.
184 @param HighLevel If TRUE set GPIO High else Set GPIO low.
185
186 **/
187 VOID
188 EFIAPI
PlatformLegacyGpioSetLevel(IN CONST UINT32 LevelRegOffset,IN CONST UINT32 GpioNum,IN CONST BOOLEAN HighLevel)189 PlatformLegacyGpioSetLevel (
190 IN CONST UINT32 LevelRegOffset,
191 IN CONST UINT32 GpioNum,
192 IN CONST BOOLEAN HighLevel
193 )
194 {
195 UINT32 RegValue;
196 UINT32 GpioBaseAddress;
197 UINT32 GpioNumMask;
198
199 GpioBaseAddress = LpcPciCfg32 (R_QNC_LPC_GBA_BASE) & B_QNC_LPC_GPA_BASE_MASK;
200 ASSERT (GpioBaseAddress > 0);
201
202 RegValue = IoRead32 (GpioBaseAddress + LevelRegOffset);
203 GpioNumMask = (1 << GpioNum);
204 if (HighLevel) {
205 RegValue |= (GpioNumMask);
206 } else {
207 RegValue &= ~(GpioNumMask);
208 }
209 IoWrite32 (GpioBaseAddress + LevelRegOffset, RegValue);
210 }
211
212 /**
213 Get Legacy GPIO Level
214
215 @param LevelRegOffset GPIO level register Offset from GPIO Base Address.
216 @param GpioNum GPIO bit to check.
217
218 @retval TRUE If bit is SET.
219 @retval FALSE If bit is CLEAR.
220
221 **/
222 BOOLEAN
223 EFIAPI
PlatformLegacyGpioGetLevel(IN CONST UINT32 LevelRegOffset,IN CONST UINT32 GpioNum)224 PlatformLegacyGpioGetLevel (
225 IN CONST UINT32 LevelRegOffset,
226 IN CONST UINT32 GpioNum
227 )
228 {
229 UINT32 RegValue;
230 UINT32 GpioBaseAddress;
231 UINT32 GpioNumMask;
232
233 GpioBaseAddress = LpcPciCfg32 (R_QNC_LPC_GBA_BASE) & B_QNC_LPC_GPA_BASE_MASK;
234 RegValue = IoRead32 (GpioBaseAddress + LevelRegOffset);
235 GpioNumMask = (1 << GpioNum);
236 return ((RegValue & GpioNumMask) != 0);
237 }
238
239
240 BOOLEAN
Pcal9555GetPortRegBit(IN CONST UINT32 Pcal9555SlaveAddr,IN CONST UINT32 GpioNum,IN CONST UINT8 RegBase)241 Pcal9555GetPortRegBit (
242 IN CONST UINT32 Pcal9555SlaveAddr,
243 IN CONST UINT32 GpioNum,
244 IN CONST UINT8 RegBase
245 )
246 {
247 EFI_STATUS Status;
248 UINTN ReadLength;
249 UINTN WriteLength;
250 UINT8 Data[2];
251 EFI_I2C_DEVICE_ADDRESS I2cDeviceAddr;
252 EFI_I2C_ADDR_MODE I2cAddrMode;
253 UINT8 *RegValuePtr;
254 UINT8 GpioNumMask;
255 UINT8 SubAddr;
256
257 I2cDeviceAddr.I2CDeviceAddress = (UINTN)Pcal9555SlaveAddr;
258 I2cAddrMode = EfiI2CSevenBitAddrMode;
259
260 if (GpioNum < 8) {
261 SubAddr = RegBase;
262 GpioNumMask = (UINT8)(1 << GpioNum);
263 } else {
264 SubAddr = RegBase + 1;
265 GpioNumMask = (UINT8)(1 << (GpioNum - 8));
266 }
267
268 //
269 // Output port value always at 2nd byte in Data variable.
270 //
271 RegValuePtr = &Data[1];
272
273 //
274 // On read entry sub address at 2nd byte, on read exit output
275 // port value in 2nd byte.
276 //
277 Data[1] = SubAddr;
278 WriteLength = 1;
279 ReadLength = 1;
280 Status = I2cReadMultipleByte (
281 I2cDeviceAddr,
282 I2cAddrMode,
283 &WriteLength,
284 &ReadLength,
285 &Data[1]
286 );
287 ASSERT_EFI_ERROR (Status);
288
289 //
290 // Adjust output port bit given callers request.
291 //
292 return ((*RegValuePtr & GpioNumMask) != 0);
293 }
294
295 VOID
Pcal9555SetPortRegBit(IN CONST UINT32 Pcal9555SlaveAddr,IN CONST UINT32 GpioNum,IN CONST UINT8 RegBase,IN CONST BOOLEAN LogicOne)296 Pcal9555SetPortRegBit (
297 IN CONST UINT32 Pcal9555SlaveAddr,
298 IN CONST UINT32 GpioNum,
299 IN CONST UINT8 RegBase,
300 IN CONST BOOLEAN LogicOne
301 )
302 {
303 EFI_STATUS Status;
304 UINTN ReadLength;
305 UINTN WriteLength;
306 UINT8 Data[2];
307 EFI_I2C_DEVICE_ADDRESS I2cDeviceAddr;
308 EFI_I2C_ADDR_MODE I2cAddrMode;
309 UINT8 *RegValuePtr;
310 UINT8 GpioNumMask;
311 UINT8 SubAddr;
312
313 I2cDeviceAddr.I2CDeviceAddress = (UINTN)Pcal9555SlaveAddr;
314 I2cAddrMode = EfiI2CSevenBitAddrMode;
315
316 if (GpioNum < 8) {
317 SubAddr = RegBase;
318 GpioNumMask = (UINT8)(1 << GpioNum);
319 } else {
320 SubAddr = RegBase + 1;
321 GpioNumMask = (UINT8)(1 << (GpioNum - 8));
322 }
323
324 //
325 // Output port value always at 2nd byte in Data variable.
326 //
327 RegValuePtr = &Data[1];
328
329 //
330 // On read entry sub address at 2nd byte, on read exit output
331 // port value in 2nd byte.
332 //
333 Data[1] = SubAddr;
334 WriteLength = 1;
335 ReadLength = 1;
336 Status = I2cReadMultipleByte (
337 I2cDeviceAddr,
338 I2cAddrMode,
339 &WriteLength,
340 &ReadLength,
341 &Data[1]
342 );
343 ASSERT_EFI_ERROR (Status);
344
345 //
346 // Adjust output port bit given callers request.
347 //
348 if (LogicOne) {
349 *RegValuePtr = *RegValuePtr | GpioNumMask;
350 } else {
351 *RegValuePtr = *RegValuePtr & ~(GpioNumMask);
352 }
353
354 //
355 // Update register. Sub address at 1st byte, value at 2nd byte.
356 //
357 WriteLength = 2;
358 Data[0] = SubAddr;
359 Status = I2cWriteMultipleByte (
360 I2cDeviceAddr,
361 I2cAddrMode,
362 &WriteLength,
363 Data
364 );
365 ASSERT_EFI_ERROR (Status);
366 }
367
368 /**
369 Set the direction of Pcal9555 IO Expander GPIO pin.
370
371 @param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander.
372 @param GpioNum Gpio direction to configure - values 0-7 for Port0
373 and 8-15 for Port1.
374 @param CfgAsInput If TRUE set pin direction as input else set as output.
375
376 **/
377 VOID
378 EFIAPI
PlatformPcal9555GpioSetDir(IN CONST UINT32 Pcal9555SlaveAddr,IN CONST UINT32 GpioNum,IN CONST BOOLEAN CfgAsInput)379 PlatformPcal9555GpioSetDir (
380 IN CONST UINT32 Pcal9555SlaveAddr,
381 IN CONST UINT32 GpioNum,
382 IN CONST BOOLEAN CfgAsInput
383 )
384 {
385 Pcal9555SetPortRegBit (
386 Pcal9555SlaveAddr,
387 GpioNum,
388 PCAL9555_REG_CFG_PORT0,
389 CfgAsInput
390 );
391 }
392
393 /**
394 Set the level of Pcal9555 IO Expander GPIO high or low.
395
396 @param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander.
397 @param GpioNum Gpio to change values 0-7 for Port0 and 8-15
398 for Port1.
399 @param HighLevel If TRUE set pin high else set pin low.
400
401 **/
402 VOID
403 EFIAPI
PlatformPcal9555GpioSetLevel(IN CONST UINT32 Pcal9555SlaveAddr,IN CONST UINT32 GpioNum,IN CONST BOOLEAN HighLevel)404 PlatformPcal9555GpioSetLevel (
405 IN CONST UINT32 Pcal9555SlaveAddr,
406 IN CONST UINT32 GpioNum,
407 IN CONST BOOLEAN HighLevel
408 )
409 {
410 Pcal9555SetPortRegBit (
411 Pcal9555SlaveAddr,
412 GpioNum,
413 PCAL9555_REG_OUT_PORT0,
414 HighLevel
415 );
416 }
417
418 /**
419
420 Enable pull-up/pull-down resistors of Pcal9555 GPIOs.
421
422 @param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander.
423 @param GpioNum Gpio to change values 0-7 for Port0 and 8-15
424 for Port1.
425
426 **/
427 VOID
428 EFIAPI
PlatformPcal9555GpioEnablePull(IN CONST UINT32 Pcal9555SlaveAddr,IN CONST UINT32 GpioNum)429 PlatformPcal9555GpioEnablePull (
430 IN CONST UINT32 Pcal9555SlaveAddr,
431 IN CONST UINT32 GpioNum
432 )
433 {
434 Pcal9555SetPortRegBit (
435 Pcal9555SlaveAddr,
436 GpioNum,
437 PCAL9555_REG_PULL_EN_PORT0,
438 TRUE
439 );
440 }
441
442 /**
443
444 Disable pull-up/pull-down resistors of Pcal9555 GPIOs.
445
446 @param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander.
447 @param GpioNum Gpio to change values 0-7 for Port0 and 8-15
448 for Port1.
449
450 **/
451 VOID
452 EFIAPI
PlatformPcal9555GpioDisablePull(IN CONST UINT32 Pcal9555SlaveAddr,IN CONST UINT32 GpioNum)453 PlatformPcal9555GpioDisablePull (
454 IN CONST UINT32 Pcal9555SlaveAddr,
455 IN CONST UINT32 GpioNum
456 )
457 {
458 Pcal9555SetPortRegBit (
459 Pcal9555SlaveAddr,
460 GpioNum,
461 PCAL9555_REG_PULL_EN_PORT0,
462 FALSE
463 );
464 }
465
466 /**
467
468 Get state of Pcal9555 GPIOs.
469
470 @param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander.
471 @param GpioNum Gpio to change values 0-7 for Port0 and 8-15
472 for Port1.
473
474 @retval TRUE GPIO pin is high
475 @retval FALSE GPIO pin is low
476 **/
477 BOOLEAN
478 EFIAPI
PlatformPcal9555GpioGetState(IN CONST UINT32 Pcal9555SlaveAddr,IN CONST UINT32 GpioNum)479 PlatformPcal9555GpioGetState (
480 IN CONST UINT32 Pcal9555SlaveAddr,
481 IN CONST UINT32 GpioNum
482 )
483 {
484 return Pcal9555GetPortRegBit (Pcal9555SlaveAddr, GpioNum, PCAL9555_REG_IN_PORT0);
485 }
486
487
488