soc/amd/glinda: Update MCA banks
[coreboot2.git] / src / soc / intel / denverton_ns / gpio_dnv.c
blob05260bfe16ed9a884aa4395c027d86af6726c93f
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <stdint.h>
4 #include <string.h>
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>
11 #include <soc/pcr.h>
12 #include <soc/soc_util.h>
13 #include <soc/gpio_dnv.h>
15 // Community PadOwnOffset HostOwnOffset
16 // GpiIsOffset
17 // GpiIeOffset GpiGpeStsOffset GpiGpeEnOffset
18 // SmiStsOffset
19 // SmiEnOffset NmiStsOffset NmiEnOffset
20 // PadCfgLockOffset
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)
69 uint32_t Mask;
70 uint32_t RegOffset;
71 uint32_t GroupIndex;
72 uint32_t PadNumber;
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 "
87 "group range\n",
88 GroupIndex);
89 return;
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",
98 PadNumber);
99 return;
102 // Calculate RegOffset using Pad Ownership offset and GPIO Pad number.
103 // One DWord register contains information for 8 pads.
105 RegOffset =
106 GpioGroupInfo[GroupIndex].PadOwnOffset + (PadNumber >> 3) * 0x4;
109 // Calculate pad bit position within DWord register
111 PadNumber %= 8;
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))
124 return;
126 uint32_t Index;
127 uint32_t Dw0Reg;
128 uint32_t Dw0RegMask;
129 uint32_t Dw1Reg;
130 uint32_t Dw1RegMask;
131 uint32_t PadCfgReg;
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;
142 GPIO_PAD Group;
143 uint32_t GroupIndex;
144 uint32_t PadNumber;
145 uint32_t FinalValue;
146 uint32_t Data32;
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++) {
162 Dw0RegMask = 0;
163 Dw0Reg = 0;
164 Dw1RegMask = 0;
165 Dw1Reg = 0;
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);
180 continue;
184 // Check if group argument exceeds GPIO group range
186 if ((Group < GpioGroupOffset) ||
187 (Group >= NumberOfGroups + GpioGroupOffset)) {
188 printk(BIOS_ERR,
189 "GPIO ERROR: Invalid Group (Group=%d)!\n",
190 Group);
191 return;
195 // Check if legal pin number
197 if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup) {
198 printk(BIOS_ERR, "GPIO ERROR: Invalid PadNumber "
199 "(PadNumber=%d)!\n",
200 PadNumber);
201 return;
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 "
222 "Host IA FW.\n");
223 continue;
227 // Configure Reset Type (PadRstCfg)
229 Dw0RegMask |=
230 ((((GpioData->GpioConfig.PowerConfig &
231 GPIO_CONF_RESET_MASK) >>
232 GPIO_CONF_RESET_BIT_POS) == GpioHardwareDefault)
233 ? 0x0
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)
243 Dw0RegMask |=
244 ((((GpioData->GpioConfig.InterruptConfig &
245 GPIO_CONF_INT_TRIG_MASK) >>
246 GPIO_CONF_INT_TRIG_BIT_POS) == GpioHardwareDefault)
247 ? 0x0
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)
257 Dw0RegMask |=
258 ((((GpioData->GpioConfig.InterruptConfig &
259 GPIO_CONF_INT_ROUTE_MASK) >>
260 GPIO_CONF_INT_ROUTE_BIT_POS) == GpioHardwareDefault)
261 ? 0x0
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
272 // RxDisable
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) ==
280 GpioHardwareDefault)
281 ? 0x0
282 : (B_PCH_GPIO_RXDIS |
283 B_PCH_GPIO_TXDIS));
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)
296 ? 0x0
297 : B_PCH_GPIO_RXINV);
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)
306 Dw0RegMask |=
307 ((((GpioData->GpioConfig.OutputState &
308 GPIO_CONF_OUTPUT_MASK) >>
309 GPIO_CONF_OUTPUT_BIT_POS) == GpioHardwareDefault)
310 ? 0x0
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)
320 Dw0RegMask |=
321 ((((GpioData->GpioConfig.OtherSettings &
322 GPIO_CONF_RXRAW_MASK) >>
323 GPIO_CONF_RXRAW_BIT_POS) == GpioHardwareDefault)
324 ? 0x0
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)
334 Dw0RegMask |=
335 ((((GpioData->GpioConfig.PadMode &
336 GPIO_CONF_PAD_MODE_MASK) >>
337 GPIO_CONF_PAD_MODE_BIT_POS) == GpioHardwareDefault)
338 ? 0x0
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)
351 ? 0x0
352 : B_PCH_GPIO_TERM);
353 Dw1Reg |= (((GpioData->GpioConfig.ElectricalConfig &
354 GPIO_CONF_TERM_MASK) >>
355 (GPIO_CONF_TERM_BIT_POS + 1))
356 << N_PCH_GPIO_TERM);
359 // Configure GPIO pad tolerance (padtol)
361 Dw1RegMask |=
362 ((((GpioData->GpioConfig.ElectricalConfig &
363 GPIO_CONF_PADTOL_MASK) >>
364 GPIO_CONF_PADTOL_BIT_POS) == GpioHardwareDefault)
365 ? 0x0
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);
386 PadMode1 =
387 (Data32 & B_PCH_GPIO_PAD_MODE) >> N_PCH_GPIO_PAD_MODE;
388 PadMode2 =
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)) ||
393 (PadMode2 == 0)) {
394 printk(BIOS_DEBUG, "Changing GpioPad PID: %x Offset: "
395 "0x%x PadModeP1: %d P2: %d ",
396 GpioGroupInfo[GroupIndex].Community, PadCfgReg,
397 PadMode1, PadMode2);
398 printk(BIOS_DEBUG, "R: 0x%08x Fx%08x !\n", Data32,
399 FinalValue);
401 // Write PADCFG DW0 register``
403 mmio_andthenor32(
404 (void *)(uint32_t)PCH_PCR_ADDRESS(
405 GpioGroupInfo[GroupIndex].Community,
406 PadCfgReg),
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
417 mmio_andthenor32(
418 (void *)(uint32_t)PCH_PCR_ADDRESS(
419 GpioGroupInfo[GroupIndex].Community,
420 PadCfgReg + 0x4),
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)
439 << PadNumber;
442 for (Index = 0; Index < NumberOfGroups; Index++) {
444 // Write HOSTSW_OWN registers
446 if (GpioGroupInfo[Index].HostOwnOffset !=
447 NO_REGISTER_FOR_PROPERTY) {
448 mmio_andthenor32(
449 (void *)PCH_PCR_ADDRESS(
450 GpioGroupInfo[Index].Community,
451 GpioGroupInfo[Index].HostOwnOffset),
452 ~(uint32_t)(HostSoftOwnRegMask[Index] &
453 0xFFFFFFFF),
454 (uint32_t)(HostSoftOwnReg[Index] & 0xFFFFFFFF));
455 mmio_andthenor32(
456 (void *)PCH_PCR_ADDRESS(
457 GpioGroupInfo[Index].Community,
458 GpioGroupInfo[Index].HostOwnOffset +
459 0x4),
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) {
469 mmio_andthenor32(
470 (void *)PCH_PCR_ADDRESS(
471 GpioGroupInfo[Index].Community,
472 GpioGroupInfo[Index].GpiGpeEnOffset),
473 ~(uint32_t)(GpiGpeEnRegMask[Index] &
474 0xFFFFFFFF),
475 (uint32_t)(GpiGpeEnReg[Index] & 0xFFFFFFFF));
476 mmio_andthenor32(
477 (void *)PCH_PCR_ADDRESS(
478 GpioGroupInfo[Index].Community,
479 GpioGroupInfo[Index].GpiGpeEnOffset +
480 0x4),
481 ~(uint32_t)(GpiGpeEnRegMask[Index] >> 32),
482 (uint32_t)(GpiGpeEnReg[Index] >> 32));