drivers/i2c/ptn3460: Add early init option

Create Kconfig options and boot state machine callback in ramstage for
an early initialization of the PTN3460 DP-to-LVDS bridge. This allows
showing the bootsplash screen on mainboards utilizing this chip during
the PCI device enumeration.

BUG=none
TEST=Select PTN3460_EARLY_INIT config switch in mainboard Kconfig and
check the log for "Attempting PTN3460 early init" message. If the
board (e.g. siemens/mc_apl7 in this case) is also configured for
showing the bootsplash logo, it should be now visible.

Change-Id: I5424d062b3fb63c78cfced3971376353be11c504
Signed-off-by: Jan Samek <jan.samek@siemens.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/67681
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-by: Uwe Poeche <uwe.poeche@siemens.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
diff --git a/src/drivers/i2c/ptn3460/Kconfig b/src/drivers/i2c/ptn3460/Kconfig
index 6dcdbc0..6d3ca2d 100644
--- a/src/drivers/i2c/ptn3460/Kconfig
+++ b/src/drivers/i2c/ptn3460/Kconfig
@@ -3,3 +3,17 @@
 	default n
 	help
 	  Enable support for external display bridge (eDP to LVDS) PTN3460.
+
+config PTN3460_EARLY_INIT
+	bool
+	default n
+	depends on DRIVERS_I2C_PTN3460
+	help
+	  Enable early initialization of the PTN3460 DP-to-LVDS bridge
+
+config PTN3460_EARLY_ADDR
+	hex
+	default 0x60
+	depends on PTN3460_EARLY_INIT
+	help
+	  I2C address for early initialization of the PTN3460 DP-to-LVDS bridge
diff --git a/src/drivers/i2c/ptn3460/ptn3460.c b/src/drivers/i2c/ptn3460/ptn3460.c
index 98a3432..25ed98a 100644
--- a/src/drivers/i2c/ptn3460/ptn3460.c
+++ b/src/drivers/i2c/ptn3460/ptn3460.c
@@ -3,6 +3,7 @@
 #include <console/console.h>
 #include <device/i2c_bus.h>
 #include <types.h>
+#include <bootstate.h>
 
 #include "ptn3460.h"
 
@@ -65,6 +66,14 @@
 	uint8_t edid_data[PTN_EDID_LEN], edid_tab, *ptr = (uint8_t *) &cfg;
 	int i, val;
 
+	/* Guard against re-initialization of the device */
+	static bool init_done = false;
+
+	if (init_done) {
+		printk(BIOS_DEBUG, "Skipping PTN3460 init as it's already initialized\n");
+		return;
+	}
+
 	/* Mainboard provides EDID data. */
 	if (mb_get_edid(edid_data) != CB_SUCCESS) {
 		printk(BIOS_ERR, "PTN3460 error: Unable to get EDID data from mainboard.\n");
@@ -109,6 +118,8 @@
 			}
 		}
 	}
+
+	init_done = true;
 }
 
 __weak enum cb_err mb_get_edid(uint8_t edid_data[0x80])
@@ -139,3 +150,30 @@
 	CHIP_NAME("PTN3460")
 	.enable_dev = ptn3460_enable
 };
+
+#if CONFIG(PTN3460_EARLY_INIT)
+
+/**
+ * \brief This function provides a callback for the boot state machine to initialize the
+ *        PTN3460 DP-to-LVDS bridge before graphics initialization in order for the bootsplash
+ *        logo to be shown.
+ * @param  *unused	Unused argument for the callback.
+ */
+
+static void ptn3460_early_init(void *unused)
+{
+	struct device *ptn_dev;
+
+	printk(BIOS_DEBUG, "Attempting PTN3460 early init.\n");
+	ptn_dev = dev_find_slot_on_smbus(0, CONFIG_PTN3460_EARLY_ADDR);
+	if (!ptn_dev) {
+		printk(BIOS_ERR, "Failed to find the PTN3460 device!\n");
+		return;
+	}
+
+	ptn3460_init(ptn_dev);
+}
+
+BOOT_STATE_INIT_ENTRY(BS_DEV_INIT, BS_ON_ENTRY, ptn3460_early_init, NULL);
+
+#endif /* CONFIG(PTN3460_EARLY_INIT) */