1 /** @file
2   This file contains routines for GPIO
3 
4   Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
5 
6   SPDX-License-Identifier: BSD-2-Clause-Patent
7 **/
8 
9 #include "GpioLibrary.h"
10 #include <Register/PchRegsPcr.h>
11 
12 /**
13   This procedure will check if GpioGroup argument is correct and
14   supplied DW reg number can be used for this group to access DW registers.
15   Function will check below conditions:
16    - Valid GpioGroup
17    - DwNum is has valid value for this group
18 
19   @param[in] Group        GPIO group
20   @param[in] DwNum        Register number for current group (parameter applicable in accessing whole register).
21                           For group which has less then 32 pads per group DwNum must be 0.
22 
23   @retval TRUE             DW Reg number and GpioGroup is valid
24   @retval FALSE            DW Reg number and GpioGroup is invalid
25 **/
26 STATIC
27 BOOLEAN
GpioIsGroupAndDwNumValid(IN GPIO_GROUP Group,IN UINT32 DwNum)28 GpioIsGroupAndDwNumValid (
29   IN GPIO_GROUP             Group,
30   IN UINT32                 DwNum
31   )
32 {
33   UINT32                 GroupIndex;
34   CONST GPIO_GROUP_INFO  *GpioGroupInfo;
35   UINT32                 GpioGroupInfoLength;
36 
37   GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
38 
39   GroupIndex = GpioGetGroupIndexFromGroup (Group);
40 
41   if ((Group < GpioGetLowestGroup ()) || (Group > GpioGetHighestGroup ()) || (GroupIndex >= GpioGroupInfoLength)) {
42     DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group argument (%d) is not within range of possible groups for this PCH\n", GroupIndex));
43     goto Error;
44   }
45 
46   //
47   // Check if DwNum argument does not exceed number of DWord registers
48   // resulting from available pads for certain group
49   //
50   if (DwNum > GPIO_GET_DW_NUM (GpioGroupInfo[GroupIndex].PadPerGroup - 1)){
51     goto Error;
52   }
53 
54   return TRUE;
55 Error:
56   ASSERT (FALSE);
57   return FALSE;
58 }
59 
60 //
61 // Possible registers to be accessed using GpioReadReg()/GpioWriteReg() functions
62 //
63 typedef enum {
64   GpioHostOwnershipRegister = 0,
65   GpioGpeEnableRegister,
66   GpioGpeStatusRegister,
67   GpioSmiEnableRegister,
68   GpioSmiStatusRegister,
69   GpioNmiEnableRegister,
70   GpioPadConfigLockRegister,
71   GpioPadLockOutputRegister
72 } GPIO_REG;
73 
74 /**
75   This procedure will read GPIO register
76 
77   @param[in] RegType              GPIO register type
78   @param[in] Group                GPIO group
79   @param[in] DwNum                Register number for current group (parameter applicable in accessing whole register).
80                                   For group which has less then 32 pads per group DwNum must be 0.
81   @param[out] ReadVal             Read data
82 **/
83 STATIC
84 VOID
GpioReadReg(IN GPIO_REG RegType,IN GPIO_GROUP Group,IN UINT32 DwNum,OUT UINT32 * ReadVal)85 GpioReadReg (
86   IN GPIO_REG               RegType,
87   IN GPIO_GROUP             Group,
88   IN UINT32                 DwNum,
89   OUT UINT32                *ReadVal
90   )
91 {
92   UINT32                 RegOffset;
93   UINT32                 GroupIndex;
94   CONST GPIO_GROUP_INFO  *GpioGroupInfo;
95   UINT32                 GpioGroupInfoLength;
96 
97   RegOffset = NO_REGISTER_FOR_PROPERTY;
98   GroupIndex = GpioGetGroupIndexFromGroup (Group);
99 
100   GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
101 
102   switch (RegType) {
103     case GpioHostOwnershipRegister:
104       RegOffset = GpioGroupInfo[GroupIndex].HostOwnOffset;
105       break;
106     case GpioGpeEnableRegister:
107       RegOffset = GpioGroupInfo[GroupIndex].GpiGpeEnOffset;
108       break;
109     case GpioGpeStatusRegister:
110       RegOffset = GpioGroupInfo[GroupIndex].GpiGpeStsOffset;
111       break;
112     case GpioSmiEnableRegister:
113       RegOffset = GpioGroupInfo[GroupIndex].SmiEnOffset;
114       break;
115     case GpioSmiStatusRegister:
116       RegOffset = GpioGroupInfo[GroupIndex].SmiStsOffset;
117       break;
118     case GpioNmiEnableRegister:
119       RegOffset = GpioGroupInfo[GroupIndex].NmiEnOffset;
120       break;
121     case GpioPadConfigLockRegister:
122       RegOffset = GpioGroupInfo[GroupIndex].PadCfgLockOffset;
123       break;
124     case GpioPadLockOutputRegister:
125       RegOffset = GpioGroupInfo[GroupIndex].PadCfgLockTxOffset;
126       break;
127     default:
128       break;
129   }
130 
131   //
132   // Check if selected register exists
133   //
134   if (RegOffset == NO_REGISTER_FOR_PROPERTY) {
135     *ReadVal = 0;
136     ASSERT (FALSE);
137     return;
138   }
139 
140   //
141   // If there are more then 32 pads per group then certain
142   // group information would be split into more then one DWord register.
143   //
144   if ((RegType == GpioPadConfigLockRegister) || (RegType == GpioPadLockOutputRegister)) {
145     //
146     // PadConfigLock and OutputLock registers when used for group containing more than 32 pads
147     // are not placed in a continuous way, e.g:
148     // 0x0 - PadConfigLock_DW0
149     // 0x4 - OutputLock_DW0
150     // 0x8 - PadConfigLock_DW1
151     // 0xC - OutputLock_DW1
152     //
153     RegOffset += DwNum * 0x8;
154   } else {
155     RegOffset += DwNum * 0x4;
156   }
157 
158   *ReadVal = MmioRead32 (PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, RegOffset));
159 }
160 
161 /**
162   This function determines if the group is SMI capable.
163 
164   @param[in] Group                GPIO group
165   @param[in] DwNum                Register number for current group (parameter applicable in accessing whole register).
166                                   For group which has less then 32 pads per group DwNum must be 0.
167   @retval TRUE                    The function completed successfully
168   @retval FALSE                   Setting SMI for a group is not supported
169 **/
170 STATIC
171 BOOLEAN
GpioIsSmiSupportedByGroupDw(IN GPIO_GROUP Group,IN UINT32 Dw)172 GpioIsSmiSupportedByGroupDw (
173   IN GPIO_GROUP             Group,
174   IN UINT32                 Dw
175   )
176 {
177   UINT32                 RegOffset;
178   UINT32                 GroupIndex;
179   CONST GPIO_GROUP_INFO  *GpioGroupInfo;
180   UINT32                 GpioGroupInfoLength;
181 
182   GroupIndex = GpioGetGroupIndexFromGroup (Group);
183 
184   GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
185 
186   RegOffset = GpioGroupInfo[GroupIndex].SmiStsOffset;
187 
188   //
189   // Check if selected register exists
190   //
191   if (RegOffset == NO_REGISTER_FOR_PROPERTY) {
192     return FALSE;
193   }
194 
195   return TRUE;
196 }
197 
198 /**
199   This function determines if the group is NMI capable.
200 
201   @param[in] Group                GPIO group
202   @param[in] DwNum                Register number for current group (parameter applicable in accessing whole register).
203                                   For group which has less then 32 pads per group DwNum must be 0.
204   @retval TRUE                    The function completed successfully
205   @retval FALSE                   Setting NMI for a group is not supported
206 **/
207 STATIC
208 BOOLEAN
GpioIsNmiSupportedByGroupDw(IN GPIO_GROUP Group,IN UINT32 Dw)209 GpioIsNmiSupportedByGroupDw (
210   IN GPIO_GROUP             Group,
211   IN UINT32                 Dw
212   )
213 {
214   UINT32                 RegOffset;
215   UINT32                 GroupIndex;
216   CONST GPIO_GROUP_INFO  *GpioGroupInfo;
217   UINT32                 GpioGroupInfoLength;
218 
219   GroupIndex = GpioGetGroupIndexFromGroup (Group);
220 
221   GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
222 
223   RegOffset = GpioGroupInfo[GroupIndex].NmiEnOffset;
224 
225   //
226   // Check if selected register exists
227   //
228   if (RegOffset == NO_REGISTER_FOR_PROPERTY) {
229     return FALSE;
230   }
231 
232   return TRUE;
233 }
234 
235 /**
236   This procedure will write GPIO register
237 
238   @param[in] RegType              GPIO register type
239   @param[in] Group                GPIO group
240   @param[in] DwNum                Register number for current group (parameter applicable in accessing whole register).
241                                   For group which has less then 32 pads per group DwNum must be 0.
242   @param[in] RegAndMask           Mask which will be AND'ed with register value
243   @param[in] RegOrMask            Mask which will be OR'ed with register value
244 **/
245 STATIC
246 VOID
GpioWriteReg(IN GPIO_REG RegType,IN GPIO_GROUP Group,IN UINT32 DwNum,IN UINT32 RegAndMask,IN UINT32 RegOrMask)247 GpioWriteReg (
248   IN GPIO_REG               RegType,
249   IN GPIO_GROUP             Group,
250   IN UINT32                 DwNum,
251   IN UINT32                 RegAndMask,
252   IN UINT32                 RegOrMask
253   )
254 {
255   UINT32                 RegOffset;
256   UINT32                 GroupIndex;
257   CONST GPIO_GROUP_INFO  *GpioGroupInfo;
258   UINT32                 GpioGroupInfoLength;
259   UINT32                 PadCfgLock;
260   BOOLEAN                Lockable;
261   EFI_STATUS             Status;
262 
263   Lockable = FALSE;
264   PadCfgLock = 0;
265   RegOffset = NO_REGISTER_FOR_PROPERTY;
266   GroupIndex = GpioGetGroupIndexFromGroup (Group);
267 
268   GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
269 
270   switch (RegType) {
271     case GpioHostOwnershipRegister:
272       RegOffset = GpioGroupInfo[GroupIndex].HostOwnOffset;
273       break;
274     case GpioGpeEnableRegister:
275       RegOffset = GpioGroupInfo[GroupIndex].GpiGpeEnOffset;
276       Lockable = TRUE;
277       break;
278     case GpioGpeStatusRegister:
279       RegOffset = GpioGroupInfo[GroupIndex].GpiGpeStsOffset;
280       break;
281     case GpioSmiEnableRegister:
282       RegOffset = GpioGroupInfo[GroupIndex].SmiEnOffset;
283       Lockable = TRUE;
284       break;
285     case GpioSmiStatusRegister:
286       RegOffset = GpioGroupInfo[GroupIndex].SmiStsOffset;
287       break;
288     case GpioNmiEnableRegister:
289       RegOffset = GpioGroupInfo[GroupIndex].NmiEnOffset;
290       Lockable = TRUE;
291       break;
292     case GpioPadConfigLockRegister:
293     case GpioPadLockOutputRegister:
294     default:
295       break;
296   }
297 
298   //
299   // Check if selected register exists
300   //
301   if (RegOffset == NO_REGISTER_FOR_PROPERTY) {
302     return;
303   }
304 
305   if (Lockable) {
306     GpioGetPadCfgLockForGroupDw (Group, DwNum, &PadCfgLock);
307     if (PadCfgLock) {
308       //
309       // Check if for pads which are going to be reconfigured lock is set.
310       //
311       if ((~RegAndMask | RegOrMask) & PadCfgLock) {
312         //
313         // Unlock all pads for this Group DW reg for simplicity
314         // even if not all of those pads will have their settings reprogrammed
315         //
316         Status = GpioUnlockPadCfgForGroupDw (Group, DwNum, PadCfgLock);
317         if (EFI_ERROR (Status)) {
318           ASSERT (FALSE);
319           return;
320         }
321       } else {
322         //
323         // No need to perform an unlock as pads which are going to be reconfigured
324         // are not in locked state
325         //
326         PadCfgLock = 0;
327       }
328     }
329   }
330 
331   //
332   // If there are more then 32 pads per group then certain
333   // group information would be split into more then one DWord register.
334   //
335   RegOffset += DwNum * 0x4;
336 
337   MmioAndThenOr32 (
338     PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, RegOffset),
339     RegAndMask,
340     RegOrMask
341     );
342 
343   if (Lockable && PadCfgLock) {
344     //
345     // Lock previously unlocked pads
346     //
347     Status = GpioLockPadCfgForGroupDw (Group, DwNum, PadCfgLock);
348     if (EFI_ERROR (Status)) {
349       ASSERT (FALSE);
350       return;
351     }
352   }
353 }
354 
355 /**
356   This procedure will write GPIO Lock/LockTx register using SBI.
357 
358   @param[in] RegType              GPIO register (Lock or LockTx)
359   @param[in] Group                GPIO group number
360   @param[in] DwNum                Register number for current group.
361                                   For group which has less then 32 pads per group DwNum must be 0.
362   @param[in] LockRegAndMask       Mask which will be AND'ed with Lock register value
363   @param[in] LockRegOrMask        Mask which will be Or'ed with Lock register value
364 
365   @retval EFI_SUCCESS             The function completed successfully
366   @retval EFI_UNSUPPORTED         Feature is not supported for this group or pad
367 **/
368 STATIC
369 EFI_STATUS
GpioWriteLockReg(IN GPIO_REG RegType,IN GPIO_GROUP Group,IN UINT32 DwNum,IN UINT32 LockRegAndMask,IN UINT32 LockRegOrMask)370 GpioWriteLockReg (
371   IN GPIO_REG                  RegType,
372   IN GPIO_GROUP                Group,
373   IN UINT32                    DwNum,
374   IN UINT32                    LockRegAndMask,
375   IN UINT32                    LockRegOrMask
376   )
377 {
378   UINT8                  Response;
379   CONST GPIO_GROUP_INFO  *GpioGroupInfo;
380   UINT32                 GpioGroupInfoLength;
381   UINT32                 RegOffset;
382   UINT32                 OldLockVal;
383   UINT32                 NewLockVal;
384   UINT32                 GroupIndex;
385   EFI_STATUS             Status;
386 
387   OldLockVal = 0;
388   NewLockVal = 0;
389 
390   RegOffset = NO_REGISTER_FOR_PROPERTY;
391   GroupIndex = GpioGetGroupIndexFromGroup (Group);
392 
393   GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
394 
395   switch (RegType) {
396     case GpioPadConfigLockRegister:
397       RegOffset = GpioGroupInfo[GroupIndex].PadCfgLockOffset;
398       GpioGetPadCfgLockForGroupDw (Group, DwNum, &OldLockVal);
399       break;
400     case GpioPadLockOutputRegister:
401       RegOffset = GpioGroupInfo[GroupIndex].PadCfgLockTxOffset;
402       GpioGetPadCfgLockTxForGroupDw (Group, DwNum, &OldLockVal);
403       break;
404     default:
405       break;
406   }
407 
408   //
409   // Check if selected register exists
410   //
411   if (RegOffset == NO_REGISTER_FOR_PROPERTY) {
412     return EFI_UNSUPPORTED;
413   }
414 
415   //
416   // If there are more then 32 pads per group then certain
417   // group information would be split into more then one DWord register.
418   // PadConfigLock and OutputLock registers when used for group containing more than 32 pads
419   // are not placed in a continuous way, e.g:
420   // 0x0 - PadConfigLock_DW0
421   // 0x4 - OutputLock_DW0
422   // 0x8 - PadConfigLock_DW1
423   // 0xC - OutputLock_DW1
424   //
425   RegOffset += DwNum *0x8;
426 
427   NewLockVal = (OldLockVal & LockRegAndMask) | LockRegOrMask;
428 
429   Status = PchSbiExecutionEx (
430              GpioGroupInfo[GroupIndex].Community,
431              RegOffset,
432              GpioLockUnlock,
433              FALSE,
434              0x000F,
435              0x0000,
436              0x0000,
437              &NewLockVal,
438              &Response
439              );
440   ASSERT_EFI_ERROR (Status);
441   return Status;
442 }
443 
444 /**
445   This internal procedure will calculate GPIO_RESET_CONFIG value  (new type)
446   based on provided PadRstCfg for a specific GPIO Pad.
447 
448   @param[in]  GpioPad               GPIO Pad
449   @param[in]  PadRstCfg             GPIO PadRstCfg value
450 
451   @retval GpioResetConfig           GPIO Reset configuration (new type)
452 **/
453 GPIO_RESET_CONFIG
GpioResetConfigFromPadRstCfg(IN GPIO_PAD GpioPad,IN UINT32 PadRstCfg)454 GpioResetConfigFromPadRstCfg (
455   IN  GPIO_PAD           GpioPad,
456   IN  UINT32             PadRstCfg
457   )
458 {
459   GPIO_GROUP           Group;
460 
461   static GPIO_RESET_CONFIG  GppPadRstCfgToGpioResetConfigMap[] = {
462                               GpioResumeReset,
463                               GpioHostDeepReset,
464                               GpioPlatformReset};
465   static GPIO_RESET_CONFIG  GpdPadRstCfgToGpioResetConfigMap[] = {
466                               GpioDswReset,
467                               GpioHostDeepReset,
468                               GpioPlatformReset,
469                               GpioResumeReset};
470 
471   Group = GpioGetGroupFromGpioPad (GpioPad);
472 
473   if (GpioIsDswGroup (Group) && PadRstCfg < 4) {
474     return GpdPadRstCfgToGpioResetConfigMap[PadRstCfg];
475   } else if (PadRstCfg < 3) {
476     return GppPadRstCfgToGpioResetConfigMap[PadRstCfg];
477   } else {
478     ASSERT (FALSE);
479     return GpioResetDefault;
480   }
481 }
482 
483 /**
484   This internal procedure will calculate PadRstCfg register value based
485   on provided GPIO Reset configuration for a certain pad.
486 
487   @param[in]  GpioPad                   GPIO Pad
488   @param[in]  GpioResetConfig           GPIO Reset configuration
489   @param[out] PadRstCfg                 GPIO PadRstCfg value
490 
491   @retval EFI_SUCCESS                   The function completed successfully
492   @retval EFI_INVALID_PARAMETER         Invalid configuration
493 **/
494 EFI_STATUS
GpioPadRstCfgFromResetConfig(IN GPIO_PAD GpioPad,IN GPIO_RESET_CONFIG GpioResetConfig,OUT UINT32 * PadRstCfg)495 GpioPadRstCfgFromResetConfig (
496   IN  GPIO_PAD           GpioPad,
497   IN  GPIO_RESET_CONFIG  GpioResetConfig,
498   OUT UINT32             *PadRstCfg
499   )
500 {
501   GPIO_GROUP           Group;
502 
503   Group = GpioGetGroupFromGpioPad (GpioPad);
504 
505   switch (GpioResetConfig) {
506     case GpioResetDefault:
507       *PadRstCfg = 0x0;
508       break;
509     case GpioHostDeepReset:
510       *PadRstCfg = V_GPIO_PCR_RST_CONF_DEEP_RST;
511       break;
512     case GpioPlatformReset:
513       *PadRstCfg = V_GPIO_PCR_RST_CONF_GPIO_RST;
514       break;
515     case GpioResumeReset:
516       if (GpioIsDswGroup (Group)) {
517         *PadRstCfg = V_GPIO_PCR_RST_CONF_RESUME_RST;
518       } else {
519         *PadRstCfg = V_GPIO_PCR_RST_CONF_POW_GOOD;
520       }
521       break;
522     case GpioDswReset:
523       if (GpioIsDswGroup (Group)) {
524         *PadRstCfg = V_GPIO_PCR_RST_CONF_POW_GOOD;
525       } else {
526         DEBUG ((DEBUG_ERROR, "GPIO ERROR: Only GPD group pads can use GpioDswReset: %a\n", GpioName (GpioPad)));
527         goto Error;
528       }
529       break;
530     default:
531       goto Error;
532   }
533 
534   return EFI_SUCCESS;
535 Error:
536   ASSERT (FALSE);
537   return EFI_INVALID_PARAMETER;
538 }
539 
540 /**
541   This internal procedure will get GPIO_CONFIG data from PADCFG registers value
542 
543   @param[in]  GpioPad                   GPIO Pad
544   @param[in]  PadCfgDwReg               PADCFG DWx register values
545   @param[out] GpioData                  GPIO Configuration data
546 
547   @retval Status
548 **/
549 STATIC
550 VOID
GpioConfigFromPadCfgRegValue(IN GPIO_PAD GpioPad,IN CONST UINT32 * PadCfgDwReg,OUT GPIO_CONFIG * GpioConfig)551 GpioConfigFromPadCfgRegValue (
552   IN GPIO_PAD      GpioPad,
553   IN CONST UINT32  *PadCfgDwReg,
554   OUT GPIO_CONFIG  *GpioConfig
555   )
556 {
557   UINT32               PadRstCfg;
558 
559   //
560   // Get Reset Type (PadRstCfg)
561   //
562   PadRstCfg = (PadCfgDwReg[0] & B_GPIO_PCR_RST_CONF) >> N_GPIO_PCR_RST_CONF;
563 
564   GpioConfig->PowerConfig = GpioResetConfigFromPadRstCfg (
565                               GpioPad,
566                               PadRstCfg
567                               );
568 
569   //
570   // Get how interrupt is triggered (RxEvCfg)
571   //
572   GpioConfig->InterruptConfig = ((PadCfgDwReg[0] & B_GPIO_PCR_RX_LVL_EDG) >> (N_GPIO_PCR_RX_LVL_EDG - (N_GPIO_INT_CONFIG_INT_TYPE_BIT_POS + 1))) | (0x1 << N_GPIO_INT_CONFIG_INT_TYPE_BIT_POS);
573 
574   //
575   // Get interrupt generation (GPIRoutIOxAPIC/SCI/SMI/NMI)
576   //
577   GpioConfig->InterruptConfig |= ((PadCfgDwReg[0] & (B_GPIO_PCR_RX_NMI_ROUTE | B_GPIO_PCR_RX_SCI_ROUTE | B_GPIO_PCR_RX_SMI_ROUTE | B_GPIO_PCR_RX_APIC_ROUTE)) >> (N_GPIO_PCR_RX_NMI_ROUTE - (N_GPIO_INT_CONFIG_INT_SOURCE_BIT_POS + 1))) | (0x1 << N_GPIO_INT_CONFIG_INT_SOURCE_BIT_POS);
578 
579   //
580   // Get GPIO direction (GPIORxDis and GPIOTxDis)
581   //
582   GpioConfig->Direction = ((PadCfgDwReg[0] & (B_GPIO_PCR_RXDIS | B_GPIO_PCR_TXDIS)) >> (N_GPIO_PCR_TXDIS - (N_GPIO_DIRECTION_DIR_BIT_POS + 1))) | (0x1 << N_GPIO_DIRECTION_DIR_BIT_POS);
583 
584   //
585   // Get GPIO input inversion (RXINV)
586   // (Only meaningful if input enabled)
587   //
588   if((PadCfgDwReg[0] & B_GPIO_PCR_RXDIS) == 0) {
589     GpioConfig->Direction |= ((PadCfgDwReg[0] & B_GPIO_PCR_RXINV) >> (N_GPIO_PCR_RXINV - (N_GPIO_DIRECTION_INV_BIT_POS + 1))) | (0x1 << N_GPIO_DIRECTION_INV_BIT_POS);
590   }
591 
592   //
593   // Get GPIO output state (GPIOTxState)
594   //
595   GpioConfig->OutputState = ((PadCfgDwReg[0] & B_GPIO_PCR_TX_STATE) << (N_GPIO_PCR_TX_STATE + (N_GPIO_OUTPUT_BIT_POS + 1))) | (0x1 << N_GPIO_OUTPUT_BIT_POS);
596 
597   //
598   // Configure GPIO RX raw override to '1' (RXRAW1)
599   //
600   GpioConfig->OtherSettings = ((PadCfgDwReg[0] & B_GPIO_PCR_RX_RAW1) >> (N_GPIO_PCR_RX_RAW1 - (N_GPIO_OTHER_CONFIG_RXRAW_BIT_POS + 1))) | (0x1 << N_GPIO_OTHER_CONFIG_RXRAW_BIT_POS);
601 
602   //
603   // Get GPIO Pad Mode (PMode)
604   //
605   GpioConfig->PadMode = ((PadCfgDwReg[0] & B_GPIO_PCR_PAD_MODE) >> (N_GPIO_PCR_PAD_MODE - (N_GPIO_PAD_MODE_BIT_POS + 1))) | (0x1 << N_GPIO_PAD_MODE_BIT_POS);
606 
607   //
608   // Get GPIO termination (Term)
609   //
610   GpioConfig->ElectricalConfig = ((PadCfgDwReg[1] & B_GPIO_PCR_TERM) >> (N_GPIO_PCR_TERM - (N_GPIO_ELECTRICAL_CONFIG_TERMINATION_BIT_POS + 1))) | (0x1 << N_GPIO_ELECTRICAL_CONFIG_TERMINATION_BIT_POS);
611 }
612 
613 /**
614   This procedure will read multiple GPIO settings
615 
616   @param[in]  GpioPad                   GPIO Pad
617   @param[out] GpioData                  GPIO data structure
618 
619   @retval EFI_SUCCESS                   The function completed successfully
620   @retval EFI_INVALID_PARAMETER         Invalid group or pad number
621 **/
622 EFI_STATUS
GpioGetPadConfig(IN GPIO_PAD GpioPad,OUT GPIO_CONFIG * GpioData)623 GpioGetPadConfig (
624   IN  GPIO_PAD               GpioPad,
625   OUT GPIO_CONFIG            *GpioData
626   )
627 {
628   UINT32               PadCfgDwReg[GPIO_PADCFG_DW_REG_NUMBER];
629   UINT32               RegVal;
630   GPIO_GROUP           Group;
631   UINT32               PadNumber;
632   UINT32               PadBitPosition;
633 
634   Group = GpioGetGroupFromGpioPad (GpioPad);
635   PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
636   PadBitPosition = GPIO_GET_PAD_POSITION (PadNumber);
637 
638   if (!GpioIsPadValid (GpioPad)) {
639     return EFI_UNSUPPORTED;
640   }
641 
642   if (!GpioIsPadHostOwned (GpioPad)) {
643     return EFI_UNSUPPORTED;
644   }
645 
646   //
647   // Read PADCFG DW0 register
648   //
649   PadCfgDwReg[0] = GpioReadPadCfgReg (GpioPad, 0);
650 
651   //
652   // Read PADCFG DW1 register
653   //
654   PadCfgDwReg[1] = GpioReadPadCfgReg (GpioPad, 1);
655 
656   //
657   // Read PADCFG DW2 register
658   //
659   PadCfgDwReg[2] = GpioReadPadCfgReg (GpioPad, 2);
660 
661   GpioConfigFromPadCfgRegValue (
662     GpioPad,
663     PadCfgDwReg,
664     GpioData
665     );
666 
667   //
668   // Read HOSTSW_OWN registers
669   //
670   GpioReadReg (
671     GpioHostOwnershipRegister,
672     Group,
673     GPIO_GET_DW_NUM (PadNumber),
674     &RegVal
675     );
676 
677   //
678   // Get Host Software Ownership
679   //
680   GpioData->HostSoftPadOwn = (((RegVal >> PadBitPosition) & 0x1) << (N_GPIO_HOSTSW_OWN_BIT_POS + 1)) | (0x1 << N_GPIO_HOSTSW_OWN_BIT_POS);
681 
682   //
683   // Read PADCFGLOCK register
684   //
685   GpioReadReg (
686     GpioPadConfigLockRegister,
687     Group,
688     GPIO_GET_DW_NUM (PadNumber),
689     &RegVal
690     );
691 
692   //
693   // Get Pad Configuration Lock state
694   //
695   GpioData->LockConfig = ((!((RegVal >> PadBitPosition) & 0x1)) << 1) | 0x1;
696 
697   //
698   // Read PADCFGLOCKTX register
699   //
700   GpioReadReg (
701     GpioPadLockOutputRegister,
702     Group,
703     GPIO_GET_DW_NUM (PadNumber),
704     &RegVal
705     );
706 
707   //
708   // Get Pad Configuration Lock Tx state
709   //
710   GpioData->LockConfig |= ((!((RegVal >> PadBitPosition) & 0x1)) << 2) | 0x1;
711 
712   return EFI_SUCCESS;
713 }
714 
715 /**
716   This procedure will calculate PADCFG register value based on GpioConfig data
717 
718   @param[in]  GpioPad                   GPIO Pad
719   @param[in]  GpioConfig                GPIO Configuration data
720   @param[out] PadCfgDwReg               PADCFG DWx register value
721   @param[out] PadCfgDwRegMask           Mask with PADCFG DWx register bits to be modified
722 **/
723 VOID
GpioPadCfgRegValueFromGpioConfig(IN GPIO_PAD GpioPad,IN CONST GPIO_CONFIG * GpioConfig,OUT UINT32 * PadCfgDwReg,OUT UINT32 * PadCfgDwRegMask)724 GpioPadCfgRegValueFromGpioConfig (
725   IN  GPIO_PAD           GpioPad,
726   IN  CONST GPIO_CONFIG  *GpioConfig,
727   OUT UINT32             *PadCfgDwReg,
728   OUT UINT32             *PadCfgDwRegMask
729   )
730 {
731   UINT32               PadRstCfg;
732   EFI_STATUS           Status;
733 
734   //
735   // Configure Reset Type (PadRstCfg)
736   // Reset configuration depends on group type.
737   // This field requires support for new and deprecated settings.
738   //
739   Status = GpioPadRstCfgFromResetConfig (
740              GpioPad,
741              GpioConfig->PowerConfig,
742              &PadRstCfg
743              );
744   if (EFI_ERROR (Status)) {
745     return;
746   }
747 
748   PadCfgDwRegMask[0] |= ((((GpioConfig->PowerConfig & B_GPIO_RESET_CONFIG_RESET_MASK) >> N_GPIO_RESET_CONFIG_RESET_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_GPIO_PCR_RST_CONF);
749   PadCfgDwReg[0] |= PadRstCfg << N_GPIO_PCR_RST_CONF;
750 
751   //
752   // Configure how interrupt is triggered (RxEvCfg)
753   //
754   PadCfgDwRegMask[0] |= ((((GpioConfig->InterruptConfig & B_GPIO_INT_CONFIG_INT_TYPE_MASK) >> N_GPIO_INT_CONFIG_INT_TYPE_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_GPIO_PCR_RX_LVL_EDG);
755   PadCfgDwReg[0] |= (((GpioConfig->InterruptConfig & B_GPIO_INT_CONFIG_INT_TYPE_MASK) >> (N_GPIO_INT_CONFIG_INT_TYPE_BIT_POS + 1)) << N_GPIO_PCR_RX_LVL_EDG);
756 
757   //
758   // Configure interrupt generation (GPIRoutIOxAPIC/SCI/SMI/NMI)
759   //
760   PadCfgDwRegMask[0] |= ((((GpioConfig->InterruptConfig & B_GPIO_INT_CONFIG_INT_SOURCE_MASK) >> N_GPIO_INT_CONFIG_INT_SOURCE_BIT_POS) == GpioHardwareDefault)  ? 0x0 : (B_GPIO_PCR_RX_NMI_ROUTE | B_GPIO_PCR_RX_SCI_ROUTE | B_GPIO_PCR_RX_SMI_ROUTE | B_GPIO_PCR_RX_APIC_ROUTE));
761   PadCfgDwReg[0] |= (((GpioConfig->InterruptConfig & B_GPIO_INT_CONFIG_INT_SOURCE_MASK) >> (N_GPIO_INT_CONFIG_INT_SOURCE_BIT_POS + 1)) << N_GPIO_PCR_RX_NMI_ROUTE);
762 
763   //
764   // Configure GPIO direction (GPIORxDis and GPIOTxDis)
765   //
766   PadCfgDwRegMask[0] |= ((((GpioConfig->Direction & B_GPIO_DIRECTION_DIR_MASK) >> N_GPIO_DIRECTION_DIR_BIT_POS) == GpioHardwareDefault) ? 0x0 : (B_GPIO_PCR_RXDIS | B_GPIO_PCR_TXDIS));
767   PadCfgDwReg[0] |= (((GpioConfig->Direction & B_GPIO_DIRECTION_DIR_MASK) >> (N_GPIO_DIRECTION_DIR_BIT_POS + 1)) << N_GPIO_PCR_TXDIS);
768 
769   //
770   // Configure GPIO input inversion (RXINV)
771   //
772   PadCfgDwRegMask[0] |= ((((GpioConfig->Direction & B_GPIO_DIRECTION_INV_MASK) >> N_GPIO_DIRECTION_INV_BIT_POS) == GpioHardwareDefault) ?  0x0 : B_GPIO_PCR_RXINV);
773   PadCfgDwReg[0] |= (((GpioConfig->Direction & B_GPIO_DIRECTION_INV_MASK) >> (N_GPIO_DIRECTION_INV_BIT_POS + 1)) << N_GPIO_PCR_RXINV);
774 
775   //
776   // Configure GPIO output state (GPIOTxState)
777   //
778   PadCfgDwRegMask[0] |= ((((GpioConfig->OutputState & B_GPIO_OUTPUT_MASK) >> N_GPIO_OUTPUT_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_GPIO_PCR_TX_STATE);
779   PadCfgDwReg[0] |= (((GpioConfig->OutputState & B_GPIO_OUTPUT_MASK) >> (N_GPIO_OUTPUT_BIT_POS + 1)) << N_GPIO_PCR_TX_STATE);
780 
781   //
782   // Configure GPIO RX raw override to '1' (RXRAW1)
783   //
784   PadCfgDwRegMask[0] |= ((((GpioConfig->OtherSettings & B_GPIO_OTHER_CONFIG_RXRAW_MASK) >> N_GPIO_OTHER_CONFIG_RXRAW_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_GPIO_PCR_RX_RAW1);
785   PadCfgDwReg[0] |= (((GpioConfig->OtherSettings & B_GPIO_OTHER_CONFIG_RXRAW_MASK) >> (N_GPIO_OTHER_CONFIG_RXRAW_BIT_POS + 1)) << N_GPIO_PCR_RX_RAW1);
786 
787   //
788   // Configure GPIO Pad Mode (PMode)
789   //
790   PadCfgDwRegMask[0] |= ((((GpioConfig->PadMode & B_GPIO_PAD_MODE_MASK) >> N_GPIO_PAD_MODE_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_GPIO_PCR_PAD_MODE);
791   PadCfgDwReg[0] |= (((GpioConfig->PadMode & B_GPIO_PAD_MODE_MASK) >> (N_GPIO_PAD_MODE_BIT_POS + 1)) << N_GPIO_PCR_PAD_MODE);
792 
793   //
794   // Configure GPIO termination (Term)
795   //
796   PadCfgDwRegMask[1] |= ((((GpioConfig->ElectricalConfig & B_GPIO_ELECTRICAL_CONFIG_TERMINATION_MASK) >> N_GPIO_ELECTRICAL_CONFIG_TERMINATION_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_GPIO_PCR_TERM);
797   PadCfgDwReg[1] |= (((GpioConfig->ElectricalConfig & B_GPIO_ELECTRICAL_CONFIG_TERMINATION_MASK) >> (N_GPIO_ELECTRICAL_CONFIG_TERMINATION_BIT_POS + 1)) << N_GPIO_PCR_TERM);
798 }
799 
800 /**
801   This procedure will configure multiple GPIO settings
802 
803   @param[in] GpioPad                    GPIO Pad
804   @param[in] GpioData                   GPIO data structure
805 
806   @retval EFI_SUCCESS                   The function completed successfully
807   @retval EFI_INVALID_PARAMETER         Invalid group or pad number
808 **/
809 EFI_STATUS
GpioSetPadConfig(IN GPIO_PAD GpioPad,IN GPIO_CONFIG * GpioData)810 GpioSetPadConfig (
811   IN GPIO_PAD                  GpioPad,
812   IN GPIO_CONFIG               *GpioData
813   )
814 {
815   EFI_STATUS           Status;
816   UINT32               PadCfgDwReg[GPIO_PADCFG_DW_REG_NUMBER];
817   UINT32               PadCfgDwRegMask[GPIO_PADCFG_DW_REG_NUMBER];
818   UINT32               HostSoftOwnReg;
819   UINT32               HostSoftOwnRegMask;
820   UINT32               GpiGpeEnReg;
821   UINT32               GpiGpeEnRegMask;
822   UINT32               GpiNmiEnReg;
823   UINT32               GpiNmiEnRegMask;
824   UINT32               GpiSmiEnReg;
825   UINT32               GpiSmiEnRegMask;
826   GPIO_GROUP           Group;
827   UINT32               GroupIndex;
828   UINT32               PadNumber;
829   UINT32               PadBitPosition;
830   UINT32               DwNum;
831   GPIO_LOCK_CONFIG     LockConfig;
832 
833   Status = EFI_SUCCESS;
834   ZeroMem (PadCfgDwReg, sizeof (PadCfgDwReg));
835   ZeroMem (PadCfgDwRegMask, sizeof (PadCfgDwRegMask));
836 
837   Group = GpioGetGroupFromGpioPad (GpioPad);
838   GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
839   PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
840   PadBitPosition = GPIO_GET_PAD_POSITION (PadNumber);
841   DwNum = GPIO_GET_DW_NUM (PadNumber);
842 
843   if (!GpioIsPadValid (GpioPad)) {
844     return EFI_UNSUPPORTED;
845   }
846 
847   if (!GpioIsPadHostOwned (GpioPad)) {
848     return EFI_UNSUPPORTED;
849   }
850 
851   //
852   // Check if Pad enabled for SCI is to be in unlocked state
853   //
854   if (((GpioData->InterruptConfig & GpioIntSci) == GpioIntSci) &&
855       ((GpioData->LockConfig & B_GPIO_LOCK_CONFIG_PAD_CONF_LOCK_MASK) != GpioPadConfigUnlock)){
856     DEBUG ((DEBUG_ERROR, "GPIO ERROR: %a for SCI is not unlocked!\n", GpioName (GpioPad)));
857     return EFI_INVALID_PARAMETER;
858   }
859 
860   //
861   // Get GPIO PADCFG register value from GPIO config data
862   //
863   GpioPadCfgRegValueFromGpioConfig (
864     GpioPad,
865     GpioData,
866     PadCfgDwReg,
867     PadCfgDwRegMask
868     );
869 
870   //
871   // Write PADCFG DW0 register
872   //
873   GpioWritePadCfgReg (
874     GpioPad,
875     0,
876     ~PadCfgDwRegMask[0],
877     PadCfgDwReg[0]
878     );
879 
880   //
881   // Write PADCFG DW1 register
882   //
883   GpioWritePadCfgReg (
884     GpioPad,
885     1,
886     ~PadCfgDwRegMask[1],
887     PadCfgDwReg[1]
888     );
889 
890   //
891   // Write PADCFG DW2 register
892   //
893   GpioWritePadCfgReg (
894     GpioPad,
895     2,
896     ~PadCfgDwRegMask[2],
897     PadCfgDwReg[2]
898     );
899 
900   //
901   // Update value to be programmed in HOSTSW_OWN register
902   //
903   if ((GpioData->InterruptConfig & GpioIntSmi) == GpioIntSmi) {
904     HostSoftOwnRegMask = 1 << PadBitPosition;
905     HostSoftOwnReg = 1 << PadBitPosition;
906   } else {
907     HostSoftOwnRegMask = (GpioData->HostSoftPadOwn & 0x1) << PadBitPosition;
908     HostSoftOwnReg = (GpioData->HostSoftPadOwn >> 0x1) << PadBitPosition;
909   }
910 
911   //
912   // Write HOSTSW_OWN registers
913   //
914   GpioWriteReg (
915     GpioHostOwnershipRegister,
916     Group,
917     DwNum,
918     ~HostSoftOwnRegMask,
919     HostSoftOwnReg
920     );
921 
922   //
923   // Update value to be programmed in GPI_GPE_EN register
924   //
925   GpiGpeEnRegMask = (GpioData->InterruptConfig & 0x1) << PadBitPosition;
926   GpiGpeEnReg = ((GpioData->InterruptConfig & GpioIntSci) >> 3) << PadBitPosition;
927 
928   //
929   // Write GPI_GPE_EN registers
930   //
931   GpioWriteReg (
932     GpioGpeEnableRegister,
933     Group,
934     DwNum,
935     ~GpiGpeEnRegMask,
936     GpiGpeEnReg
937     );
938 
939   //
940   // Update value to be programmed in GPI_NMI_EN register
941   //
942   GpiNmiEnRegMask = (GpioData->InterruptConfig & 0x1) << PadBitPosition;
943   GpiNmiEnReg = ((GpioData->InterruptConfig & GpioIntNmi) >> 1) << PadBitPosition;
944 
945   if (GpioIsNmiSupportedByGroupDw (Group, DwNum)) {
946     GpioWriteReg (
947       GpioNmiEnableRegister,
948       Group,
949       DwNum,
950       ~GpiNmiEnRegMask,
951       GpiNmiEnReg
952       );
953   } else {
954     if (GpiNmiEnReg == 0) {
955       //
956       // Not all GPIO have NMI capabilities. Since we always try to program this register,
957       // even when not enabling NMI for a pad so do not report such access as an error
958       //
959       Status = EFI_SUCCESS;
960     } else {
961       DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group %a has no pads supporting NMI\n", GpioGetGroupName (GroupIndex)));
962       ASSERT (FALSE);
963       return EFI_UNSUPPORTED;
964     }
965   }
966 
967   //
968   // Update value to be programmed in GPI_SMI_EN register
969   //
970   GpiSmiEnRegMask = (GpioData->InterruptConfig & 0x1) << PadBitPosition;
971   GpiSmiEnReg = ((GpioData->InterruptConfig & GpioIntSmi) >> 2) << PadBitPosition;
972 
973   if (GpioIsSmiSupportedByGroupDw (Group, DwNum)) {
974     GpioWriteReg (
975       GpioSmiEnableRegister,
976       Group,
977       DwNum,
978       ~GpiSmiEnRegMask,
979       GpiSmiEnReg
980       );
981   } else {
982     if (GpiSmiEnReg == 0) {
983       //
984       // Not all GPIO have SMI capabilities. Since we always try to program this register,
985       // even when not enabling SMI for a pad so do not report such access as an error
986       //
987       Status = EFI_SUCCESS;
988     } else {
989       DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group %a has no pads supporting SMI\n", GpioGetGroupName (GroupIndex)));
990       ASSERT (FALSE);
991       return EFI_UNSUPPORTED;
992     }
993   }
994 
995   //
996   // Store unlock data
997   //
998   if (GpioData->LockConfig != GpioLockDefault) {
999     LockConfig = GpioData->LockConfig & B_GPIO_LOCK_CONFIG_PAD_CONF_LOCK_MASK;
1000     //
1001     // If pad in GpioMode is an output default action should be to leave output unlocked
1002     //
1003     if ((GpioData->PadMode == GpioPadModeGpio) &&
1004       (GpioData->Direction == GpioDirOut) &&
1005       ((GpioData->LockConfig & B_GPIO_LOCK_CONFIG_OUTPUT_LOCK_MASK) == GpioLockDefault)) {
1006       LockConfig |= GpioOutputStateUnlock;
1007     } else {
1008       LockConfig |= GpioData->LockConfig & B_GPIO_LOCK_CONFIG_OUTPUT_LOCK_MASK;
1009     }
1010     Status = GpioStoreUnlockData (GpioPad, LockConfig);
1011   }
1012 
1013   return Status;
1014 }
1015 
1016 /**
1017   This procedure will set GPIO output level
1018 
1019   @param[in] GpioPad              GPIO pad
1020   @param[in] Value                Output value
1021                                   0: OutputLow, 1: OutputHigh
1022 
1023   @retval EFI_SUCCESS             The function completed successfully
1024   @retval EFI_INVALID_PARAMETER   Invalid GpioPad
1025 **/
1026 EFI_STATUS
GpioSetOutputValue(IN GPIO_PAD GpioPad,IN UINT32 Value)1027 GpioSetOutputValue (
1028   IN GPIO_PAD                  GpioPad,
1029   IN UINT32                    Value
1030   )
1031 {
1032   if (Value > 1) {
1033     return EFI_INVALID_PARAMETER;
1034   }
1035 
1036   if (!GpioIsPadValid (GpioPad)) {
1037     return EFI_INVALID_PARAMETER;
1038   }
1039 
1040   if (!GpioIsPadHostOwned (GpioPad)) {
1041     return EFI_UNSUPPORTED;
1042   }
1043 
1044   GpioWritePadCfgReg (
1045     GpioPad,
1046     0,
1047     (UINT32)~B_GPIO_PCR_TX_STATE,
1048     Value << N_GPIO_PCR_TX_STATE
1049     );
1050 
1051   return EFI_SUCCESS;
1052 }
1053 
1054 /**
1055   This procedure will get GPIO output level
1056 
1057   @param[in]  GpioPad             GPIO pad
1058   @param[out] OutputVal           GPIO Output value
1059                                   0: OutputLow, 1: OutputHigh
1060 
1061   @retval EFI_SUCCESS             The function completed successfully
1062   @retval EFI_INVALID_PARAMETER   Invalid GpioPad
1063 **/
1064 EFI_STATUS
GpioGetOutputValue(IN GPIO_PAD GpioPad,OUT UINT32 * OutputVal)1065 GpioGetOutputValue (
1066   IN GPIO_PAD                  GpioPad,
1067   OUT UINT32                   *OutputVal
1068   )
1069 {
1070   UINT32      PadCfgReg;
1071 
1072   if (!GpioIsPadValid (GpioPad)) {
1073     return EFI_INVALID_PARAMETER;
1074   }
1075 
1076   if (!GpioIsPadHostOwned (GpioPad)) {
1077     return EFI_UNSUPPORTED;
1078   }
1079 
1080   PadCfgReg = GpioReadPadCfgReg (GpioPad, 0);
1081 
1082   *OutputVal = (PadCfgReg & B_GPIO_PCR_TX_STATE) >> N_GPIO_PCR_TX_STATE;
1083 
1084   return EFI_SUCCESS;
1085 }
1086 
1087 /**
1088   This procedure will get GPIO input level
1089 
1090   @param[in] GpioPad              GPIO pad
1091   @param[out] InputVal            GPIO Input value
1092                                   0: InputLow, 1: InpuHigh
1093 
1094   @retval EFI_SUCCESS             The function completed successfully
1095   @retval EFI_INVALID_PARAMETER   Invalid GpioPad
1096 **/
1097 EFI_STATUS
GpioGetInputValue(IN GPIO_PAD GpioPad,OUT UINT32 * InputVal)1098 GpioGetInputValue (
1099   IN GPIO_PAD                  GpioPad,
1100   OUT UINT32                   *InputVal
1101   )
1102 {
1103   UINT32      PadCfgReg;
1104 
1105   if (!GpioIsPadValid (GpioPad)) {
1106     return EFI_INVALID_PARAMETER;
1107   }
1108 
1109   if (!GpioIsPadHostOwned (GpioPad)) {
1110     return EFI_UNSUPPORTED;
1111   }
1112 
1113   PadCfgReg = GpioReadPadCfgReg (GpioPad, 0);
1114 
1115   *InputVal = (PadCfgReg & B_GPIO_PCR_RX_STATE) >> N_GPIO_PCR_RX_STATE;
1116 
1117   return EFI_SUCCESS;
1118 }
1119 
1120 /**
1121   This procedure will get GPIO IOxAPIC interrupt number
1122 
1123   @param[in]  GpioPad             GPIO pad
1124   @param[out] IrqNum              IRQ number
1125 
1126   @retval EFI_SUCCESS             The function completed successfully
1127   @retval EFI_INVALID_PARAMETER   Invalid GpioPad
1128 **/
1129 EFI_STATUS
GpioGetPadIoApicIrqNumber(IN GPIO_PAD GpioPad,OUT UINT32 * IrqNum)1130 GpioGetPadIoApicIrqNumber (
1131   IN GPIO_PAD                  GpioPad,
1132   OUT UINT32                   *IrqNum
1133   )
1134 {
1135   UINT32      PadCfgReg;
1136 
1137   if (!GpioIsPadValid (GpioPad)) {
1138     return EFI_INVALID_PARAMETER;
1139   }
1140 
1141   if (!GpioIsPadHostOwned (GpioPad)) {
1142     return EFI_UNSUPPORTED;
1143   }
1144 
1145   PadCfgReg = GpioReadPadCfgReg (GpioPad, 1);
1146 
1147   *IrqNum = (PadCfgReg & B_GPIO_PCR_INTSEL) >> N_GPIO_PCR_INTSEL;
1148 
1149   return EFI_SUCCESS;
1150 }
1151 
1152 /**
1153   This procedure will configure GPIO input inversion
1154 
1155   @param[in] GpioPad              GPIO pad
1156   @param[in] Value                Value for GPIO input inversion
1157                                   0: No input inversion, 1: Invert input
1158 
1159   @retval EFI_SUCCESS             The function completed successfully
1160   @retval EFI_INVALID_PARAMETER   Invalid GpioPad
1161 **/
1162 EFI_STATUS
GpioSetInputInversion(IN GPIO_PAD GpioPad,IN UINT32 Value)1163 GpioSetInputInversion (
1164   IN GPIO_PAD                  GpioPad,
1165   IN UINT32                    Value
1166   )
1167 {
1168   if (Value > 1) {
1169     return EFI_INVALID_PARAMETER;
1170   }
1171 
1172   if (!GpioIsPadValid (GpioPad)) {
1173     return EFI_INVALID_PARAMETER;
1174   }
1175 
1176   if (!GpioIsPadHostOwned (GpioPad)) {
1177     return EFI_UNSUPPORTED;
1178   }
1179 
1180   GpioWritePadCfgReg (
1181     GpioPad,
1182     0,
1183     (UINT32)~B_GPIO_PCR_RXINV,
1184     Value << N_GPIO_PCR_RXINV
1185     );
1186 
1187   return EFI_SUCCESS;
1188 }
1189 
1190 /**
1191   This procedure will get GPIO pad input inversion value
1192 
1193   @param[in]  GpioPad             GPIO pad
1194   @param[out] InvertState         GPIO inversion state
1195                                   0: No input inversion, 1: Inverted input
1196 
1197   @retval EFI_SUCCESS             The function completed successfully
1198   @retval EFI_INVALID_PARAMETER   Invalid GpioPad
1199 **/
1200 EFI_STATUS
GpioGetInputInversion(IN GPIO_PAD GpioPad,OUT UINT32 * InvertState)1201 GpioGetInputInversion (
1202   IN  GPIO_PAD                 GpioPad,
1203   OUT UINT32                   *InvertState
1204   )
1205 {
1206   UINT32      PadCfgReg;
1207 
1208   if (!GpioIsPadValid (GpioPad)) {
1209     return EFI_INVALID_PARAMETER;
1210   }
1211 
1212   if (!GpioIsPadHostOwned (GpioPad)) {
1213     return EFI_UNSUPPORTED;
1214   }
1215 
1216   PadCfgReg = GpioReadPadCfgReg (GpioPad, 0);
1217 
1218   *InvertState = (PadCfgReg & B_GPIO_PCR_RXINV) >> N_GPIO_PCR_RXINV;
1219   return EFI_SUCCESS;
1220 }
1221 
1222 /**
1223   This procedure will set GPIO interrupt settings
1224 
1225   @param[in] GpioPad              GPIO pad
1226   @param[in] Value                Value of Level/Edge
1227                                   use GPIO_INT_CONFIG as argument
1228 
1229   @retval EFI_SUCCESS             The function completed successfully
1230   @retval EFI_INVALID_PARAMETER   Invalid GpioPad
1231 **/
1232 EFI_STATUS
GpioSetPadInterruptConfig(IN GPIO_PAD GpioPad,IN GPIO_INT_CONFIG Value)1233 GpioSetPadInterruptConfig (
1234   IN GPIO_PAD                 GpioPad,
1235   IN GPIO_INT_CONFIG          Value
1236   )
1237 {
1238   EFI_STATUS  Status;
1239   BOOLEAN     IsNmiSupported;
1240   UINT32      RxLvlEdgeValue;
1241   UINT32      IntRouteValue;
1242   UINT32      PadNumber;
1243   UINT32      GpeEnable;
1244   UINT32      NmiEnable;
1245 
1246   if (!GpioIsPadValid (GpioPad)) {
1247     return EFI_INVALID_PARAMETER;
1248   }
1249 
1250   if (!GpioIsPadHostOwned (GpioPad)) {
1251     return EFI_UNSUPPORTED;
1252   }
1253 
1254   Status = EFI_SUCCESS;
1255 
1256   if (((Value & B_GPIO_INT_CONFIG_INT_TYPE_MASK) >> N_GPIO_INT_CONFIG_INT_TYPE_BIT_POS) != GpioHardwareDefault) {
1257     RxLvlEdgeValue = ((Value & B_GPIO_INT_CONFIG_INT_TYPE_MASK) >> (N_GPIO_INT_CONFIG_INT_TYPE_BIT_POS + 1)) << N_GPIO_PCR_RX_LVL_EDG;
1258 
1259     GpioWritePadCfgReg (
1260       GpioPad,
1261       0,
1262       (UINT32)~B_GPIO_PCR_RX_LVL_EDG,
1263       RxLvlEdgeValue
1264       );
1265   }
1266 
1267   if (((Value & B_GPIO_INT_CONFIG_INT_SOURCE_MASK) >> N_GPIO_INT_CONFIG_INT_SOURCE_BIT_POS) != GpioHardwareDefault) {
1268 
1269     IntRouteValue = ((Value & B_GPIO_INT_CONFIG_INT_SOURCE_MASK) >> (N_GPIO_INT_CONFIG_INT_SOURCE_BIT_POS + 1)) << N_GPIO_PCR_RX_NMI_ROUTE;
1270 
1271     GpioWritePadCfgReg (
1272       GpioPad,
1273       0,
1274       (UINT32)~(B_GPIO_PCR_RX_NMI_ROUTE | B_GPIO_PCR_RX_SCI_ROUTE | B_GPIO_PCR_RX_SMI_ROUTE | B_GPIO_PCR_RX_APIC_ROUTE),
1275       IntRouteValue
1276       );
1277 
1278     if ((Value & GpioIntSci) == GpioIntSci) {
1279       GpeEnable = 0x1;
1280     } else {
1281       GpeEnable = 0x0;
1282     }
1283 
1284     PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
1285 
1286     GpioWriteReg (
1287       GpioGpeEnableRegister,
1288       GpioGetGroupFromGpioPad (GpioPad),
1289       GPIO_GET_DW_NUM (PadNumber),
1290       ~(1 << GPIO_GET_PAD_POSITION (PadNumber)),
1291       GpeEnable << GPIO_GET_PAD_POSITION (PadNumber)
1292       );
1293 
1294     if ((Value & GpioIntNmi) == GpioIntNmi) {
1295       NmiEnable = 0x1;
1296     } else {
1297       NmiEnable = 0x0;
1298     }
1299 
1300     IsNmiSupported = GpioIsNmiSupportedByGroupDw (
1301                        GpioGetGroupFromGpioPad (GpioPad),
1302                        GPIO_GET_DW_NUM (PadNumber)
1303                        );
1304     if (IsNmiSupported) {
1305       GpioWriteReg (
1306         GpioNmiEnableRegister,
1307         GpioGetGroupFromGpioPad (GpioPad),
1308         GPIO_GET_DW_NUM (PadNumber),
1309         ~(1 << GPIO_GET_PAD_POSITION (PadNumber)),
1310         NmiEnable << GPIO_GET_PAD_POSITION (PadNumber)
1311         );
1312     } else {
1313       if (NmiEnable == 0) {
1314         //
1315         // Not all GPIO have NMI capabilities. Since we always try to program this register,
1316         // even when not enabling NMI for a pad so do not report such access as an error
1317         //
1318         return EFI_SUCCESS;
1319       } else {
1320         DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group %a has no pads supporting NMI\n", GpioGetGroupName (GpioGetGroupIndexFromGpioPad (GpioPad))));
1321         ASSERT (FALSE);
1322       }
1323     }
1324   }
1325 
1326   return Status;
1327 }
1328 
1329 /**
1330   This procedure will set GPIO electrical settings
1331 
1332   @param[in] GpioPad              GPIO pad
1333   @param[in] Value                Value of termination
1334                                   use GPIO_ELECTRICAL_CONFIG as argument
1335 
1336   @retval EFI_SUCCESS             The function completed successfully
1337   @retval EFI_INVALID_PARAMETER   Invalid GpioPad
1338 **/
1339 EFI_STATUS
GpioSetPadElectricalConfig(IN GPIO_PAD GpioPad,IN GPIO_ELECTRICAL_CONFIG Value)1340 GpioSetPadElectricalConfig (
1341   IN GPIO_PAD                  GpioPad,
1342   IN GPIO_ELECTRICAL_CONFIG    Value
1343   )
1344 {
1345   UINT32      TermValue;
1346 
1347   if (!GpioIsPadValid (GpioPad)) {
1348     return EFI_INVALID_PARAMETER;
1349   }
1350 
1351   if (!GpioIsPadHostOwned (GpioPad)) {
1352     return EFI_UNSUPPORTED;
1353   }
1354 
1355   if (((Value & B_GPIO_ELECTRICAL_CONFIG_TERMINATION_MASK) >> N_GPIO_ELECTRICAL_CONFIG_TERMINATION_BIT_POS) != GpioHardwareDefault) {
1356     TermValue = ((Value & B_GPIO_ELECTRICAL_CONFIG_TERMINATION_MASK) >> (N_GPIO_ELECTRICAL_CONFIG_TERMINATION_BIT_POS + 1)) << N_GPIO_PCR_TERM;
1357 
1358     GpioWritePadCfgReg (
1359       GpioPad,
1360       1,
1361       (UINT32)~B_GPIO_PCR_TERM,
1362       TermValue
1363       );
1364   }
1365 
1366   return EFI_SUCCESS;
1367 }
1368 
1369 /**
1370   This procedure will set GPIO Reset settings
1371 
1372   @param[in] GpioPad              GPIO pad
1373   @param[in] Value                Value for Pad Reset Configuration
1374                                   use GPIO_RESET_CONFIG as argument
1375 
1376   @retval EFI_SUCCESS             The function completed successfully
1377   @retval EFI_INVALID_PARAMETER   Invalid GpioPad
1378 **/
1379 EFI_STATUS
GpioSetPadResetConfig(IN GPIO_PAD GpioPad,IN GPIO_RESET_CONFIG Value)1380 GpioSetPadResetConfig (
1381   IN GPIO_PAD                  GpioPad,
1382   IN GPIO_RESET_CONFIG         Value
1383   )
1384 {
1385   UINT32      PadRstCfg;
1386   EFI_STATUS  Status;
1387 
1388   if (!GpioIsPadValid (GpioPad)) {
1389     return EFI_INVALID_PARAMETER;
1390   }
1391 
1392   if (!GpioIsPadHostOwned (GpioPad)) {
1393     return EFI_UNSUPPORTED;
1394   }
1395 
1396   if (((Value & B_GPIO_RESET_CONFIG_RESET_MASK) >> N_GPIO_RESET_CONFIG_RESET_BIT_POS) != GpioHardwareDefault) {
1397 
1398     //
1399     // Reset configuration depends on group type.
1400     // This field requires support for new and deprecated settings.
1401     //
1402     Status = GpioPadRstCfgFromResetConfig (
1403                GpioPad,
1404                Value,
1405                &PadRstCfg
1406                );
1407     if (EFI_ERROR (Status)) {
1408       return Status;
1409     }
1410     GpioWritePadCfgReg (
1411       GpioPad,
1412       0,
1413       (UINT32)~B_GPIO_PCR_RST_CONF,
1414       PadRstCfg << N_GPIO_PCR_RST_CONF
1415       );
1416   }
1417   return EFI_SUCCESS;
1418 }
1419 
1420 /**
1421   This procedure will get GPIO Reset settings
1422 
1423   @param[in] GpioPad              GPIO pad
1424   @param[in] Value                Value of Pad Reset Configuration
1425                                   based on GPIO_RESET_CONFIG
1426 
1427   @retval EFI_SUCCESS             The function completed successfully
1428   @retval EFI_INVALID_PARAMETER   Invalid GpioPad
1429 **/
1430 EFI_STATUS
GpioGetPadResetConfig(IN GPIO_PAD GpioPad,IN GPIO_RESET_CONFIG * Value)1431 GpioGetPadResetConfig (
1432   IN GPIO_PAD                  GpioPad,
1433   IN GPIO_RESET_CONFIG         *Value
1434   )
1435 {
1436   UINT32      PadRstCfg;
1437   UINT32      PadCfgDw0Reg;
1438 
1439   if (!GpioIsPadValid (GpioPad)) {
1440     return EFI_INVALID_PARAMETER;
1441   }
1442 
1443   if (!GpioIsPadHostOwned (GpioPad)) {
1444     return EFI_UNSUPPORTED;
1445   }
1446 
1447   PadCfgDw0Reg = GpioReadPadCfgReg (GpioPad, 0);
1448 
1449   //
1450   // Get Reset Type (PadRstCfg)
1451   //
1452   PadRstCfg = (PadCfgDw0Reg & B_GPIO_PCR_RST_CONF) >> N_GPIO_PCR_RST_CONF;
1453 
1454   *Value = GpioResetConfigFromPadRstCfg (
1455              GpioPad,
1456              PadRstCfg
1457              );
1458 
1459   return EFI_SUCCESS;
1460 }
1461 
1462 /**
1463   This procedure will get GPIO Host Software Pad Ownership for certain group
1464 
1465   @param[in]  Group               GPIO group
1466   @param[in]  DwNum               Host Ownership register number for current group.
1467                                   For group which has less then 32 pads per group DwNum must be 0.
1468   @param[out] HostSwRegVal        Value of Host Software Pad Ownership register
1469                                   Bit position - PadNumber
1470                                   Bit value - 0: ACPI Mode, 1: GPIO Driver mode
1471 
1472   @retval EFI_SUCCESS             The function completed successfully
1473   @retval EFI_INVALID_PARAMETER   Invalid group or DwNum parameter number
1474 **/
1475 EFI_STATUS
GpioGetHostSwOwnershipForGroupDw(IN GPIO_GROUP Group,IN UINT32 DwNum,OUT UINT32 * HostSwRegVal)1476 GpioGetHostSwOwnershipForGroupDw (
1477   IN  GPIO_GROUP                  Group,
1478   IN  UINT32                      DwNum,
1479   OUT UINT32                      *HostSwRegVal
1480   )
1481 {
1482   if (!GpioIsGroupAndDwNumValid (Group, DwNum)) {
1483     return EFI_INVALID_PARAMETER;
1484   }
1485 
1486   GpioReadReg (
1487     GpioHostOwnershipRegister,
1488     Group,
1489     DwNum,
1490     HostSwRegVal
1491     );
1492 
1493   return EFI_SUCCESS;
1494 }
1495 
1496 /**
1497   This procedure will get GPIO Host Software Pad Ownership for certain group
1498 
1499   @param[in]  Group               GPIO group
1500   @param[in]  DwNum               Host Ownership register number for current group
1501                                   For group which has less then 32 pads per group DwNum must be 0.
1502   @param[in]  HostSwRegVal        Value of Host Software Pad Ownership register
1503                                   Bit position - PadNumber
1504                                   Bit value - 0: ACPI Mode, 1: GPIO Driver mode
1505 
1506   @retval EFI_SUCCESS             The function completed successfully
1507   @retval EFI_INVALID_PARAMETER   Invalid group or DwNum parameter number
1508 **/
1509 EFI_STATUS
GpioSetHostSwOwnershipForGroupDw(IN GPIO_GROUP Group,IN UINT32 DwNum,IN UINT32 HostSwRegVal)1510 GpioSetHostSwOwnershipForGroupDw (
1511   IN GPIO_GROUP                   Group,
1512   IN UINT32                       DwNum,
1513   IN UINT32                       HostSwRegVal
1514   )
1515 {
1516   if (!GpioIsGroupAndDwNumValid (Group, DwNum)) {
1517     return EFI_INVALID_PARAMETER;
1518   }
1519 
1520   GpioWriteReg (
1521     GpioHostOwnershipRegister,
1522     Group,
1523     DwNum,
1524     0,
1525     HostSwRegVal
1526     );
1527   return EFI_SUCCESS;
1528 }
1529 
1530 /**
1531   This procedure will get Gpio Pad Host Software Ownership
1532 
1533   @param[in]  GpioPad             GPIO pad
1534   @param[out] PadHostSwOwn        Value of Host Software Pad Owner
1535                                   0: ACPI Mode, 1: GPIO Driver mode
1536 
1537   @retval EFI_SUCCESS             The function completed successfully
1538   @retval EFI_INVALID_PARAMETER   Invalid GpioPad
1539 **/
1540 EFI_STATUS
GpioGetHostSwOwnershipForPad(IN GPIO_PAD GpioPad,OUT UINT32 * PadHostSwOwn)1541 GpioGetHostSwOwnershipForPad (
1542   IN GPIO_PAD                 GpioPad,
1543   OUT UINT32                  *PadHostSwOwn
1544   )
1545 {
1546   UINT32      PadNumber;
1547   UINT32      HostSwRegVal;
1548 
1549   if (!GpioIsPadValid (GpioPad)) {
1550     return EFI_INVALID_PARAMETER;
1551   }
1552 
1553   PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
1554 
1555   GpioReadReg (
1556     GpioHostOwnershipRegister,
1557     GpioGetGroupFromGpioPad (GpioPad),
1558     GPIO_GET_DW_NUM (PadNumber),
1559     &HostSwRegVal
1560     );
1561 
1562   *PadHostSwOwn = (HostSwRegVal >> GPIO_GET_PAD_POSITION (PadNumber)) & 0x1;
1563 
1564   return EFI_SUCCESS;
1565 }
1566 
1567 /**
1568   This procedure will set Gpio Pad Host Software Ownership
1569 
1570   @param[in] GpioPad              GPIO pad
1571   @param[in] PadHostSwOwn         Pad Host Software Owner
1572                                   0: ACPI Mode, 1: GPIO Driver mode
1573 
1574   @retval EFI_SUCCESS             The function completed successfully
1575   @retval EFI_INVALID_PARAMETER   Invalid GpioPad
1576 **/
1577 EFI_STATUS
GpioSetHostSwOwnershipForPad(IN GPIO_PAD GpioPad,IN UINT32 PadHostSwOwn)1578 GpioSetHostSwOwnershipForPad (
1579   IN GPIO_PAD                  GpioPad,
1580   IN UINT32                    PadHostSwOwn
1581   )
1582 {
1583   UINT32      PadNumber;
1584 
1585   if (!GpioIsPadValid (GpioPad) || (PadHostSwOwn > 1)) {
1586     return EFI_INVALID_PARAMETER;
1587   }
1588 
1589   PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
1590 
1591   GpioWriteReg (
1592     GpioHostOwnershipRegister,
1593     GpioGetGroupFromGpioPad (GpioPad),
1594     GPIO_GET_DW_NUM (PadNumber),
1595     (UINT32)~(1 << GPIO_GET_PAD_POSITION (PadNumber)),
1596     PadHostSwOwn << GPIO_GET_PAD_POSITION (PadNumber)
1597     );
1598 
1599   return EFI_SUCCESS;
1600 }
1601 
1602 /**
1603   This procedure will get Gpio Pad Ownership
1604 
1605   @param[in] GpioPad              GPIO pad
1606   @param[out] PadOwnVal           Value of Pad Ownership
1607 
1608   @retval EFI_SUCCESS             The function completed successfully
1609   @retval EFI_INVALID_PARAMETER   Invalid group or pad number
1610 **/
1611 EFI_STATUS
GpioGetPadOwnership(IN GPIO_PAD GpioPad,OUT GPIO_PAD_OWN * PadOwnVal)1612 GpioGetPadOwnership (
1613   IN  GPIO_PAD                GpioPad,
1614   OUT GPIO_PAD_OWN            *PadOwnVal
1615   )
1616 {
1617   UINT32                 Mask;
1618   UINT32                 RegOffset;
1619   UINT32                 GroupIndex;
1620   UINT32                 PadNumber;
1621   CONST GPIO_GROUP_INFO  *GpioGroupInfo;
1622   UINT32                 GpioGroupInfoLength;
1623   UINT32                 PadOwnRegValue;
1624 
1625   if (!GpioIsPadValid (GpioPad)) {
1626     return EFI_INVALID_PARAMETER;
1627   }
1628 
1629   GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
1630   PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
1631 
1632   GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
1633 
1634   //
1635   // Calculate RegOffset using Pad Ownership offset and GPIO Pad number.
1636   // One DWord register contains information for 8 pads.
1637   //
1638   RegOffset = GpioGroupInfo[GroupIndex].PadOwnOffset + (PadNumber >> 3) * 0x4;
1639 
1640   //
1641   // Calculate pad bit position within DWord register
1642   //
1643   PadNumber %= 8;
1644   Mask = (BIT1 | BIT0) << (PadNumber * 4);
1645 
1646   PadOwnRegValue = MmioRead32 (PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, RegOffset));
1647 
1648   *PadOwnVal = (GPIO_PAD_OWN) ((PadOwnRegValue & Mask) >> (PadNumber * 4));
1649 
1650   return EFI_SUCCESS;
1651 }
1652 
1653 /**
1654   This procedure will check state of Pad Config Lock for pads within one group
1655 
1656   @param[in]  Group               GPIO group
1657   @param[in]  DwNum               PadCfgLock register number for current group.
1658                                   For group which has less then 32 pads per group DwNum must be 0.
1659   @param[out] PadCfgLockRegVal    Value of PadCfgLock register
1660                                   Bit position - PadNumber
1661                                   Bit value - 0: NotLocked, 1: Locked
1662 
1663   @retval EFI_SUCCESS             The function completed successfully
1664   @retval EFI_INVALID_PARAMETER   Invalid group or DwNum parameter number
1665 **/
1666 EFI_STATUS
GpioGetPadCfgLockForGroupDw(IN GPIO_GROUP Group,IN UINT32 DwNum,OUT UINT32 * PadCfgLockRegVal)1667 GpioGetPadCfgLockForGroupDw (
1668   IN  GPIO_GROUP                  Group,
1669   IN  UINT32                      DwNum,
1670   OUT UINT32                      *PadCfgLockRegVal
1671   )
1672 {
1673   if (!GpioIsGroupAndDwNumValid (Group, DwNum)) {
1674     return EFI_INVALID_PARAMETER;
1675   }
1676 
1677   GpioReadReg (
1678     GpioPadConfigLockRegister,
1679     Group,
1680     DwNum,
1681     PadCfgLockRegVal
1682     );
1683 
1684   return EFI_SUCCESS;
1685 }
1686 
1687 /**
1688   This procedure will check state of Pad Config Lock for selected pad
1689 
1690   @param[in] GpioPad              GPIO pad
1691   @param[out] PadCfgLock          PadCfgLock for selected pad
1692                                   0: NotLocked, 1: Locked
1693 
1694   @retval EFI_SUCCESS             The function completed successfully
1695   @retval EFI_INVALID_PARAMETER   Invalid GpioPad
1696 **/
1697 EFI_STATUS
GpioGetPadCfgLock(IN GPIO_PAD GpioPad,OUT UINT32 * PadCfgLock)1698 GpioGetPadCfgLock (
1699   IN GPIO_PAD                   GpioPad,
1700   OUT UINT32                    *PadCfgLock
1701   )
1702 {
1703   UINT32      PadNumber;
1704   UINT32      PadCfgLockRegVal;
1705 
1706   if (!GpioIsPadValid (GpioPad)) {
1707     return EFI_INVALID_PARAMETER;
1708   }
1709 
1710   PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
1711 
1712   GpioReadReg (
1713     GpioPadConfigLockRegister,
1714     GpioGetGroupFromGpioPad (GpioPad),
1715     GPIO_GET_DW_NUM (PadNumber),
1716     &PadCfgLockRegVal
1717     );
1718 
1719   *PadCfgLock = (PadCfgLockRegVal >> GPIO_GET_PAD_POSITION (PadNumber)) & 0x1;
1720 
1721   return EFI_SUCCESS;
1722 }
1723 
1724 /**
1725   This procedure will check state of Pad Config Tx Lock for pads within one group
1726 
1727   @param[in]  Group               GPIO group
1728   @param[in]  DwNum               PadCfgLockTx register number for current group.
1729                                   For group which has less then 32 pads per group DwNum must be 0.
1730   @param[out] PadCfgLockTxRegVal  Value of PadCfgLockTx register
1731                                   Bit position - PadNumber
1732                                   Bit value - 0: NotLockedTx, 1: LockedTx
1733 
1734   @retval EFI_SUCCESS             The function completed successfully
1735   @retval EFI_INVALID_PARAMETER   Invalid group or DwNum parameter number
1736 **/
1737 EFI_STATUS
GpioGetPadCfgLockTxForGroupDw(IN GPIO_GROUP Group,IN UINT32 DwNum,OUT UINT32 * PadCfgLockTxRegVal)1738 GpioGetPadCfgLockTxForGroupDw (
1739   IN  GPIO_GROUP                  Group,
1740   IN  UINT32                      DwNum,
1741   OUT UINT32                      *PadCfgLockTxRegVal
1742   )
1743 {
1744   if (!GpioIsGroupAndDwNumValid (Group, DwNum)) {
1745     return EFI_INVALID_PARAMETER;
1746   }
1747 
1748   GpioReadReg (
1749     GpioPadLockOutputRegister,
1750     Group,
1751     DwNum,
1752     PadCfgLockTxRegVal
1753     );
1754 
1755   return EFI_SUCCESS;
1756 }
1757 
1758 /**
1759   This procedure will check state of Pad Config Tx Lock for selected pad
1760 
1761   @param[in] GpioPad              GPIO pad
1762   @param[out] PadCfgLock          PadCfgLockTx for selected pad
1763                                   0: NotLockedTx, 1: LockedTx
1764 
1765   @retval EFI_SUCCESS             The function completed successfully
1766   @retval EFI_INVALID_PARAMETER   Invalid GpioPad
1767 **/
1768 EFI_STATUS
GpioGetPadCfgLockTx(IN GPIO_PAD GpioPad,OUT UINT32 * PadCfgLockTx)1769 GpioGetPadCfgLockTx (
1770   IN GPIO_PAD                   GpioPad,
1771   OUT UINT32                    *PadCfgLockTx
1772   )
1773 {
1774   UINT32      PadNumber;
1775   UINT32      PadCfgLockTxRegVal;
1776 
1777   if (!GpioIsPadValid (GpioPad)) {
1778     return EFI_INVALID_PARAMETER;
1779   }
1780 
1781   PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
1782 
1783   GpioReadReg (
1784     GpioPadLockOutputRegister,
1785     GpioGetGroupFromGpioPad (GpioPad),
1786     GPIO_GET_DW_NUM (PadNumber),
1787     &PadCfgLockTxRegVal
1788     );
1789 
1790   *PadCfgLockTx = (PadCfgLockTxRegVal >> GPIO_GET_PAD_POSITION (PadNumber)) & 0x1;
1791 
1792   return EFI_SUCCESS;
1793 }
1794 
1795 /**
1796   This procedure will clear PadCfgLock for selected pads within one group.
1797   This function should be used only inside SMI.
1798 
1799   @param[in]  Group               GPIO group
1800   @param[in]  DwNum               PadCfgLock register number for current group.
1801                                   For group which has less then 32 pads per group DwNum must be 0.
1802   @param[in]  PadsToUnlock        Bitmask for pads which are going to be unlocked,
1803                                   Bit position - PadNumber
1804                                   Bit value - 0: DoNotUnlock, 1: Unlock
1805 
1806   @retval EFI_SUCCESS             The function completed successfully
1807   @retval EFI_INVALID_PARAMETER   Invalid group or pad number
1808 **/
1809 EFI_STATUS
GpioUnlockPadCfgForGroupDw(IN GPIO_GROUP Group,IN UINT32 DwNum,IN UINT32 PadsToUnlock)1810 GpioUnlockPadCfgForGroupDw (
1811   IN GPIO_GROUP                Group,
1812   IN UINT32                    DwNum,
1813   IN UINT32                    PadsToUnlock
1814   )
1815 {
1816   if (!GpioIsGroupAndDwNumValid (Group, DwNum)) {
1817     return EFI_INVALID_PARAMETER;
1818   }
1819 
1820   return GpioWriteLockReg (
1821            GpioPadConfigLockRegister,
1822            Group,
1823            DwNum,
1824            ~PadsToUnlock,
1825            0
1826            );
1827 }
1828 
1829 /**
1830   This procedure will clear PadCfgLock for selected pad.
1831   This function should be used only inside SMI.
1832 
1833   @param[in] GpioPad              GPIO pad
1834 
1835   @retval EFI_SUCCESS             The function completed successfully
1836   @retval EFI_INVALID_PARAMETER   Invalid group or pad number
1837 **/
1838 EFI_STATUS
GpioUnlockPadCfg(IN GPIO_PAD GpioPad)1839 GpioUnlockPadCfg (
1840   IN GPIO_PAD                   GpioPad
1841   )
1842 {
1843   GPIO_GROUP   Group;
1844   UINT32       PadNumber;
1845 
1846   Group = GpioGetGroupFromGpioPad (GpioPad);
1847   PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
1848 
1849   return GpioUnlockPadCfgForGroupDw (
1850            Group,
1851            GPIO_GET_DW_NUM (PadNumber),
1852            1 << GPIO_GET_PAD_POSITION (PadNumber)
1853            );
1854 }
1855 
1856 /**
1857   This procedure will set PadCfgLock for selected pads within one group
1858 
1859   @param[in]  Group               GPIO group
1860   @param[in]  DwNum               PadCfgLock register number for current group.
1861                                   For group which has less then 32 pads per group DwNum must be 0.
1862   @param[in]  PadsToLock          Bitmask for pads which are going to be locked
1863                                   Bit position - PadNumber
1864                                   Bit value - 0: DoNotLock, 1: Lock
1865 
1866   @retval EFI_SUCCESS             The function completed successfully
1867   @retval EFI_INVALID_PARAMETER   Invalid group or DwNum parameter number
1868 **/
1869 EFI_STATUS
GpioLockPadCfgForGroupDw(IN GPIO_GROUP Group,IN UINT32 DwNum,IN UINT32 PadsToLock)1870 GpioLockPadCfgForGroupDw (
1871   IN GPIO_GROUP                   Group,
1872   IN UINT32                       DwNum,
1873   IN UINT32                       PadsToLock
1874   )
1875 {
1876   if (!GpioIsGroupAndDwNumValid (Group, DwNum)) {
1877     return EFI_INVALID_PARAMETER;
1878   }
1879 
1880   return GpioWriteLockReg (
1881            GpioPadConfigLockRegister,
1882            Group,
1883            DwNum,
1884            ~0u,
1885            PadsToLock
1886            );
1887 }
1888 
1889 /**
1890   This procedure will set PadCfgLock for selected pad
1891 
1892   @param[in] GpioPad              GPIO pad
1893 
1894   @retval EFI_SUCCESS             The function completed successfully
1895   @retval EFI_INVALID_PARAMETER   Invalid group or pad number
1896 **/
1897 EFI_STATUS
GpioLockPadCfg(IN GPIO_PAD GpioPad)1898 GpioLockPadCfg (
1899   IN GPIO_PAD                   GpioPad
1900   )
1901 {
1902   GPIO_GROUP   Group;
1903   UINT32       PadNumber;
1904 
1905   Group = GpioGetGroupFromGpioPad (GpioPad);
1906   PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
1907 
1908   return GpioLockPadCfgForGroupDw (
1909            Group,
1910            GPIO_GET_DW_NUM (PadNumber),
1911            1 << GPIO_GET_PAD_POSITION (PadNumber)
1912            );
1913 }
1914 
1915 /**
1916   This procedure will clear PadCfgLockTx for selected pads within one group.
1917   This function should be used only inside SMI.
1918 
1919   @param[in]  Group               GPIO group
1920   @param[in]  DwNum               PadCfgLockTx register number for current group.
1921                                   For group which has less then 32 pads per group DwNum must be 0.
1922   @param[in]  PadsToUnlockTx      Bitmask for pads which are going to be unlocked,
1923                                   Bit position - PadNumber
1924                                   Bit value - 0: DoNotUnLockTx, 1: LockTx
1925 
1926   @retval EFI_SUCCESS             The function completed successfully
1927   @retval EFI_INVALID_PARAMETER   Invalid group or pad number
1928 **/
1929 EFI_STATUS
GpioUnlockPadCfgTxForGroupDw(IN GPIO_GROUP Group,IN UINT32 DwNum,IN UINT32 PadsToUnlockTx)1930 GpioUnlockPadCfgTxForGroupDw (
1931   IN GPIO_GROUP                Group,
1932   IN UINT32                    DwNum,
1933   IN UINT32                    PadsToUnlockTx
1934   )
1935 {
1936   if (!GpioIsGroupAndDwNumValid (Group, DwNum)) {
1937     return EFI_INVALID_PARAMETER;
1938   }
1939 
1940   return GpioWriteLockReg (
1941            GpioPadLockOutputRegister,
1942            Group,
1943            DwNum,
1944            ~PadsToUnlockTx,
1945            0
1946            );
1947 }
1948 
1949 /**
1950   This procedure will clear PadCfgLockTx for selected pad.
1951   This function should be used only inside SMI.
1952 
1953   @param[in] GpioPad              GPIO pad
1954 
1955   @retval EFI_SUCCESS             The function completed successfully
1956   @retval EFI_INVALID_PARAMETER   Invalid group or pad number
1957 **/
1958 EFI_STATUS
GpioUnlockPadCfgTx(IN GPIO_PAD GpioPad)1959 GpioUnlockPadCfgTx (
1960   IN GPIO_PAD                   GpioPad
1961   )
1962 {
1963   GPIO_GROUP   Group;
1964   UINT32       PadNumber;
1965 
1966   Group = GpioGetGroupFromGpioPad (GpioPad);
1967   PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
1968 
1969   return GpioUnlockPadCfgTxForGroupDw (
1970            Group,
1971            GPIO_GET_DW_NUM (PadNumber),
1972            1 << GPIO_GET_PAD_POSITION (PadNumber)
1973            );
1974 }
1975 
1976 /**
1977   This procedure will set PadCfgLockTx for selected pads within one group
1978 
1979   @param[in]  Group               GPIO group
1980   @param[in]  DwNum               PadCfgLock register number for current group.
1981                                   For group which has less then 32 pads per group DwNum must be 0.
1982   @param[in]  PadsToLockTx        Bitmask for pads which are going to be locked,
1983                                   Bit position - PadNumber
1984                                   Bit value - 0: DoNotLockTx, 1: LockTx
1985 
1986   @retval EFI_SUCCESS             The function completed successfully
1987   @retval EFI_INVALID_PARAMETER   Invalid group or DwNum parameter number
1988 **/
1989 EFI_STATUS
GpioLockPadCfgTxForGroupDw(IN GPIO_GROUP Group,IN UINT32 DwNum,IN UINT32 PadsToLockTx)1990 GpioLockPadCfgTxForGroupDw (
1991   IN GPIO_GROUP                   Group,
1992   IN UINT32                       DwNum,
1993   IN UINT32                       PadsToLockTx
1994   )
1995 {
1996   if (!GpioIsGroupAndDwNumValid (Group, DwNum)) {
1997     return EFI_INVALID_PARAMETER;
1998   }
1999 
2000   return GpioWriteLockReg (
2001            GpioPadLockOutputRegister,
2002            Group,
2003            DwNum,
2004            ~0u,
2005            PadsToLockTx
2006            );
2007 }
2008 
2009 /**
2010   This procedure will set PadCfgLockTx for selected pad
2011 
2012   @param[in] GpioPad              GPIO pad
2013 
2014   @retval EFI_SUCCESS             The function completed successfully
2015   @retval EFI_INVALID_PARAMETER   Invalid group or pad number
2016 **/
2017 EFI_STATUS
GpioLockPadCfgTx(IN GPIO_PAD GpioPad)2018 GpioLockPadCfgTx (
2019   IN GPIO_PAD                   GpioPad
2020   )
2021 {
2022   GPIO_GROUP   Group;
2023   UINT32       PadNumber;
2024 
2025   Group = GpioGetGroupFromGpioPad (GpioPad);
2026   PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
2027 
2028   return GpioLockPadCfgTxForGroupDw (
2029            Group,
2030            GPIO_GET_DW_NUM (PadNumber),
2031            1 << GPIO_GET_PAD_POSITION (PadNumber)
2032            );
2033 }
2034 
2035 /**
2036   This procedure will get Group to GPE mapping.
2037   It will assume that only first 32 pads can be mapped to GPE.
2038   To handle cases where groups have more than 32 pads and higher part of group
2039   can be mapped please refer to GpioGetGroupDwToGpeDwX()
2040 
2041   @param[out] GroupToGpeDw0       GPIO group to be mapped to GPE_DW0
2042   @param[out] GroupToGpeDw1       GPIO group to be mapped to GPE_DW1
2043   @param[out] GroupToGpeDw2       GPIO group to be mapped to GPE_DW2
2044 
2045   @retval EFI_SUCCESS             The function completed successfully
2046   @retval EFI_INVALID_PARAMETER   Invalid group or pad number
2047 **/
2048 EFI_STATUS
GpioGetGroupToGpeDwX(IN GPIO_GROUP * GroupToGpeDw0,IN GPIO_GROUP * GroupToGpeDw1,IN GPIO_GROUP * GroupToGpeDw2)2049 GpioGetGroupToGpeDwX (
2050   IN GPIO_GROUP               *GroupToGpeDw0,
2051   IN GPIO_GROUP               *GroupToGpeDw1,
2052   IN GPIO_GROUP               *GroupToGpeDw2
2053   )
2054 {
2055   UINT32     GroupDw[3];
2056   UINT32     Index;
2057   EFI_STATUS Status;
2058 
2059   Status = GpioGetGroupDwToGpeDwX (
2060              GroupToGpeDw0,
2061              &GroupDw[0],
2062              GroupToGpeDw1,
2063              &GroupDw[1],
2064              GroupToGpeDw2,
2065              &GroupDw[2]
2066              );
2067 
2068   for (Index = 0; Index < ARRAY_SIZE (GroupDw); Index++) {
2069     if (GroupDw[Index] != 0) {
2070       Status = EFI_UNSUPPORTED;
2071       ASSERT (FALSE);
2072     }
2073   }
2074   return Status;
2075 }
2076 
2077 
2078 /**
2079   This procedure will get Group to GPE mapping. If group has more than 32 bits
2080   it is possible to map only single DW of pins (e.g. 0-31, 32-63) because
2081   ACPI GPE_DWx register is 32 bits large.
2082 
2083   @param[out]  GroupToGpeDw0       GPIO group mapped to GPE_DW0
2084   @param[out]  GroupDwForGpeDw0    DW of pins mapped to GPE_DW0
2085   @param[out]  GroupToGpeDw1       GPIO group mapped to GPE_DW1
2086   @param[out]  GroupDwForGpeDw1    DW of pins mapped to GPE_DW1
2087   @param[out]  GroupToGpeDw2       GPIO group mapped to GPE_DW2
2088   @param[out]  GroupDwForGpeDw2    DW of pins mapped to GPE_DW2
2089 
2090   @retval EFI_SUCCESS             The function completed successfully
2091   @retval EFI_INVALID_PARAMETER   Invalid group or pad number
2092 **/
2093 EFI_STATUS
GpioGetGroupDwToGpeDwX(OUT GPIO_GROUP * GroupToGpeDw0,OUT UINT32 * GroupDwForGpeDw0,OUT GPIO_GROUP * GroupToGpeDw1,OUT UINT32 * GroupDwForGpeDw1,OUT GPIO_GROUP * GroupToGpeDw2,OUT UINT32 * GroupDwForGpeDw2)2094 GpioGetGroupDwToGpeDwX (
2095   OUT GPIO_GROUP                *GroupToGpeDw0,
2096   OUT UINT32                    *GroupDwForGpeDw0,
2097   OUT GPIO_GROUP                *GroupToGpeDw1,
2098   OUT UINT32                    *GroupDwForGpeDw1,
2099   OUT GPIO_GROUP                *GroupToGpeDw2,
2100   OUT UINT32                    *GroupDwForGpeDw2
2101   )
2102 {
2103   UINT32                     PmcGpeDwXValue[3];
2104   GPIO_GROUP                 GroupToGpeDwX[3];
2105   UINT32                     GroupDwForGpeDwX[3];
2106   UINT8                      GpeDwXIndex;
2107   UINT32                     Index;
2108   GPIO_GROUP_TO_GPE_MAPPING  *GpioGpeMap;
2109   UINT32                     GpioGpeMapLength;
2110 
2111   ZeroMem (GroupToGpeDwX, sizeof (GroupToGpeDwX));
2112   ZeroMem (GroupDwForGpeDwX, sizeof (GroupDwForGpeDwX));
2113 
2114   PmcGetGpioGpe (&PmcGpeDwXValue[0], &PmcGpeDwXValue[1], &PmcGpeDwXValue[2]);
2115 
2116   GpioGetGroupToGpeMapping (&GpioGpeMap, &GpioGpeMapLength);
2117 
2118   for (GpeDwXIndex = 0; GpeDwXIndex < 3; GpeDwXIndex++) {
2119     for (Index = 0; Index < GpioGpeMapLength; Index++) {
2120 
2121       if (GpioGpeMap[Index].PmcGpeDwxVal == PmcGpeDwXValue[GpeDwXIndex]) {
2122         GroupToGpeDwX[GpeDwXIndex] = GpioGpeMap[Index].Group;
2123         GroupDwForGpeDwX[GpeDwXIndex] = GpioGpeMap[Index].GroupDw;
2124         break;
2125       }
2126     }
2127   }
2128 
2129   if ((GroupToGpeDwX[0] == 0) ||
2130       (GroupToGpeDwX[1] == 0) ||
2131       (GroupToGpeDwX[2] == 0)) {
2132     ASSERT (FALSE);
2133     return EFI_UNSUPPORTED;
2134   }
2135 
2136   *GroupToGpeDw0 = GroupToGpeDwX[0];
2137   *GroupDwForGpeDw0 = GroupDwForGpeDwX[0];
2138   *GroupToGpeDw1 = GroupToGpeDwX[1];
2139   *GroupDwForGpeDw1 = GroupDwForGpeDwX[1];
2140   *GroupToGpeDw2 = GroupToGpeDwX[2];
2141   *GroupDwForGpeDw2 = GroupDwForGpeDwX[2];
2142 
2143   return EFI_SUCCESS;
2144 }
2145 
2146 
2147 /**
2148   This procedure will set Group to GPE mapping.
2149   It will assume that only first 32 pads can be mapped to GPE.
2150   To handle cases where groups have more than 32 pads and higher part of group
2151   can be mapped please refer to GpioSetGroupDwToGpeDwX()
2152 
2153   @param[in]  GroupToGpeDw0       GPIO group to be mapped to GPE_DW0
2154   @param[in]  GroupToGpeDw1       GPIO group to be mapped to GPE_DW1
2155   @param[in]  GroupToGpeDw2       GPIO group to be mapped to GPE_DW2
2156 
2157   @retval EFI_SUCCESS             The function completed successfully
2158   @retval EFI_INVALID_PARAMETER   Invalid group or pad number
2159 **/
2160 EFI_STATUS
GpioSetGroupToGpeDwX(IN GPIO_GROUP GroupToGpeDw0,IN GPIO_GROUP GroupToGpeDw1,IN GPIO_GROUP GroupToGpeDw2)2161 GpioSetGroupToGpeDwX (
2162   IN GPIO_GROUP                GroupToGpeDw0,
2163   IN GPIO_GROUP                GroupToGpeDw1,
2164   IN GPIO_GROUP                GroupToGpeDw2
2165   )
2166 {
2167   return GpioSetGroupDwToGpeDwX (
2168            GroupToGpeDw0,
2169            0,
2170            GroupToGpeDw1,
2171            0,
2172            GroupToGpeDw2,
2173            0
2174            );
2175 }
2176 
2177 /**
2178   This procedure will set Group to GPE mapping. If group has more than 32 bits
2179   it is possible to map only single DW of pins (e.g. 0-31, 32-63) because
2180   ACPI GPE_DWx register is 32 bits large.
2181 
2182   @param[in]  GroupToGpeDw0       GPIO group to be mapped to GPE_DW0
2183   @param[in]  GroupDwForGpeDw0    DW of pins to be mapped to GPE_DW0
2184   @param[in]  GroupToGpeDw1       GPIO group to be mapped to GPE_DW1
2185   @param[in]  GroupDwForGpeDw1    DW of pins to be mapped to GPE_DW1
2186   @param[in]  GroupToGpeDw2       GPIO group to be mapped to GPE_DW2
2187   @param[in]  GroupDwForGpeDw2    DW of pins to be mapped to GPE_DW2
2188 
2189   @retval EFI_SUCCESS             The function completed successfully
2190   @retval EFI_INVALID_PARAMETER   Invalid group or pad number
2191 **/
2192 EFI_STATUS
GpioSetGroupDwToGpeDwX(IN GPIO_GROUP GroupToGpeDw0,IN UINT32 GroupDwForGpeDw0,IN GPIO_GROUP GroupToGpeDw1,IN UINT32 GroupDwForGpeDw1,IN GPIO_GROUP GroupToGpeDw2,IN UINT32 GroupDwForGpeDw2)2193 GpioSetGroupDwToGpeDwX (
2194   IN GPIO_GROUP                GroupToGpeDw0,
2195   IN UINT32                    GroupDwForGpeDw0,
2196   IN GPIO_GROUP                GroupToGpeDw1,
2197   IN UINT32                    GroupDwForGpeDw1,
2198   IN GPIO_GROUP                GroupToGpeDw2,
2199   IN UINT32                    GroupDwForGpeDw2
2200   )
2201 {
2202   UINT32                     Data32Or;
2203   UINT32                     Data32And;
2204   PCH_SBI_PID                *GpioComSbiIds;
2205   UINT32                     NoOfGpioComs;
2206   UINT32                     GpioComIndex;
2207   UINT32                     GpioGpeDwx[3];
2208   UINT32                     PmcGpeDwx[3];
2209   GPIO_GROUP                 GroupToGpeDwX[3];
2210   UINT32                     GroupDwForGpeDwX[3];
2211   UINT8                      GpeDwXIndex;
2212   UINT32                     Index;
2213   GPIO_GROUP_TO_GPE_MAPPING  *GpioGpeMap;
2214   UINT32                     GpioGpeMapLength;
2215 
2216   ZeroMem (GpioGpeDwx, sizeof (GpioGpeDwx));
2217   ZeroMem (PmcGpeDwx, sizeof (PmcGpeDwx));
2218   //
2219   // Check if each group number is unique
2220   //
2221   if ((GroupToGpeDw0 == GroupToGpeDw1) ||
2222       (GroupToGpeDw0 == GroupToGpeDw2) ||
2223       (GroupToGpeDw1 == GroupToGpeDw2)) {
2224     return EFI_INVALID_PARAMETER;
2225   }
2226 
2227   GroupToGpeDwX[0] = GroupToGpeDw0;
2228   GroupDwForGpeDwX[0] = GroupDwForGpeDw0;
2229   GroupToGpeDwX[1] = GroupToGpeDw1;
2230   GroupDwForGpeDwX[1] = GroupDwForGpeDw1;
2231   GroupToGpeDwX[2] = GroupToGpeDw2;
2232   GroupDwForGpeDwX[2] = GroupDwForGpeDw2;
2233 
2234   GpioGetGroupToGpeMapping (&GpioGpeMap, &GpioGpeMapLength);
2235 
2236   for (GpeDwXIndex = 0; GpeDwXIndex < 3; GpeDwXIndex++) {
2237     for (Index = 0; Index < GpioGpeMapLength; Index++) {
2238 
2239       if ((GpioGpeMap[Index].Group == GroupToGpeDwX[GpeDwXIndex]) &&
2240           (GpioGpeMap[Index].GroupDw == GroupDwForGpeDwX[GpeDwXIndex])) {
2241         PmcGpeDwx[GpeDwXIndex] = GpioGpeMap[Index].PmcGpeDwxVal;
2242         GpioGpeDwx[GpeDwXIndex] = GpioGpeMap[Index].GpioGpeDwxVal;
2243         break;
2244       }
2245     }
2246 
2247     if (Index == GpioGpeMapLength) {
2248       ASSERT (FALSE);
2249       return EFI_INVALID_PARAMETER;
2250     }
2251   }
2252 
2253   //
2254   // Program GPE configuration in PMC register
2255   //
2256   PmcSetGpioGpe (
2257     PmcGpeDwx[0],
2258     PmcGpeDwx[1],
2259     PmcGpeDwx[2]
2260     );
2261 
2262   //
2263   // Program GPE configuration in GPIO registers
2264   //
2265   Data32And = (UINT32) ~(B_GPIO_PCR_MISCCFG_GPE0_DW2 | B_GPIO_PCR_MISCCFG_GPE0_DW1 | B_GPIO_PCR_MISCCFG_GPE0_DW0);
2266   Data32Or = (UINT32) ((GpioGpeDwx[2] << N_GPIO_PCR_MISCCFG_GPE0_DW2) |
2267                        (GpioGpeDwx[1] << N_GPIO_PCR_MISCCFG_GPE0_DW1) |
2268                        (GpioGpeDwx[0] << N_GPIO_PCR_MISCCFG_GPE0_DW0));
2269 
2270   NoOfGpioComs = GpioGetComSbiPortIds (&GpioComSbiIds);
2271 
2272   //
2273   // Program MISCCFG register for each community
2274   //
2275   for (GpioComIndex = 0; GpioComIndex < NoOfGpioComs; GpioComIndex++) {
2276     MmioAndThenOr32 (
2277       PCH_PCR_ADDRESS (GpioComSbiIds[GpioComIndex], R_GPIO_PCR_MISCCFG),
2278       Data32And,
2279       Data32Or
2280       );
2281   }
2282 
2283   return EFI_SUCCESS;
2284 }
2285 
2286 /**
2287   This procedure will get GPE number for provided GpioPad.
2288   PCH allows to configure mapping between GPIO groups and related GPE (GpioSetGroupToGpeDwX())
2289   what results in the fact that certain Pad can cause different General Purpose Event. Only three
2290   GPIO groups can be mapped to cause unique GPE (1-tier), all others groups will be under one common
2291   event (GPE_111 for 2-tier).
2292 
2293   1-tier:
2294   Returned GpeNumber is in range <0,95>. GpioGetGpeNumber() can be used
2295   to determine what _LXX ACPI method would be called on event on selected GPIO pad
2296 
2297   2-tier:
2298   Returned GpeNumber is 0x6F (111). All GPIO pads which are not mapped to 1-tier GPE
2299   will be under one master GPE_111 which is linked to _L6F ACPI method. If it is needed to determine
2300   what Pad from 2-tier has caused the event, _L6F method should check GPI_GPE_STS and GPI_GPE_EN
2301   registers for all GPIO groups not mapped to 1-tier GPE.
2302 
2303   @param[in]  GpioPad             GPIO pad
2304   @param[out] GpeNumber           GPE number
2305 
2306   @retval EFI_SUCCESS             The function completed successfully
2307   @retval EFI_INVALID_PARAMETER   Invalid GpioPad
2308 **/
2309 EFI_STATUS
GpioGetGpeNumber(IN GPIO_PAD GpioPad,OUT UINT32 * GpeNumber)2310 GpioGetGpeNumber (
2311   IN  GPIO_PAD                  GpioPad,
2312   OUT UINT32                    *GpeNumber
2313   )
2314 {
2315   GPIO_GROUP           GroupToGpeDwX[3];
2316   UINT32               GroupDw[3];
2317   GPIO_GROUP           Group;
2318   UINT32               PadNumber;
2319   UINT32               Index;
2320   EFI_STATUS           Status;
2321 
2322   Group = GpioGetGroupFromGpioPad (GpioPad);
2323   PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
2324 
2325   if (!GpioIsPadValid (GpioPad)) {
2326     return EFI_INVALID_PARAMETER;
2327   }
2328 
2329   //
2330   // Get GPIO groups mapping to 1-tier GPE
2331   // This mapping is dependent on GPIO IP implementation
2332   // and may change between chipset generations
2333   //
2334   Status = GpioGetGroupDwToGpeDwX (
2335              &GroupToGpeDwX[0], &GroupDw[0],
2336              &GroupToGpeDwX[1], &GroupDw[1],
2337              &GroupToGpeDwX[2], &GroupDw[2]
2338              );
2339   if (EFI_ERROR (Status)) {
2340     return Status;
2341   }
2342 
2343   //
2344   // Check if pad is routed to 1-Tier GPE
2345   //
2346   for (Index = 0; Index < 3; Index++) {
2347     if ((Group == GroupToGpeDwX[Index]) && (PadNumber >= (32 * GroupDw[Index])) && (PadNumber < (32 * (GroupDw[Index] + 1)))) {
2348       *GpeNumber = PadNumber + (32 * Index) - (32 * GroupDw[Index]);
2349       return EFI_SUCCESS;
2350     }
2351   }
2352 
2353   //
2354   // If Group number doesn't match any of above then
2355   // it means that the pad is routed to 2-tier GPE
2356   // which corresponds to  GPE_111 (0x6F)
2357   //
2358   *GpeNumber = PCH_GPIO_2_TIER_MASTER_GPE_NUMBER;
2359 
2360   return EFI_SUCCESS;
2361 }
2362 
2363 /**
2364   This procedure is used to clear SMI STS for a specified Pad
2365 
2366   @param[in]  GpioPad             GPIO pad
2367 
2368   @retval EFI_SUCCESS             The function completed successfully
2369   @retval EFI_INVALID_PARAMETER   Invalid GpioPad
2370 **/
2371 EFI_STATUS
GpioClearGpiSmiSts(IN GPIO_PAD GpioPad)2372 GpioClearGpiSmiSts (
2373   IN GPIO_PAD                   GpioPad
2374   )
2375 {
2376   GPIO_GROUP           Group;
2377   UINT32               PadNumber;
2378   UINT32               DwNum;
2379   UINT32               PadBitPosition;
2380 
2381   if (!GpioIsPadValid (GpioPad)) {
2382     return EFI_UNSUPPORTED;
2383   }
2384 
2385   Group = GpioGetGroupFromGpioPad (GpioPad);
2386   PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
2387   DwNum = GPIO_GET_DW_NUM (PadNumber);
2388   PadBitPosition = GPIO_GET_PAD_POSITION (PadNumber);
2389 
2390   //
2391   // Clear GPI SMI Status bit by writing '1'
2392   //
2393   GpioWriteReg (
2394     GpioSmiStatusRegister,
2395     Group,
2396     DwNum,
2397     0u,
2398     (UINT32) (BIT0 << PadBitPosition)
2399     );
2400 
2401   return EFI_SUCCESS;
2402 }
2403 
2404 /**
2405   This procedure is used by PchSmiDispatcher and will clear
2406   all GPI SMI Status bits
2407 
2408   @retval EFI_SUCCESS             The function completed successfully
2409   @retval EFI_INVALID_PARAMETER   Invalid group or pad number
2410 **/
2411 EFI_STATUS
GpioClearAllGpiSmiSts(VOID)2412 GpioClearAllGpiSmiSts (
2413   VOID
2414   )
2415 {
2416   UINT32         DwNum;
2417   GPIO_GROUP     Group;
2418   GPIO_GROUP     GroupMin;
2419   GPIO_GROUP     GroupMax;
2420 
2421   GroupMin = GpioGetLowestGroup ();
2422   GroupMax = GpioGetHighestGroup ();
2423 
2424   for (Group = GroupMin; Group <= GroupMax; Group++) {
2425     //
2426     // Clear all GPI SMI STS
2427     //
2428     for (DwNum = 0; DwNum <= GPIO_GET_DW_NUM (GpioGetPadPerGroup (Group)); DwNum++) {
2429       if (GpioIsSmiSupportedByGroupDw(Group, DwNum)) {
2430         GpioWriteReg (
2431           GpioSmiStatusRegister,
2432           Group,
2433           DwNum,
2434           0u,
2435           0xFFFFFFFF
2436           );
2437       }
2438     }
2439   }
2440   return EFI_SUCCESS;
2441 
2442 }
2443 
2444 /**
2445   This procedure is used to disable all GPI SMI
2446 
2447   @retval EFI_SUCCESS             The function completed successfully
2448   @retval EFI_INVALID_PARAMETER   Invalid group or pad number
2449 **/
2450 EFI_STATUS
GpioDisableAllGpiSmi(VOID)2451 GpioDisableAllGpiSmi (
2452   VOID
2453   )
2454 {
2455   UINT32         DwNum;
2456   GPIO_GROUP     Group;
2457   GPIO_GROUP     GroupMin;
2458   GPIO_GROUP     GroupMax;
2459   UINT32         SmiEnRegVal;
2460 
2461   GroupMin = GpioGetLowestGroup ();
2462   GroupMax = GpioGetHighestGroup ();
2463 
2464   for (Group = GroupMin; Group <= GroupMax; Group++) {
2465     //
2466     // Disable all GPI SMI
2467     //
2468     for (DwNum = 0; DwNum <= GPIO_GET_DW_NUM (GpioGetPadPerGroup (Group)); DwNum++) {
2469       if (GpioIsSmiSupportedByGroupDw (Group, DwNum)) {
2470         SmiEnRegVal = 0;
2471         //
2472         // Check which pins have SMI_EN set
2473         //
2474         GpioReadReg (
2475           GpioSmiEnableRegister,
2476           Group,
2477           DwNum,
2478           &SmiEnRegVal
2479           );
2480           //
2481           // Set HOSTSW_OWN to GPIO mode (1) for those pins to disable SMI capability
2482           //
2483         GpioWriteReg (
2484           GpioHostOwnershipRegister,
2485           Group,
2486           DwNum,
2487           ~0u,
2488           SmiEnRegVal
2489           );
2490       }
2491     }
2492   }
2493   return EFI_SUCCESS;
2494 }
2495 
2496 /**
2497   This procedure is used to register GPI SMI dispatch function.
2498 
2499   @param[in]  GpioPad             GPIO pad
2500   @param[out] GpiNum              GPI number
2501 
2502   @retval EFI_SUCCESS             The function completed successfully
2503   @retval EFI_INVALID_PARAMETER   Invalid GpioPad
2504 **/
2505 EFI_STATUS
GpioGetGpiSmiNum(IN GPIO_PAD GpioPad,OUT UINTN * GpiNum)2506 GpioGetGpiSmiNum (
2507   IN GPIO_PAD          GpioPad,
2508   OUT UINTN            *GpiNum
2509   )
2510 {
2511   UINT32                 GroupIndex;
2512   UINT32                 Index;
2513   UINT32                 PadNumber;
2514   CONST GPIO_GROUP_INFO  *GpioGroupInfo;
2515   UINT32                 GpioGroupInfoLength;
2516 
2517   GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
2518   PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
2519 
2520   if (!GpioIsPadValid (GpioPad)) {
2521     return EFI_UNSUPPORTED;
2522   }
2523 
2524   GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
2525 
2526   *GpiNum = 0;
2527 
2528   for (Index = 0; Index < GroupIndex; Index++) {
2529     *GpiNum += (UINTN) (GpioGroupInfo[Index].PadPerGroup);
2530   }
2531   *GpiNum += (UINTN) PadNumber;
2532 
2533   return EFI_SUCCESS;
2534 }
2535 
2536 /**
2537   This procedure is used to check GPIO inputs belongs to 2 tier or 1 tier architecture
2538 
2539   @param[in]  GpioPad             GPIO pad
2540 
2541   @retval     Data                0 means 1-tier, 1 means 2-tier
2542 **/
2543 BOOLEAN
GpioCheckFor2Tier(IN GPIO_PAD GpioPad)2544 GpioCheckFor2Tier (
2545   IN GPIO_PAD                  GpioPad
2546   )
2547 {
2548   UINT32               Data32;
2549   EFI_STATUS           Status;
2550 
2551   Status = GpioGetGpeNumber (GpioPad, &Data32);
2552   if (EFI_ERROR (Status)) {
2553     DEBUG (( DEBUG_ERROR, "GpioCheckFor2Tier: Failed to get GPE number. Status: %r\n", Status ));
2554     return FALSE;
2555   }
2556 
2557   if (Data32 == PCH_GPIO_2_TIER_MASTER_GPE_NUMBER) {
2558     return TRUE;
2559   }
2560 
2561   return FALSE;
2562 }
2563 
2564 /**
2565   This procedure is used to clear GPE STS for a specified GpioPad
2566 
2567   @param[in]  GpioPad             GPIO pad
2568 
2569   @retval EFI_SUCCESS             The function completed successfully
2570   @retval EFI_INVALID_PARAMETER   Invalid GpioPad
2571 **/
2572 EFI_STATUS
GpioClearGpiGpeSts(IN GPIO_PAD GpioPad)2573 GpioClearGpiGpeSts (
2574   IN GPIO_PAD                  GpioPad
2575   )
2576 {
2577   GPIO_GROUP           Group;
2578   UINT32               PadNumber;
2579   UINT32               DwNum;
2580   UINT32               PadBitPosition;
2581 
2582   if (!GpioIsPadValid (GpioPad)) {
2583     return EFI_UNSUPPORTED;
2584   }
2585 
2586   //
2587   // Check for 2-tier
2588   //
2589   if (!(GpioCheckFor2Tier (GpioPad))) {
2590     return EFI_INVALID_PARAMETER;
2591   }
2592 
2593   Group = GpioGetGroupFromGpioPad (GpioPad);
2594   PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
2595   DwNum = GPIO_GET_DW_NUM (PadNumber);
2596   PadBitPosition = GPIO_GET_PAD_POSITION (PadNumber);
2597 
2598   //
2599   // Clear GPI GPE Status bit by writing '1'
2600   //
2601   GpioWriteReg (
2602     GpioGpeStatusRegister,
2603     Group,
2604     DwNum,
2605     0u,
2606     (UINT32) (BIT0 << PadBitPosition)
2607     );
2608 
2609   return EFI_SUCCESS;
2610 }
2611 
2612 /**
2613   This procedure is used to read GPE STS for a specified Pad
2614 
2615   @param[in]  GpioPad             GPIO pad
2616   @param[out] Data                GPE STS data
2617 
2618   @retval EFI_SUCCESS             The function completed successfully
2619   @retval EFI_INVALID_PARAMETER   Invalid GpioPad
2620 **/
2621 EFI_STATUS
GpioGetGpiGpeSts(IN GPIO_PAD GpioPad,OUT UINT32 * Data)2622 GpioGetGpiGpeSts (
2623   IN GPIO_PAD                  GpioPad,
2624   OUT UINT32                   *Data
2625   )
2626 {
2627   UINT32               GpeStsRegVal;
2628   GPIO_GROUP           Group;
2629   UINT32               PadNumber;
2630   UINT32               DwNum;
2631   UINT32               PadBitPosition;
2632 
2633   if (!GpioIsPadValid (GpioPad)) {
2634     return EFI_UNSUPPORTED;
2635   }
2636 
2637   //
2638   // Check for 2-tier
2639   //
2640   if (!(GpioCheckFor2Tier (GpioPad))) {
2641     return EFI_INVALID_PARAMETER;
2642   }
2643 
2644   Group = GpioGetGroupFromGpioPad (GpioPad);
2645   PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
2646   DwNum = GPIO_GET_DW_NUM (PadNumber);
2647   PadBitPosition = GPIO_GET_PAD_POSITION (PadNumber);
2648 
2649   //
2650   // Read GPI GPE Status bits
2651   //
2652   GpioReadReg (
2653     GpioGpeStatusRegister,
2654     Group,
2655     DwNum,
2656     &GpeStsRegVal
2657     );
2658 
2659   *Data = (GpeStsRegVal >> PadBitPosition) & 0x1;
2660 
2661   return EFI_SUCCESS;
2662 }
2663 
2664 /**
2665   This procedure is used to lock all GPIO pads except the ones
2666   which were requested during their configuration to be left unlocked.
2667   This function must be called before BIOS_DONE - before POSTBOOT_SAI is enabled.
2668     FSP - call this function from wrapper before transition to FSP-S
2669     UEFI/EDK - call this function before EndOfPei event
2670 
2671   @retval EFI_SUCCESS             The function completed successfully
2672   @retval EFI_INVALID_PARAMETER   Invalid group or pad number
2673 **/
2674 EFI_STATUS
GpioLockPads(VOID)2675 GpioLockPads (
2676   VOID
2677   )
2678 {
2679   UINT32         DwNum;
2680   GPIO_GROUP     Group;
2681   GPIO_GROUP     GroupMin;
2682   GPIO_GROUP     GroupMax;
2683   UINT32         UnlockedPads;
2684   EFI_STATUS     Status;
2685 
2686   GroupMin = GpioGetLowestGroup ();
2687   GroupMax = GpioGetHighestGroup ();
2688 
2689   for (Group = GroupMin; Group <= GroupMax; Group++) {
2690     for (DwNum = 0; DwNum <= GPIO_GET_DW_NUM (GpioGetPadPerGroup (Group)); DwNum++) {
2691 
2692       UnlockedPads = GpioGetGroupDwUnlockPadConfigMask (GpioGetGroupIndexFromGroup (Group), DwNum);
2693 
2694       Status = GpioLockPadCfgForGroupDw (Group, DwNum, (UINT32)~UnlockedPads);
2695       if (EFI_ERROR (Status)) {
2696         ASSERT (FALSE);
2697         return Status;
2698       }
2699 
2700       UnlockedPads = GpioGetGroupDwUnlockOutputMask (GpioGetGroupIndexFromGroup (Group), DwNum);
2701 
2702       Status = GpioLockPadCfgTxForGroupDw (Group, DwNum, (UINT32)~UnlockedPads);
2703       if (EFI_ERROR (Status)) {
2704         ASSERT (FALSE);
2705         return Status;
2706       }
2707     }
2708   }
2709   return EFI_SUCCESS;
2710 }
2711