superio/nuvoton/nct5104d: Add virtual LDN for simple GPIO IO control

Now, Super I/O GPIOs can also be controlled directly through
access to I/O registers. VLDN 108 and specific I/O port from a range
<100h; ff8h> may be enabled in mainboard devicetree.

Change-Id: I4ce99bb44e6f5db684170f4190bdc38a944849f6
Signed-off-by: Piotr Kleinschmidt <piotr.kleinschmidt@3mdeb.com>
Signed-off-by: Michał Żygowski <michal.zygowski@3mdeb.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/35849
Reviewed-by: Felix Held <felix-coreboot@felixheld.de>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
diff --git a/src/superio/nuvoton/nct5104d/nct5104d.h b/src/superio/nuvoton/nct5104d/nct5104d.h
index 9a88105..3f78c1d 100644
--- a/src/superio/nuvoton/nct5104d/nct5104d.h
+++ b/src/superio/nuvoton/nct5104d/nct5104d.h
@@ -40,7 +40,6 @@
 #define NCT5104D_FDC        0x00 /* FDC - not pinned out */
 #define NCT5104D_SP1        0x02 /* UARTA */
 #define NCT5104D_SP2        0x03 /* UARTB */
-#define NCT5104D_GPIO_WDT   0x08 /* GPIO WDT Interface */
 #define NCT5104D_GPIO_PP_OD 0x0F /* GPIO Push-Pull / Open drain select  */
 #define NCT5104D_SP3        0x10 /* UARTC */
 #define NCT5104D_SP4        0x11 /* UARTD */
@@ -48,6 +47,7 @@
 
 /* Virtual Logical Device Numbers (LDN) */
 #define NCT5104D_GPIO_V 0x07 /* GPIO - 0,1,6 Interface */
+#define NCT5104D_GPIO_WDT_V 0x08 /* GPIO/WDT Interface */
 
 /* Virtual devices sharing the enables are encoded as follows:
 	VLDN = baseLDN[7:0] | [10:8] bitpos of enable in 0x30 of baseLDN
@@ -56,6 +56,9 @@
 #define NCT5104D_GPIO1 ((1 << 8) | NCT5104D_GPIO_V)
 #define NCT5104D_GPIO6 ((6 << 8) | NCT5104D_GPIO_V)
 
+#define NCT5104D_GPIO_WDT ((0 << 8) | NCT5104D_GPIO_WDT_V)
+#define NCT5104D_GPIO_IO  ((1 << 8) | NCT5104D_GPIO_WDT_V)
+
 void nct5104d_enable_uartd(pnp_devfn_t dev);
 
 #endif /* SUPERIO_NUVOTON_NCT5104D_H */
diff --git a/src/superio/nuvoton/nct5104d/superio.c b/src/superio/nuvoton/nct5104d/superio.c
index 69f54a7..6836d69 100644
--- a/src/superio/nuvoton/nct5104d/superio.c
+++ b/src/superio/nuvoton/nct5104d/superio.c
@@ -14,7 +14,9 @@
  * GNU General Public License for more details.
  */
 
+#include <console/console.h>
 #include <device/pnp.h>
+#include <device/device.h>
 #include <superio/conf_mode.h>
 
 #include "nct5104d.h"
@@ -147,6 +149,29 @@
 		pnp_write_config(dev, NCT5104D_GPIO6_PP_OD, 0xFF);
 }
 
+static void disable_gpio_io_port(struct device *dev)
+{
+	struct device *gpio0, *gpio1, *gpio6;
+
+	/*
+	 * Since UARTC and UARTD share pins with GPIO0 and GPIO1 and the
+	 * GPIO/UART can be selected via Kconfig, check whether at least one of
+	 * GPIOs is enabled and if yes keep the GPIO IO VLDN enabled. If no
+	 * GPIOs are enabled, disable the VLDN in order to protect from invalid
+	 * devicetree + Kconfig settings.
+	 */
+	gpio0 = dev_find_slot_pnp(dev->path.pnp.port, NCT5104D_GPIO0);
+	gpio1 = dev_find_slot_pnp(dev->path.pnp.port, NCT5104D_GPIO1);
+	gpio6 = dev_find_slot_pnp(dev->path.pnp.port, NCT5104D_GPIO6);
+
+	if (!((gpio0 && gpio0->enabled) || (gpio1 && gpio1->enabled) ||
+	      (gpio6 && gpio6->enabled))) {
+		dev->enabled = 0;
+		printk(BIOS_WARNING, "WARNING: GPIO IO port configured,"
+				     " but no GPIO enabled. Disabling...");
+	}
+}
+
 static void nct5104d_init(struct device *dev)
 {
 	struct superio_nuvoton_nct5104d_config *conf = dev->chip_info;
@@ -177,6 +202,9 @@
 	case NCT5104D_GPIO_PP_OD:
 		reset_gpio_default_od(dev);
 		break;
+	case NCT5104D_GPIO_IO:
+		disable_gpio_io_port(dev);
+		break;
 	default:
 		break;
 	}
@@ -204,6 +232,7 @@
 	{ NULL, NCT5104D_GPIO1},
 	{ NULL, NCT5104D_GPIO6},
 	{ NULL, NCT5104D_GPIO_PP_OD},
+	{ NULL, NCT5104D_GPIO_IO, PNP_IO0, 0x07f8, },
 	{ NULL, NCT5104D_PORT80},
 };