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 Read 8bit character from debug stream.
95
96 Block until character is read.
97
98 @return 8bit character read from debug stream.
99
100 **/
101 CHAR8
102 EFIAPI
PlatformDebugPortGetChar8(VOID)103 PlatformDebugPortGetChar8 (
104 VOID
105 )
106 {
107 CHAR8 Got;
108
109 do {
110 if (SerialPortPoll ()) {
111 if (SerialPortRead ((UINT8 *) &Got, 1) == 1) {
112 break;
113 }
114 }
115 } while (TRUE);
116
117 return Got;
118 }
119
120 /**
121 Clear SPI Protect registers.
122
123 @retval EFI_SUCCESS SPI protect registers cleared.
124 @retval EFI_ACCESS_DENIED Unable to clear SPI protect registers.
125 **/
126
127 EFI_STATUS
128 EFIAPI
PlatformClearSpiProtect(VOID)129 PlatformClearSpiProtect (
130 VOID
131 )
132 {
133 UINT32 PchRootComplexBar;
134
135 PchRootComplexBar = QNC_RCRB_BASE;
136 //
137 // Check if the SPI interface has been locked-down.
138 //
139 if ((MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS) & B_QNC_RCRB_SPIS_SCL) != 0) {
140 return EFI_ACCESS_DENIED;
141 }
142 MmioWrite32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR0, 0);
143 if (MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR0) != 0) {
144 return EFI_ACCESS_DENIED;
145 }
146 MmioWrite32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR1, 0);
147 if (MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR0) != 0) {
148 return EFI_ACCESS_DENIED;
149 }
150 MmioWrite32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR2, 0);
151 if (MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR0) != 0) {
152 return EFI_ACCESS_DENIED;
153 }
154 return EFI_SUCCESS;
155 }
156
157 /**
158 Determine if an SPI address range is protected.
159
160 @param SpiBaseAddress Base of SPI range.
161 @param Length Length of SPI range.
162
163 @retval TRUE Range is protected.
164 @retval FALSE Range is not protected.
165 **/
166 BOOLEAN
167 EFIAPI
PlatformIsSpiRangeProtected(IN CONST UINT32 SpiBaseAddress,IN CONST UINT32 Length)168 PlatformIsSpiRangeProtected (
169 IN CONST UINT32 SpiBaseAddress,
170 IN CONST UINT32 Length
171 )
172 {
173 UINT32 RegVal;
174 UINT32 Offset;
175 UINT32 Limit;
176 UINT32 ProtectedBase;
177 UINT32 ProtectedLimit;
178 UINT32 PchRootComplexBar;
179
180 PchRootComplexBar = QNC_RCRB_BASE;
181
182 if (Length > 0) {
183 Offset = R_QNC_RCRB_SPIPBR0;
184 Limit = SpiBaseAddress + (Length - 1);
185 do {
186 RegVal = MmioRead32 (PchRootComplexBar + Offset);
187 if ((RegVal & B_QNC_RCRB_SPIPBRn_WPE) != 0) {
188 ProtectedBase = (RegVal & 0xfff) << 12;
189 ProtectedLimit = (RegVal & 0x00fff000) + 0xfff;
190 if (SpiBaseAddress >= ProtectedBase && Limit <= ProtectedLimit) {
191 return TRUE;
192 }
193 }
194 if (Offset == R_QNC_RCRB_SPIPBR0) {
195 Offset = R_QNC_RCRB_SPIPBR1;
196 } else if (Offset == R_QNC_RCRB_SPIPBR1) {
197 Offset = R_QNC_RCRB_SPIPBR2;
198 } else {
199 break;
200 }
201 } while (TRUE);
202 }
203 return FALSE;
204 }
205
206 /**
207 Set Legacy GPIO Level
208
209 @param LevelRegOffset GPIO level register Offset from GPIO Base Address.
210 @param GpioNum GPIO bit to change.
211 @param HighLevel If TRUE set GPIO High else Set GPIO low.
212
213 **/
214 VOID
215 EFIAPI
PlatformLegacyGpioSetLevel(IN CONST UINT32 LevelRegOffset,IN CONST UINT32 GpioNum,IN CONST BOOLEAN HighLevel)216 PlatformLegacyGpioSetLevel (
217 IN CONST UINT32 LevelRegOffset,
218 IN CONST UINT32 GpioNum,
219 IN CONST BOOLEAN HighLevel
220 )
221 {
222 UINT32 RegValue;
223 UINT32 GpioBaseAddress;
224 UINT32 GpioNumMask;
225
226 GpioBaseAddress = LpcPciCfg32 (R_QNC_LPC_GBA_BASE) & B_QNC_LPC_GPA_BASE_MASK;
227 ASSERT (GpioBaseAddress > 0);
228
229 RegValue = IoRead32 (GpioBaseAddress + LevelRegOffset);
230 GpioNumMask = (1 << GpioNum);
231 if (HighLevel) {
232 RegValue |= (GpioNumMask);
233 } else {
234 RegValue &= ~(GpioNumMask);
235 }
236 IoWrite32 (GpioBaseAddress + LevelRegOffset, RegValue);
237 }
238
239 /**
240 Get Legacy GPIO Level
241
242 @param LevelRegOffset GPIO level register Offset from GPIO Base Address.
243 @param GpioNum GPIO bit to check.
244
245 @retval TRUE If bit is SET.
246 @retval FALSE If bit is CLEAR.
247
248 **/
249 BOOLEAN
250 EFIAPI
PlatformLegacyGpioGetLevel(IN CONST UINT32 LevelRegOffset,IN CONST UINT32 GpioNum)251 PlatformLegacyGpioGetLevel (
252 IN CONST UINT32 LevelRegOffset,
253 IN CONST UINT32 GpioNum
254 )
255 {
256 UINT32 RegValue;
257 UINT32 GpioBaseAddress;
258 UINT32 GpioNumMask;
259
260 GpioBaseAddress = LpcPciCfg32 (R_QNC_LPC_GBA_BASE) & B_QNC_LPC_GPA_BASE_MASK;
261 RegValue = IoRead32 (GpioBaseAddress + LevelRegOffset);
262 GpioNumMask = (1 << GpioNum);
263 return ((RegValue & GpioNumMask) != 0);
264 }
265
266
267 BOOLEAN
Pcal9555GetPortRegBit(IN CONST UINT32 Pcal9555SlaveAddr,IN CONST UINT32 GpioNum,IN CONST UINT8 RegBase)268 Pcal9555GetPortRegBit (
269 IN CONST UINT32 Pcal9555SlaveAddr,
270 IN CONST UINT32 GpioNum,
271 IN CONST UINT8 RegBase
272 )
273 {
274 EFI_STATUS Status;
275 UINTN ReadLength;
276 UINTN WriteLength;
277 UINT8 Data[2];
278 EFI_I2C_DEVICE_ADDRESS I2cDeviceAddr;
279 EFI_I2C_ADDR_MODE I2cAddrMode;
280 UINT8 *RegValuePtr;
281 UINT8 GpioNumMask;
282 UINT8 SubAddr;
283
284 I2cDeviceAddr.I2CDeviceAddress = (UINTN)Pcal9555SlaveAddr;
285 I2cAddrMode = EfiI2CSevenBitAddrMode;
286
287 if (GpioNum < 8) {
288 SubAddr = RegBase;
289 GpioNumMask = (UINT8)(1 << GpioNum);
290 } else {
291 SubAddr = RegBase + 1;
292 GpioNumMask = (UINT8)(1 << (GpioNum - 8));
293 }
294
295 //
296 // Output port value always at 2nd byte in Data variable.
297 //
298 RegValuePtr = &Data[1];
299
300 //
301 // On read entry sub address at 2nd byte, on read exit output
302 // port value in 2nd byte.
303 //
304 Data[1] = SubAddr;
305 WriteLength = 1;
306 ReadLength = 1;
307 Status = I2cReadMultipleByte (
308 I2cDeviceAddr,
309 I2cAddrMode,
310 &WriteLength,
311 &ReadLength,
312 &Data[1]
313 );
314 ASSERT_EFI_ERROR (Status);
315
316 //
317 // Adjust output port bit given callers request.
318 //
319 return ((*RegValuePtr & GpioNumMask) != 0);
320 }
321
322 VOID
Pcal9555SetPortRegBit(IN CONST UINT32 Pcal9555SlaveAddr,IN CONST UINT32 GpioNum,IN CONST UINT8 RegBase,IN CONST BOOLEAN LogicOne)323 Pcal9555SetPortRegBit (
324 IN CONST UINT32 Pcal9555SlaveAddr,
325 IN CONST UINT32 GpioNum,
326 IN CONST UINT8 RegBase,
327 IN CONST BOOLEAN LogicOne
328 )
329 {
330 EFI_STATUS Status;
331 UINTN ReadLength;
332 UINTN WriteLength;
333 UINT8 Data[2];
334 EFI_I2C_DEVICE_ADDRESS I2cDeviceAddr;
335 EFI_I2C_ADDR_MODE I2cAddrMode;
336 UINT8 *RegValuePtr;
337 UINT8 GpioNumMask;
338 UINT8 SubAddr;
339
340 I2cDeviceAddr.I2CDeviceAddress = (UINTN)Pcal9555SlaveAddr;
341 I2cAddrMode = EfiI2CSevenBitAddrMode;
342
343 if (GpioNum < 8) {
344 SubAddr = RegBase;
345 GpioNumMask = (UINT8)(1 << GpioNum);
346 } else {
347 SubAddr = RegBase + 1;
348 GpioNumMask = (UINT8)(1 << (GpioNum - 8));
349 }
350
351 //
352 // Output port value always at 2nd byte in Data variable.
353 //
354 RegValuePtr = &Data[1];
355
356 //
357 // On read entry sub address at 2nd byte, on read exit output
358 // port value in 2nd byte.
359 //
360 Data[1] = SubAddr;
361 WriteLength = 1;
362 ReadLength = 1;
363 Status = I2cReadMultipleByte (
364 I2cDeviceAddr,
365 I2cAddrMode,
366 &WriteLength,
367 &ReadLength,
368 &Data[1]
369 );
370 ASSERT_EFI_ERROR (Status);
371
372 //
373 // Adjust output port bit given callers request.
374 //
375 if (LogicOne) {
376 *RegValuePtr = *RegValuePtr | GpioNumMask;
377 } else {
378 *RegValuePtr = *RegValuePtr & ~(GpioNumMask);
379 }
380
381 //
382 // Update register. Sub address at 1st byte, value at 2nd byte.
383 //
384 WriteLength = 2;
385 Data[0] = SubAddr;
386 Status = I2cWriteMultipleByte (
387 I2cDeviceAddr,
388 I2cAddrMode,
389 &WriteLength,
390 Data
391 );
392 ASSERT_EFI_ERROR (Status);
393 }
394
395 /**
396 Set the direction of Pcal9555 IO Expander GPIO pin.
397
398 @param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander.
399 @param GpioNum Gpio direction to configure - values 0-7 for Port0
400 and 8-15 for Port1.
401 @param CfgAsInput If TRUE set pin direction as input else set as output.
402
403 **/
404 VOID
405 EFIAPI
PlatformPcal9555GpioSetDir(IN CONST UINT32 Pcal9555SlaveAddr,IN CONST UINT32 GpioNum,IN CONST BOOLEAN CfgAsInput)406 PlatformPcal9555GpioSetDir (
407 IN CONST UINT32 Pcal9555SlaveAddr,
408 IN CONST UINT32 GpioNum,
409 IN CONST BOOLEAN CfgAsInput
410 )
411 {
412 Pcal9555SetPortRegBit (
413 Pcal9555SlaveAddr,
414 GpioNum,
415 PCAL9555_REG_CFG_PORT0,
416 CfgAsInput
417 );
418 }
419
420 /**
421 Set the level of Pcal9555 IO Expander GPIO high or low.
422
423 @param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander.
424 @param GpioNum Gpio to change values 0-7 for Port0 and 8-15
425 for Port1.
426 @param HighLevel If TRUE set pin high else set pin low.
427
428 **/
429 VOID
430 EFIAPI
PlatformPcal9555GpioSetLevel(IN CONST UINT32 Pcal9555SlaveAddr,IN CONST UINT32 GpioNum,IN CONST BOOLEAN HighLevel)431 PlatformPcal9555GpioSetLevel (
432 IN CONST UINT32 Pcal9555SlaveAddr,
433 IN CONST UINT32 GpioNum,
434 IN CONST BOOLEAN HighLevel
435 )
436 {
437 Pcal9555SetPortRegBit (
438 Pcal9555SlaveAddr,
439 GpioNum,
440 PCAL9555_REG_OUT_PORT0,
441 HighLevel
442 );
443 }
444
445 /**
446
447 Enable pull-up/pull-down resistors of Pcal9555 GPIOs.
448
449 @param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander.
450 @param GpioNum Gpio to change values 0-7 for Port0 and 8-15
451 for Port1.
452
453 **/
454 VOID
455 EFIAPI
PlatformPcal9555GpioEnablePull(IN CONST UINT32 Pcal9555SlaveAddr,IN CONST UINT32 GpioNum)456 PlatformPcal9555GpioEnablePull (
457 IN CONST UINT32 Pcal9555SlaveAddr,
458 IN CONST UINT32 GpioNum
459 )
460 {
461 Pcal9555SetPortRegBit (
462 Pcal9555SlaveAddr,
463 GpioNum,
464 PCAL9555_REG_PULL_EN_PORT0,
465 TRUE
466 );
467 }
468
469 /**
470
471 Disable pull-up/pull-down resistors of Pcal9555 GPIOs.
472
473 @param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander.
474 @param GpioNum Gpio to change values 0-7 for Port0 and 8-15
475 for Port1.
476
477 **/
478 VOID
479 EFIAPI
PlatformPcal9555GpioDisablePull(IN CONST UINT32 Pcal9555SlaveAddr,IN CONST UINT32 GpioNum)480 PlatformPcal9555GpioDisablePull (
481 IN CONST UINT32 Pcal9555SlaveAddr,
482 IN CONST UINT32 GpioNum
483 )
484 {
485 Pcal9555SetPortRegBit (
486 Pcal9555SlaveAddr,
487 GpioNum,
488 PCAL9555_REG_PULL_EN_PORT0,
489 FALSE
490 );
491 }
492
493 /**
494
495 Get state of Pcal9555 GPIOs.
496
497 @param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander.
498 @param GpioNum Gpio to change values 0-7 for Port0 and 8-15
499 for Port1.
500
501 @retval TRUE GPIO pin is high
502 @retval FALSE GPIO pin is low
503 **/
504 BOOLEAN
505 EFIAPI
PlatformPcal9555GpioGetState(IN CONST UINT32 Pcal9555SlaveAddr,IN CONST UINT32 GpioNum)506 PlatformPcal9555GpioGetState (
507 IN CONST UINT32 Pcal9555SlaveAddr,
508 IN CONST UINT32 GpioNum
509 )
510 {
511 return Pcal9555GetPortRegBit (Pcal9555SlaveAddr, GpioNum, PCAL9555_REG_IN_PORT0);
512 }
513
514
515