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