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