1 /* SPDX-License-Identifier: GPL-2.0-only */
5 #include <device/mmio.h>
6 #include <console/console.h>
7 #include <device/device.h>
8 #include <device/pci.h>
10 #include <soc/iomap.h>
12 #include <soc/soc_util.h>
13 #include <soc/gpio_dnv.h>
15 // Community PadOwnOffset HostOwnOffset
17 // GpiIeOffset GpiGpeStsOffset GpiGpeEnOffset
19 // SmiEnOffset NmiStsOffset NmiEnOffset
21 // PadCfgLockTxOffset PadCfgOffset PadPerGroup
22 static const struct GPIO_GROUP_INFO mGpioGroupInfo
[] = {
23 {PID_GPIOCOM0
, R_PCH_PCR_GPIO_NC_PAD_OWN
, R_PCH_PCR_GPIO_NC_HOSTSW_OWN
,
24 R_PCH_PCR_GPIO_NC_GPI_IS
, R_PCH_PCR_GPIO_NC_GPI_IE
,
25 R_PCH_PCR_GPIO_NC_GPI_GPE_STS
, R_PCH_PCR_GPIO_NC_GPI_GPE_EN
,
26 R_PCH_PCR_GPIO_NC_SMI_STS
, R_PCH_PCR_GPIO_NC_SMI_EN
,
27 R_PCH_PCR_GPIO_NC_NMI_STS
, R_PCH_PCR_GPIO_NC_NMI_EN
,
28 R_PCH_PCR_GPIO_NC_PADCFGLOCK
, R_PCH_PCR_GPIO_NC_PADCFGLOCKTX
,
29 R_PCH_PCR_GPIO_NC_PADCFG_OFFSET
,
30 V_PCH_GPIO_NC_PAD_MAX
}, // DNV NORTH_ALL
31 {PID_GPIOCOM1
, R_PCH_PCR_GPIO_SC_DFX_PAD_OWN
,
32 R_PCH_PCR_GPIO_SC_DFX_HOSTSW_OWN
, R_PCH_PCR_GPIO_SC_DFX_GPI_IS
,
33 R_PCH_PCR_GPIO_SC_DFX_GPI_IE
, R_PCH_PCR_GPIO_SC_DFX_GPI_GPE_STS
,
34 R_PCH_PCR_GPIO_SC_DFX_GPI_GPE_EN
, NO_REGISTER_FOR_PROPERTY
,
35 NO_REGISTER_FOR_PROPERTY
, NO_REGISTER_FOR_PROPERTY
,
36 NO_REGISTER_FOR_PROPERTY
, R_PCH_PCR_GPIO_SC_DFX_PADCFGLOCK
,
37 R_PCH_PCR_GPIO_SC_DFX_PADCFGLOCKTX
,
38 R_PCH_PCR_GPIO_SC_DFX_PADCFG_OFFSET
,
39 V_PCH_GPIO_SC_DFX_PAD_MAX
}, // DNV SOUTH_DFX
40 {PID_GPIOCOM1
, R_PCH_PCR_GPIO_SC0_PAD_OWN
,
41 R_PCH_PCR_GPIO_SC0_HOSTSW_OWN
, R_PCH_PCR_GPIO_SC0_GPI_IS
,
42 R_PCH_PCR_GPIO_SC0_GPI_IE
, R_PCH_PCR_GPIO_SC0_GPI_GPE_STS
,
43 R_PCH_PCR_GPIO_SC0_GPI_GPE_EN
, R_PCH_PCR_GPIO_SC0_SMI_STS
,
44 R_PCH_PCR_GPIO_SC0_SMI_EN
, R_PCH_PCR_GPIO_SC0_NMI_STS
,
45 R_PCH_PCR_GPIO_SC0_NMI_EN
, R_PCH_PCR_GPIO_SC0_PADCFGLOCK
,
46 R_PCH_PCR_GPIO_SC0_PADCFGLOCKTX
, R_PCH_PCR_GPIO_SC0_PADCFG_OFFSET
,
47 V_PCH_GPIO_SC0_PAD_MAX
}, // DNV South Community 0
48 {PID_GPIOCOM1
, R_PCH_PCR_GPIO_SC1_PAD_OWN
,
49 R_PCH_PCR_GPIO_SC1_HOSTSW_OWN
, R_PCH_PCR_GPIO_SC1_GPI_IS
,
50 R_PCH_PCR_GPIO_SC1_GPI_IE
, R_PCH_PCR_GPIO_SC1_GPI_GPE_STS
,
51 R_PCH_PCR_GPIO_SC1_GPI_GPE_EN
, R_PCH_PCR_GPIO_SC1_SMI_STS
,
52 R_PCH_PCR_GPIO_SC1_SMI_EN
, R_PCH_PCR_GPIO_SC1_NMI_STS
,
53 R_PCH_PCR_GPIO_SC1_NMI_EN
, R_PCH_PCR_GPIO_SC1_PADCFGLOCK
,
54 R_PCH_PCR_GPIO_SC1_PADCFGLOCKTX
, R_PCH_PCR_GPIO_SC1_PADCFG_OFFSET
,
55 V_PCH_GPIO_SC1_PAD_MAX
}, // DNV South Community 1
58 /* Retrieve address and length of GPIO info table */
59 static struct GPIO_GROUP_INFO
*
60 GpioGetGroupInfoTable(uint32_t *GpioGroupInfoTableLength
)
62 *GpioGroupInfoTableLength
= ARRAY_SIZE(mGpioGroupInfo
);
63 return (struct GPIO_GROUP_INFO
*)mGpioGroupInfo
;
66 /* Get Gpio Pad Ownership */
67 static void GpioGetPadOwnership(GPIO_PAD GpioPad
, GPIO_PAD_OWN
*PadOwnVal
)
73 struct GPIO_GROUP_INFO
*GpioGroupInfo
;
74 uint32_t GpioGroupInfoLength
;
75 uint32_t PadOwnRegValue
;
77 GroupIndex
= GPIO_GET_GROUP_INDEX_FROM_PAD(GpioPad
);
78 PadNumber
= GPIO_GET_PAD_NUMBER(GpioPad
);
80 GpioGroupInfo
= GpioGetGroupInfoTable(&GpioGroupInfoLength
);
83 // Check if group argument exceeds GPIO GROUP INFO array
85 if ((uint32_t)GroupIndex
>= GpioGroupInfoLength
) {
86 printk(BIOS_ERR
, "GPIO ERROR: Group argument (%d) exceeds GPIO "
93 // Check if legal pin number
95 if (PadNumber
>= GpioGroupInfo
[GroupIndex
].PadPerGroup
) {
96 printk(BIOS_ERR
, "GPIO ERROR: Pin number (%d) exceeds possible "
97 "range for this group\n",
102 // Calculate RegOffset using Pad Ownership offset and GPIO Pad number.
103 // One DWord register contains information for 8 pads.
106 GpioGroupInfo
[GroupIndex
].PadOwnOffset
+ (PadNumber
>> 3) * 0x4;
109 // Calculate pad bit position within DWord register
112 Mask
= ((1 << 1) | (1 << 0)) << (PadNumber
* 4);
114 PadOwnRegValue
= read32((void *)PCH_PCR_ADDRESS(
115 GpioGroupInfo
[GroupIndex
].Community
, RegOffset
));
117 *PadOwnVal
= (GPIO_PAD_OWN
)((PadOwnRegValue
& Mask
) >> (PadNumber
* 4));
120 void gpio_configure_dnv_pads(const struct dnv_pad_config
*gpio
, size_t num
)
122 /* Return if gpio not valid */
123 if ((gpio
== NULL
) || (num
== 0))
132 uint64_t HostSoftOwnReg
[V_PCH_GPIO_GROUP_MAX
];
133 uint64_t HostSoftOwnRegMask
[V_PCH_GPIO_GROUP_MAX
];
134 uint64_t GpiGpeEnReg
[V_PCH_GPIO_GROUP_MAX
];
135 uint64_t GpiGpeEnRegMask
[V_PCH_GPIO_GROUP_MAX
];
136 struct GPIO_GROUP_INFO
*GpioGroupInfo
;
137 uint32_t GpioGroupInfoLength
;
138 GPIO_PAD GpioGroupOffset
;
139 uint32_t NumberOfGroups
;
140 GPIO_PAD_OWN PadOwnVal
;
141 struct dnv_pad_config
*GpioData
;
147 uint32_t PadMode1
, PadMode2
;
149 PadOwnVal
= GpioPadOwnHost
;
151 memset(HostSoftOwnReg
, 0, sizeof(HostSoftOwnReg
));
152 memset(HostSoftOwnRegMask
, 0, sizeof(HostSoftOwnRegMask
));
153 memset(GpiGpeEnReg
, 0, sizeof(GpiGpeEnReg
));
154 memset(GpiGpeEnRegMask
, 0, sizeof(GpiGpeEnRegMask
));
156 GpioGroupInfo
= GpioGetGroupInfoTable(&GpioGroupInfoLength
);
158 GpioGroupOffset
= GPIO_DNV_GROUP_MIN
;
159 NumberOfGroups
= V_PCH_GPIO_GROUP_MAX
;
161 for (Index
= 0; Index
< (uint32_t)num
; Index
++) {
167 GpioData
= (struct dnv_pad_config
*)&(gpio
[Index
]);
169 Group
= GPIO_GET_GROUP_FROM_PAD(GpioData
->GpioPad
);
170 GroupIndex
= GPIO_GET_GROUP_INDEX_FROM_PAD(GpioData
->GpioPad
);
171 PadNumber
= GPIO_GET_PAD_NUMBER(GpioData
->GpioPad
);
174 // Check if group index argument exceeds GPIO group index range
176 if (GroupIndex
>= V_PCH_GPIO_GROUP_MAX
) {
177 printk(BIOS_ERR
, "GPIO ERROR: Invalid Group Index "
178 "(GroupIndex=%d, Pad=%d)!\n",
179 GroupIndex
, PadNumber
);
184 // Check if group argument exceeds GPIO group range
186 if ((Group
< GpioGroupOffset
) ||
187 (Group
>= NumberOfGroups
+ GpioGroupOffset
)) {
189 "GPIO ERROR: Invalid Group (Group=%d)!\n",
195 // Check if legal pin number
197 if (PadNumber
>= GpioGroupInfo
[GroupIndex
].PadPerGroup
) {
198 printk(BIOS_ERR
, "GPIO ERROR: Invalid PadNumber "
205 // Check if selected GPIO Pad is not owned by CSME/ISH
207 GpioGetPadOwnership(GpioData
->GpioPad
, &PadOwnVal
);
209 if (PadOwnVal
!= GpioPadOwnHost
) {
210 printk(BIOS_ERR
, "GPIO WARNING: Accessing pad not "
211 "owned by host (Group=%d, Pad=%d)!",
212 GroupIndex
, PadNumber
);
213 if (PadOwnVal
== GpioPadOwnCsme
)
214 printk(BIOS_ERR
, "The owner is CSME\n");
215 else if (PadOwnVal
== GpioPadOwnIsh
)
216 printk(BIOS_ERR
, "The owner is ISH\n");
217 printk(BIOS_ERR
, "** Please make sure the GPIO usage "
218 "in sync between CSME/ISH and Host IA "
219 "FW configuration.\n");
220 printk(BIOS_ERR
, "** All the GPIO occupied by CSME/ISH "
221 "should not do any configuration by "
227 // Configure Reset Type (PadRstCfg)
230 ((((GpioData
->GpioConfig
.PowerConfig
&
231 GPIO_CONF_RESET_MASK
) >>
232 GPIO_CONF_RESET_BIT_POS
) == GpioHardwareDefault
)
234 : B_PCH_GPIO_RST_CONF
);
235 Dw0Reg
|= (((GpioData
->GpioConfig
.PowerConfig
&
236 GPIO_CONF_RESET_MASK
) >>
237 (GPIO_CONF_RESET_BIT_POS
+ 1))
238 << N_PCH_GPIO_RST_CONF
);
241 // Configure how interrupt is triggered (RxEvCfg)
244 ((((GpioData
->GpioConfig
.InterruptConfig
&
245 GPIO_CONF_INT_TRIG_MASK
) >>
246 GPIO_CONF_INT_TRIG_BIT_POS
) == GpioHardwareDefault
)
248 : B_PCH_GPIO_RX_LVL_EDG
);
249 Dw0Reg
|= (((GpioData
->GpioConfig
.InterruptConfig
&
250 GPIO_CONF_INT_TRIG_MASK
) >>
251 (GPIO_CONF_INT_TRIG_BIT_POS
+ 1))
252 << N_PCH_GPIO_RX_LVL_EDG
);
255 // Configure interrupt generation (GPIRoutIOxAPIC/SCI/SMI/NMI)
258 ((((GpioData
->GpioConfig
.InterruptConfig
&
259 GPIO_CONF_INT_ROUTE_MASK
) >>
260 GPIO_CONF_INT_ROUTE_BIT_POS
) == GpioHardwareDefault
)
262 : (B_PCH_GPIO_RX_NMI_ROUTE
|
263 B_PCH_GPIO_RX_SCI_ROUTE
|
264 B_PCH_GPIO_RX_SMI_ROUTE
|
265 B_PCH_GPIO_RX_APIC_ROUTE
));
266 Dw0Reg
|= (((GpioData
->GpioConfig
.InterruptConfig
&
267 GPIO_CONF_INT_ROUTE_MASK
) >>
268 (GPIO_CONF_INT_ROUTE_BIT_POS
+ 1))
269 << N_PCH_GPIO_RX_NMI_ROUTE
);
271 // If CFIO is not Working as GPIO mode, Don't move TxDisable and
273 if (GpioData
->GpioConfig
.PadMode
== GpioPadModeGpio
) {
275 // Configure GPIO direction (GPIORxDis and GPIOTxDis)
277 Dw0RegMask
|= ((((GpioData
->GpioConfig
.Direction
&
278 GPIO_CONF_DIR_MASK
) >>
279 GPIO_CONF_DIR_BIT_POS
) ==
282 : (B_PCH_GPIO_RXDIS
|
284 Dw0Reg
|= (((GpioData
->GpioConfig
.Direction
&
285 GPIO_CONF_DIR_MASK
) >>
286 (GPIO_CONF_DIR_BIT_POS
+ 1))
287 << N_PCH_GPIO_TXDIS
);
291 // Configure GPIO input inversion (RXINV)
293 Dw0RegMask
|= ((((GpioData
->GpioConfig
.Direction
&
294 GPIO_CONF_INV_MASK
) >>
295 GPIO_CONF_INV_BIT_POS
) == GpioHardwareDefault
)
298 Dw0Reg
|= (((GpioData
->GpioConfig
.Direction
&
299 GPIO_CONF_INV_MASK
) >>
300 (GPIO_CONF_INV_BIT_POS
+ 1))
301 << N_PCH_GPIO_RXINV
);
304 // Configure GPIO output state (GPIOTxState)
307 ((((GpioData
->GpioConfig
.OutputState
&
308 GPIO_CONF_OUTPUT_MASK
) >>
309 GPIO_CONF_OUTPUT_BIT_POS
) == GpioHardwareDefault
)
311 : B_PCH_GPIO_TX_STATE
);
312 Dw0Reg
|= (((GpioData
->GpioConfig
.OutputState
&
313 GPIO_CONF_OUTPUT_MASK
) >>
314 (GPIO_CONF_OUTPUT_BIT_POS
+ 1))
315 << N_PCH_GPIO_TX_STATE
);
318 // Configure GPIO RX raw override to '1' (RXRAW1)
321 ((((GpioData
->GpioConfig
.OtherSettings
&
322 GPIO_CONF_RXRAW_MASK
) >>
323 GPIO_CONF_RXRAW_BIT_POS
) == GpioHardwareDefault
)
325 : B_PCH_GPIO_RX_RAW1
);
326 Dw0Reg
|= (((GpioData
->GpioConfig
.OtherSettings
&
327 GPIO_CONF_RXRAW_MASK
) >>
328 (GPIO_CONF_RXRAW_BIT_POS
+ 1))
329 << N_PCH_GPIO_RX_RAW1
);
332 // Configure GPIO Pad Mode (PMode)
335 ((((GpioData
->GpioConfig
.PadMode
&
336 GPIO_CONF_PAD_MODE_MASK
) >>
337 GPIO_CONF_PAD_MODE_BIT_POS
) == GpioHardwareDefault
)
339 : B_PCH_GPIO_PAD_MODE
);
340 Dw0Reg
|= (((GpioData
->GpioConfig
.PadMode
&
341 GPIO_CONF_PAD_MODE_MASK
) >>
342 (GPIO_CONF_PAD_MODE_BIT_POS
+ 1))
343 << N_PCH_GPIO_PAD_MODE
);
346 // Configure GPIO termination (Term)
348 Dw1RegMask
|= ((((GpioData
->GpioConfig
.ElectricalConfig
&
349 GPIO_CONF_TERM_MASK
) >>
350 GPIO_CONF_TERM_BIT_POS
) == GpioHardwareDefault
)
353 Dw1Reg
|= (((GpioData
->GpioConfig
.ElectricalConfig
&
354 GPIO_CONF_TERM_MASK
) >>
355 (GPIO_CONF_TERM_BIT_POS
+ 1))
359 // Configure GPIO pad tolerance (padtol)
362 ((((GpioData
->GpioConfig
.ElectricalConfig
&
363 GPIO_CONF_PADTOL_MASK
) >>
364 GPIO_CONF_PADTOL_BIT_POS
) == GpioHardwareDefault
)
366 : B_PCH_GPIO_PADTOL
);
367 Dw1Reg
|= (((GpioData
->GpioConfig
.ElectricalConfig
&
368 GPIO_CONF_PADTOL_MASK
) >>
369 (GPIO_CONF_PADTOL_BIT_POS
+ 1))
370 << N_PCH_GPIO_PADTOL
);
373 // Check for additional requirements on setting PADCFG register
377 // Create PADCFG register offset using group and pad number
379 PadCfgReg
= 0x8 * PadNumber
+
380 GpioGroupInfo
[GroupIndex
].PadCfgOffset
;
381 Data32
= read32((void *)PCH_PCR_ADDRESS(
382 GpioGroupInfo
[GroupIndex
].Community
, PadCfgReg
));
384 FinalValue
= ((Data32
& (~Dw0RegMask
)) | Dw0Reg
);
387 (Data32
& B_PCH_GPIO_PAD_MODE
) >> N_PCH_GPIO_PAD_MODE
;
389 (Dw0Reg
& B_PCH_GPIO_PAD_MODE
) >> N_PCH_GPIO_PAD_MODE
;
391 if (((Data32
& B_PCH_GPIO_PAD_MODE
) !=
392 (FinalValue
& B_PCH_GPIO_PAD_MODE
)) ||
394 printk(BIOS_DEBUG
, "Changing GpioPad PID: %x Offset: "
395 "0x%x PadModeP1: %d P2: %d ",
396 GpioGroupInfo
[GroupIndex
].Community
, PadCfgReg
,
398 printk(BIOS_DEBUG
, "R: 0x%08x Fx%08x !\n", Data32
,
401 // Write PADCFG DW0 register``
404 (void *)(uint32_t)PCH_PCR_ADDRESS(
405 GpioGroupInfo
[GroupIndex
].Community
,
407 ~(uint32_t)Dw0RegMask
, (uint32_t)Dw0Reg
);
410 Data32
= read32((void *)PCH_PCR_ADDRESS(
411 GpioGroupInfo
[GroupIndex
].Community
, PadCfgReg
+ 0x4));
412 FinalValue
= ((Data32
& (~Dw1RegMask
)) | Dw1Reg
);
413 if (Data32
!= FinalValue
) {
415 // Write PADCFG DW1 register
418 (void *)(uint32_t)PCH_PCR_ADDRESS(
419 GpioGroupInfo
[GroupIndex
].Community
,
421 ~(uint32_t)Dw1RegMask
, (uint32_t)Dw1Reg
);
425 // Update value to be programmed in HOSTSW_OWN register
427 HostSoftOwnRegMask
[GroupIndex
] |=
428 ((uint64_t)GpioData
->GpioConfig
.HostSoftPadOwn
& 0x1) << PadNumber
;
429 HostSoftOwnReg
[GroupIndex
] |=
430 ((uint64_t)GpioData
->GpioConfig
.HostSoftPadOwn
>> 0x1) << PadNumber
;
433 // Update value to be programmed in GPI_GPE_EN register
435 GpiGpeEnRegMask
[GroupIndex
] |=
436 ((uint64_t)GpioData
->GpioConfig
.InterruptConfig
& 0x1) << PadNumber
;
437 GpiGpeEnReg
[GroupIndex
] |=
438 (((uint64_t)GpioData
->GpioConfig
.InterruptConfig
& GpioIntSci
) >> 3)
442 for (Index
= 0; Index
< NumberOfGroups
; Index
++) {
444 // Write HOSTSW_OWN registers
446 if (GpioGroupInfo
[Index
].HostOwnOffset
!=
447 NO_REGISTER_FOR_PROPERTY
) {
449 (void *)PCH_PCR_ADDRESS(
450 GpioGroupInfo
[Index
].Community
,
451 GpioGroupInfo
[Index
].HostOwnOffset
),
452 ~(uint32_t)(HostSoftOwnRegMask
[Index
] &
454 (uint32_t)(HostSoftOwnReg
[Index
] & 0xFFFFFFFF));
456 (void *)PCH_PCR_ADDRESS(
457 GpioGroupInfo
[Index
].Community
,
458 GpioGroupInfo
[Index
].HostOwnOffset
+
460 ~(uint32_t)(HostSoftOwnRegMask
[Index
] >> 32),
461 (uint32_t)(HostSoftOwnReg
[Index
] >> 32));
465 // Write GPI_GPE_EN registers
467 if (GpioGroupInfo
[Index
].GpiGpeEnOffset
!=
468 NO_REGISTER_FOR_PROPERTY
) {
470 (void *)PCH_PCR_ADDRESS(
471 GpioGroupInfo
[Index
].Community
,
472 GpioGroupInfo
[Index
].GpiGpeEnOffset
),
473 ~(uint32_t)(GpiGpeEnRegMask
[Index
] &
475 (uint32_t)(GpiGpeEnReg
[Index
] & 0xFFFFFFFF));
477 (void *)PCH_PCR_ADDRESS(
478 GpioGroupInfo
[Index
].Community
,
479 GpioGroupInfo
[Index
].GpiGpeEnOffset
+
481 ~(uint32_t)(GpiGpeEnRegMask
[Index
] >> 32),
482 (uint32_t)(GpiGpeEnReg
[Index
] >> 32));