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