soc/amd/common: Introduce I2C driver common to all AMD SoCs

I2C driver is replicated in each generation of AMD SoCs. Introduce a
common I2C driver that can be used across all the AMD SoCs. To begin
with, peripheral reset functionality is moved into this common driver.
SoC specific I2C driver passes the SCL pin configuration in order for
the common driver to reset the peripherals. More functionality can be
moved here in subsequent changes.

Also sb_reset_i2c_slaves() is renamed as sb_reset_i2c_peripherals() as
an effort towards using inclusive language.

BUG=None
TEST=Build Dalboz and Grunt. Boot to OS in Dalboz. Ensure that the I2C
peripherals are detected as earlier in Dalboz.
localhost ~ # i2cdetect -y 0
Warning: Can't use SMBus Quick Write command, will skip some addresses
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:
10:
20:
30: -- -- -- -- -- -- -- --
40:
50: 50 51 -- -- -- -- -- -- 58 59 -- -- -- -- -- --
60:
70:
localhost ~ # i2cdetect -y 1
Warning: Can't use SMBus Quick Write command, will skip some addresses
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:
10:
20:
30: -- -- -- -- -- -- -- --
40:
50: UU -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60:
70:

Change-Id: I9f735dcfe8375abdc88ff06e8c4f8a6b741bc085
Signed-off-by: Karthikeyan Ramasubramanian <kramasub@google.com>
Suggested-by: Kyosti Malkki <kyosti.malkki@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/51404
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Mathew King <mathewk@chromium.org>
Reviewed-by: Furquan Shaikh <furquan@google.com>
diff --git a/src/soc/amd/picasso/Kconfig b/src/soc/amd/picasso/Kconfig
index ea9ee5b..1fca390 100644
--- a/src/soc/amd/picasso/Kconfig
+++ b/src/soc/amd/picasso/Kconfig
@@ -34,6 +34,7 @@
 	select SOC_AMD_COMMON_BLOCK_GRAPHICS
 	select SOC_AMD_COMMON_BLOCK_HAS_ESPI
 	select SOC_AMD_COMMON_BLOCK_HDA
+	select SOC_AMD_COMMON_BLOCK_I2C
 	select SOC_AMD_COMMON_BLOCK_IOMMU
 	select SOC_AMD_COMMON_BLOCK_LPC
 	select SOC_AMD_COMMON_BLOCK_NONCAR
diff --git a/src/soc/amd/picasso/chip.h b/src/soc/amd/picasso/chip.h
index 549f033..2944b2a 100644
--- a/src/soc/amd/picasso/chip.h
+++ b/src/soc/amd/picasso/chip.h
@@ -97,9 +97,9 @@
 struct soc_amd_picasso_config {
 	struct soc_amd_common_config common_config;
 	/*
-	 * If sb_reset_i2c_slaves() is called, this devicetree register
+	 * If sb_reset_i2c_peripherals() is called, this devicetree register
 	 * defines which I2C SCL will be toggled 9 times at 100 KHz.
-	 * For example, should we need I2C0 and  I2C3 have their slave
+	 * For example, should we need I2C0 and  I2C3 have their peripheral
 	 * devices reseted by toggling SCL, use:
 	 *
 	 * register i2c_scl_reset = (GPIO_I2C0_SCL | GPIO_I2C3_SCL)
diff --git a/src/soc/amd/picasso/early_fch.c b/src/soc/amd/picasso/early_fch.c
index a9118ad..1aff83b 100644
--- a/src/soc/amd/picasso/early_fch.c
+++ b/src/soc/amd/picasso/early_fch.c
@@ -2,6 +2,7 @@
 
 #include <amdblocks/acpimmio.h>
 #include <amdblocks/espi.h>
+#include <amdblocks/i2c.h>
 #include <amdblocks/lpc.h>
 #include <amdblocks/smbus.h>
 #include <amdblocks/spi.h>
@@ -11,12 +12,32 @@
 #include <soc/uart.h>
 #include <types.h>
 
+#include "chip.h"
+
+/* This table is for the initial conversion of all SCL pins to input with no pull. */
+static const struct soc_i2c_scl_pin i2c_scl_pins[] = {
+	{ PAD_GPI(I2C2_SCL_PIN, PULL_NONE), GPIO_I2C2_SCL },
+	{ PAD_GPI(I2C3_SCL_PIN, PULL_NONE), GPIO_I2C3_SCL },
+	/* I2C4 is a peripheral device only */
+};
+
 static void lpc_configure_decodes(void)
 {
 	if (CONFIG(POST_IO) && (CONFIG_POST_IO_PORT == 0x80))
 		lpc_enable_port80();
 }
 
+static void reset_i2c_peripherals(void)
+{
+	const struct soc_amd_picasso_config *cfg = config_of_soc();
+	struct soc_i2c_peripheral_reset_info reset_info;
+
+	reset_info.i2c_scl_reset_mask = cfg->i2c_scl_reset & GPIO_I2C_MASK;
+	reset_info.i2c_scl = i2c_scl_pins;
+	reset_info.num_pins = ARRAY_SIZE(i2c_scl_pins);
+	sb_reset_i2c_peripherals(&reset_info);
+}
+
 /* Before console init */
 void fch_pre_init(void)
 {
@@ -31,7 +52,7 @@
 	fch_enable_cf9_io();
 	fch_enable_legacy_io();
 	enable_aoac_devices();
-	sb_reset_i2c_slaves();
+	reset_i2c_peripherals();
 
 	/*
 	 * On reset Range_0 defaults to enabled. We want to start with a clean
diff --git a/src/soc/amd/picasso/i2c.c b/src/soc/amd/picasso/i2c.c
index af4c41f..9d01615 100644
--- a/src/soc/amd/picasso/i2c.c
+++ b/src/soc/amd/picasso/i2c.c
@@ -7,6 +7,7 @@
 #include <device/device.h>
 #include <drivers/i2c/designware/dw_i2c.h>
 #include <amdblocks/acpimmio.h>
+#include <amdblocks/i2c.h>
 #include <soc/i2c.h>
 #include <soc/iomap.h>
 #include <soc/pci_devs.h>
@@ -141,81 +142,3 @@
 	.acpi_name = i2c_acpi_name,
 	.acpi_fill_ssdt = dw_i2c_acpi_fill_ssdt,
 };
-
-/*
- * I2C pins are open drain with external pull up, so in order to bit bang them
- * all, SCL pins must become GPIO inputs with no pull, then they need to be
- * toggled between input-no-pull and output-low. This table is for the initial
- * conversion of all SCL pins to input with no pull.
- */
-static const struct soc_amd_gpio i2c_2_gpi[] = {
-	PAD_GPI(I2C2_SCL_PIN, PULL_NONE),
-	PAD_GPI(I2C3_SCL_PIN, PULL_NONE),
-	/* I2C4 is a slave device only */
-};
-#define saved_pins_count ARRAY_SIZE(i2c_2_gpi)
-
-/*
- * To program I2C pins without destroying their programming, the registers
- * that will be changed need to be saved first.
- */
-static void save_i2c_pin_registers(uint8_t gpio,
-					struct soc_amd_i2c_save *save_table)
-{
-	save_table->mux_value = iomux_read8(gpio);
-	save_table->control_value = gpio_read32(gpio);
-}
-
-static void restore_i2c_pin_registers(uint8_t gpio,
-					struct soc_amd_i2c_save *save_table)
-{
-	/* Write and flush posted writes. */
-	iomux_write8(gpio, save_table->mux_value);
-	iomux_read8(gpio);
-	gpio_write32(gpio, save_table->control_value);
-	gpio_read32(gpio);
-}
-
-/* Slaves to be reset are controlled by devicetree register i2c_scl_reset */
-void sb_reset_i2c_slaves(void)
-{
-	const struct soc_amd_picasso_config *cfg;
-	struct soc_amd_i2c_save save_table[saved_pins_count];
-	uint8_t i, j, control;
-
-	cfg = config_of_soc();
-	control = cfg->i2c_scl_reset & GPIO_I2C_MASK;
-	if (control == 0)
-		return;
-
-	/* Save and reprogram I2C SCL pins */
-	for (i = 0; i < saved_pins_count; i++)
-		save_i2c_pin_registers(i2c_2_gpi[i].gpio, &save_table[i]);
-	program_gpios(i2c_2_gpi, saved_pins_count);
-
-	/*
-	 * Toggle SCL back and forth 9 times under 100KHz. A single read is
-	 * needed after the writes to force the posted write to complete.
-	 */
-	for (j = 0; j < 9; j++) {
-		if (control & GPIO_I2C2_SCL)
-			gpio_write32(I2C2_SCL_PIN, GPIO_OUTPUT_ENABLE);
-		if (control & GPIO_I2C3_SCL)
-			gpio_write32(I2C3_SCL_PIN, GPIO_OUTPUT_ENABLE);
-
-		gpio_read32(0); /* Flush posted write */
-		udelay(4); /* 4usec gets 85KHz for 1 pin, 70KHz for 4 pins */
-
-		if (control & GPIO_I2C2_SCL)
-			gpio_write32(I2C2_SCL_PIN, 0);
-		if (control & GPIO_I2C3_SCL)
-			gpio_write32(I2C3_SCL_PIN, 0);
-
-		gpio_read32(0); /* Flush posted write */
-		udelay(4);
-	}
-
-	/* Restore I2C pins. */
-	for (i = 0; i < saved_pins_count; i++)
-		restore_i2c_pin_registers(i2c_2_gpi[i].gpio, &save_table[i]);
-}
diff --git a/src/soc/amd/picasso/include/soc/i2c.h b/src/soc/amd/picasso/include/soc/i2c.h
index 41b930b..f62cb11 100644
--- a/src/soc/amd/picasso/include/soc/i2c.h
+++ b/src/soc/amd/picasso/include/soc/i2c.h
@@ -6,11 +6,6 @@
 #include <types.h>
 #include <soc/gpio.h>
 
-struct soc_amd_i2c_save {
-	uint32_t control_value;
-	uint8_t mux_value;
-};
-
 #define GPIO_I2C2_SCL		BIT(2)
 #define GPIO_I2C3_SCL		BIT(3)
 #define GPIO_I2C_MASK		(BIT(2) | BIT(3))
@@ -28,8 +23,6 @@
 #define USB_PD_RFMUX_OVERRIDE	BIT(8)
 #define USB_PD_DP_OVERRIDE	BIT(9)
 
-void sb_reset_i2c_slaves(void);
-
 /* Sets the base address for the specific I2C bus. */
 void i2c_set_bar(unsigned int bus, uintptr_t bar);