soc/amd/genoa: add I2C support

The Genoa SoC has 6 I2C controllers. In order to support those, select
SOC_AMD_COMMON_BLOCK_I2C and implement the SoC-specific functions and
data structures needed by the common AMD I2C code. Since the common AMD
I2C code also reports if the controller is enabled or not in the SSDT,
change the corresponding DSDT code to use this information. In this
patch the I2C pad control registers don't get configured by coreboot yet
and we rely on ABL already having those set up correctly which seems to
be an assumption that the reference firmware is making too. PPR #55901
Rev 0.26 was used as a reference for the I2C controllers and the GPIO
pins being used.

Signed-off-by: Felix Held <felix-coreboot@felixheld.de>
Change-Id: Iebc10de6ea5c6d441cff04e016dcec62405078c3
Reviewed-on: https://review.coreboot.org/c/coreboot/+/78900
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Varshit Pandya <pandyavarshit@gmail.com>
diff --git a/src/soc/amd/genoa/Kconfig b/src/soc/amd/genoa/Kconfig
index 210b3e5..cbf0ddd 100644
--- a/src/soc/amd/genoa/Kconfig
+++ b/src/soc/amd/genoa/Kconfig
@@ -20,6 +20,7 @@
 	select SOC_AMD_COMMON_BLOCK_DATA_FABRIC_MULTI_PCI_SEGMENT
 	select SOC_AMD_COMMON_BLOCK_DATA_FABRIC_EXTENDED_MMIO
 	select SOC_AMD_COMMON_BLOCK_HAS_ESPI
+	select SOC_AMD_COMMON_BLOCK_I2C
 	select SOC_AMD_COMMON_BLOCK_IOMMU
 	select SOC_AMD_COMMON_BLOCK_LPC
 	select SOC_AMD_COMMON_BLOCK_MCAX
@@ -43,6 +44,10 @@
 	string
 	default "soc/amd/genoa/chipset.cb"
 
+config DRIVERS_I2C_DESIGNWARE_CLOCK_MHZ
+	int
+	default 150
+
 config EARLY_RESERVED_DRAM_BASE
 	hex
 	default 0x7000000
diff --git a/src/soc/amd/genoa/Makefile.inc b/src/soc/amd/genoa/Makefile.inc
index 33a4061..4b47886 100644
--- a/src/soc/amd/genoa/Makefile.inc
+++ b/src/soc/amd/genoa/Makefile.inc
@@ -5,6 +5,7 @@
 all-y		+= reset.c
 all-y		+= config.c
 all-y		+= gpio.c
+all-y		+= i2c.c
 all-y		+= uart.c
 
 bootblock-y	+= early_fch.c
diff --git a/src/soc/amd/genoa/acpi/mmio.asl b/src/soc/amd/genoa/acpi/mmio.asl
index 8ef61a7..9b5e1d2 100644
--- a/src/soc/amd/genoa/acpi/mmio.asl
+++ b/src/soc/amd/genoa/acpi/mmio.asl
@@ -195,9 +195,10 @@
 		}
 	}
 
+	Name (STAT, 0x0)
 	Method (_STA, 0x0, NotSerialized)
 	{
-		Return (0x0F)
+		Return (STAT)
 	}
 
 	AOAC_DEVICE(FCH_AOAC_DEV_I2C0, 0)
@@ -231,9 +232,10 @@
 		}
 	}
 
+	Name (STAT, 0x0)
 	Method (_STA, 0x0, NotSerialized)
 	{
-		Return (0x0F)
+		Return (STAT)
 	}
 
 	AOAC_DEVICE(FCH_AOAC_DEV_I2C1, 0)
@@ -267,9 +269,10 @@
 		}
 	}
 
+	Name (STAT, 0x0)
 	Method (_STA, 0x0, NotSerialized)
 	{
-		Return (0x0F)
+		Return (STAT)
 	}
 
 	AOAC_DEVICE(FCH_AOAC_DEV_I2C2, 0)
@@ -303,9 +306,11 @@
 			Return (Local0)
 		}
 	}
+
+	Name (STAT, 0x0)
 	Method (_STA, 0x0, NotSerialized)
 	{
-		Return (0x0F)
+		Return (STAT)
 	}
 
 	AOAC_DEVICE(FCH_AOAC_DEV_I2C3, 0)
@@ -339,9 +344,11 @@
 			Return (Local0)
 		}
 	}
+
+	Name (STAT, 0x0)
 	Method (_STA, 0x0, NotSerialized)
 	{
-		Return (0x0F)
+		Return (STAT)
 	}
 
 	AOAC_DEVICE(FCH_AOAC_DEV_I2C4, 0)
@@ -375,9 +382,11 @@
 			Return (Local0)
 		}
 	}
+
+	Name (STAT, 0x0)
 	Method (_STA, 0x0, NotSerialized)
 	{
-		Return (0x0F)
+		Return (STAT)
 	}
 
 	AOAC_DEVICE(FCH_AOAC_DEV_I2C5, 0)
diff --git a/src/soc/amd/genoa/chip.h b/src/soc/amd/genoa/chip.h
index 9168586..bca40af 100644
--- a/src/soc/amd/genoa/chip.h
+++ b/src/soc/amd/genoa/chip.h
@@ -4,9 +4,16 @@
 #define __GENOA_CHIP_H__
 
 #include <amdblocks/chip.h>
+#include <amdblocks/i2c.h>
+#include <drivers/i2c/designware/dw_i2c.h>
+#include <soc/iomap.h>
+#include <types.h>
 
 struct soc_amd_genoa_config {
 	struct soc_amd_common_config common_config;
+
+	u8 i2c_scl_reset;
+	struct dw_i2c_bus_config i2c[I2C_CTRLR_COUNT];
 };
 
 #endif
diff --git a/src/soc/amd/genoa/chipset.cb b/src/soc/amd/genoa/chipset.cb
index 58c1156..0f543e7 100644
--- a/src/soc/amd/genoa/chipset.cb
+++ b/src/soc/amd/genoa/chipset.cb
@@ -207,12 +207,12 @@
 		end
 	end
 
-	device mmio 0xfedc2000 alias i2c_0 off end
-	device mmio 0xfedc3000 alias i2c_1 off end
-	device mmio 0xfedc4000 alias i2c_2 off end
-	device mmio 0xfedc5000 alias i2c_3 off end
-	device mmio 0xfedc6000 alias i2c_4 off end
-	device mmio 0xfedcb000 alias i2c_5 off end
+	device mmio 0xfedc2000 alias i2c_0 off ops soc_amd_i2c_mmio_ops end
+	device mmio 0xfedc3000 alias i2c_1 off ops soc_amd_i2c_mmio_ops end
+	device mmio 0xfedc4000 alias i2c_2 off ops soc_amd_i2c_mmio_ops end
+	device mmio 0xfedc5000 alias i2c_3 off ops soc_amd_i2c_mmio_ops end
+	device mmio 0xfedc6000 alias i2c_4 off ops soc_amd_i2c_mmio_ops end
+	device mmio 0xfedcb000 alias i2c_5 off ops soc_amd_i2c_mmio_ops end
 	device mmio 0xfedc9000 alias uart_0 off ops amd_uart_mmio_ops end
 	device mmio 0xfedca000 alias uart_1 off ops amd_uart_mmio_ops end
 	device mmio 0xfedce000 alias uart_2 off ops amd_uart_mmio_ops end
diff --git a/src/soc/amd/genoa/i2c.c b/src/soc/amd/genoa/i2c.c
new file mode 100644
index 0000000..76c1049
--- /dev/null
+++ b/src/soc/amd/genoa/i2c.c
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <amdblocks/i2c.h>
+#include <console/console.h>
+#include <soc/i2c.h>
+#include <soc/southbridge.h>
+#include "chip.h"
+
+/* Table to switch SCL pins to outputs to initially reset the I2C peripherals */
+static const struct soc_i2c_scl_pin i2c_scl_pins[] = {
+	I2C_RESET_SCL_PIN(I2C0_SCL_PIN, GPIO_I2C0_SCL),
+	I2C_RESET_SCL_PIN(I2C1_SCL_PIN, GPIO_I2C1_SCL),
+	I2C_RESET_SCL_PIN(I2C2_SCL_PIN, GPIO_I2C2_SCL),
+	I2C_RESET_SCL_PIN(I2C3_SCL_PIN, GPIO_I2C3_SCL),
+	I2C_RESET_SCL_PIN(I2C4_SCL_PIN, GPIO_I2C4_SCL),
+	I2C_RESET_SCL_PIN(I2C5_SCL_PIN, GPIO_I2C5_SCL),
+};
+
+static const struct soc_i2c_ctrlr_info i2c_ctrlr[I2C_CTRLR_COUNT] = {
+	{ I2C_MASTER_MODE, APU_I2C0_BASE, "I2C0" },
+	{ I2C_MASTER_MODE, APU_I2C1_BASE, "I2C1" },
+	{ I2C_MASTER_MODE, APU_I2C2_BASE, "I2C2" },
+	{ I2C_MASTER_MODE, APU_I2C3_BASE, "I2C3" },
+	{ I2C_MASTER_MODE, APU_I2C4_BASE, "I2C4" },
+	{ I2C_MASTER_MODE, APU_I2C5_BASE, "I2C5" }
+};
+
+void reset_i2c_peripherals(void)
+{
+	const struct soc_amd_genoa_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);
+}
+
+void soc_i2c_misc_init(unsigned int bus, const struct dw_i2c_bus_config *cfg)
+{
+	/* TODO: write I2C pad control registers */
+}
+
+const struct soc_i2c_ctrlr_info *soc_get_i2c_ctrlr_info(size_t *num_ctrlrs)
+{
+	*num_ctrlrs = ARRAY_SIZE(i2c_ctrlr);
+	return i2c_ctrlr;
+}
+
+const struct dw_i2c_bus_config *soc_get_i2c_bus_config(size_t *num_buses)
+{
+	const struct soc_amd_genoa_config *config = config_of_soc();
+
+	*num_buses = ARRAY_SIZE(config->i2c);
+	return config->i2c;
+}
diff --git a/src/soc/amd/genoa/include/soc/i2c.h b/src/soc/amd/genoa/include/soc/i2c.h
new file mode 100644
index 0000000..ffff754
--- /dev/null
+++ b/src/soc/amd/genoa/include/soc/i2c.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef AMD_GENOA_I2C_H
+#define AMD_GENOA_I2C_H
+
+#include <gpio.h>
+#include <types.h>
+
+#define GPIO_I2C0_SCL		BIT(0)
+#define GPIO_I2C1_SCL		BIT(1)
+#define GPIO_I2C2_SCL		BIT(2)
+#define GPIO_I2C3_SCL		BIT(3)
+#define GPIO_I2C4_SCL		BIT(4)
+#define GPIO_I2C5_SCL		BIT(5)
+#define GPIO_I2C_MASK		(GPIO_I2C0_SCL | GPIO_I2C1_SCL | \
+				 GPIO_I2C2_SCL | GPIO_I2C3_SCL | \
+				 GPIO_I2C4_SCL | GPIO_I2C5_SCL)
+
+
+#define I2C0_SCL_PIN			GPIO_145
+#define I2C1_SCL_PIN			GPIO_147
+#define I2C2_SCL_PIN			GPIO_149
+#define I2C3_SCL_PIN			GPIO_151
+#define I2C4_SCL_PIN			GPIO_13
+#define I2C5_SCL_PIN			GPIO_19
+
+#define I2C0_SCL_PIN_IOMUX_GPIOxx	GPIO_145_IOMUX_GPIOxx
+#define I2C1_SCL_PIN_IOMUX_GPIOxx	GPIO_147_IOMUX_GPIOxx
+#define I2C2_SCL_PIN_IOMUX_GPIOxx	GPIO_149_IOMUX_GPIOxx
+#define I2C3_SCL_PIN_IOMUX_GPIOxx	GPIO_151_IOMUX_GPIOxx
+#define I2C4_SCL_PIN_IOMUX_GPIOxx	GPIO_13_IOMUX_GPIOxx
+#define I2C5_SCL_PIN_IOMUX_GPIOxx	GPIO_19_IOMUX_GPIOxx
+
+void reset_i2c_peripherals(void);
+
+#endif /* AMD_GENOA_I2C_H */
diff --git a/src/soc/amd/genoa/include/soc/iomap.h b/src/soc/amd/genoa/include/soc/iomap.h
index 5b767e3..0e24780 100644
--- a/src/soc/amd/genoa/include/soc/iomap.h
+++ b/src/soc/amd/genoa/include/soc/iomap.h
@@ -3,6 +3,10 @@
 #ifndef AMD_GENOA_IOMAP_H
 #define AMD_GENOA_IOMAP_H
 
+#define I2C_MASTER_DEV_COUNT		6
+#define I2C_PERIPHERAL_DEV_COUNT	0
+#define I2C_CTRLR_COUNT			(I2C_MASTER_DEV_COUNT + I2C_PERIPHERAL_DEV_COUNT)
+
 #define SPI_BASE_ADDRESS		0xfec10000
 
 /* @Todo : Check these values for Genoa */