soc/amd/cezanne: Get I2C specific code for cezanne

Add macros, settings and callbacks to support I2C for cezanne.

Change-Id: Ic480681d4b7c6fb8591e729090e4faeb5fccf800
Signed-off-by: Zheng Bao <fishbaozi@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/51025
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Martin Roth <martinroth@google.com>
diff --git a/src/soc/amd/cezanne/Kconfig b/src/soc/amd/cezanne/Kconfig
index ab305a7..119889d 100644
--- a/src/soc/amd/cezanne/Kconfig
+++ b/src/soc/amd/cezanne/Kconfig
@@ -39,6 +39,7 @@
 	select SOC_AMD_COMMON_BLOCK_DATA_FABRIC
 	select SOC_AMD_COMMON_BLOCK_GRAPHICS
 	select SOC_AMD_COMMON_BLOCK_HAS_ESPI
+	select SOC_AMD_COMMON_BLOCK_I2C
 	select SOC_AMD_COMMON_BLOCK_LPC
 	select SOC_AMD_COMMON_BLOCK_NONCAR
 	select SOC_AMD_COMMON_BLOCK_PCI
diff --git a/src/soc/amd/cezanne/Makefile.inc b/src/soc/amd/cezanne/Makefile.inc
index f099ad8..91a16d8 100644
--- a/src/soc/amd/cezanne/Makefile.inc
+++ b/src/soc/amd/cezanne/Makefile.inc
@@ -11,19 +11,23 @@
 
 bootblock-y	+= bootblock.c
 bootblock-y	+= early_fch.c
+bootblock-y	+= i2c.c
 bootblock-y	+= gpio.c
 bootblock-y	+= reset.c
 bootblock-y	+= uart.c
 
+verstage-y	+= i2c.c
 verstage_x86-y	+= gpio.c
 verstage_x86-y	+= reset.c
 verstage_x86-y	+= uart.c
 
+romstage-y	+= i2c.c
 romstage-y	+= gpio.c
 romstage-y	+= reset.c
 romstage-y	+= romstage.c
 romstage-y	+= uart.c
 
+ramstage-y	+= i2c.c
 ramstage-y	+= acpi.c
 ramstage-y	+= chip.c
 ramstage-y	+= cpu.c
diff --git a/src/soc/amd/cezanne/chip.h b/src/soc/amd/cezanne/chip.h
index b4e94a4..76ecbfa 100644
--- a/src/soc/amd/cezanne/chip.h
+++ b/src/soc/amd/cezanne/chip.h
@@ -4,9 +4,13 @@
 #define CEZANNE_CHIP_H
 
 #include <amdblocks/chip.h>
+#include <soc/i2c.h>
+#include <drivers/i2c/designware/dw_i2c.h>
 
 struct soc_amd_cezanne_config {
 	struct soc_amd_common_config common_config;
+	u8 i2c_scl_reset;
+	struct dw_i2c_bus_config i2c[I2C_CTRLR_COUNT];
 };
 
 #endif /* CEZANNE_CHIP_H */
diff --git a/src/soc/amd/cezanne/early_fch.c b/src/soc/amd/cezanne/early_fch.c
index cdb1f12..0bab87f 100644
--- a/src/soc/amd/cezanne/early_fch.c
+++ b/src/soc/amd/cezanne/early_fch.c
@@ -4,10 +4,33 @@
 #include <amdblocks/espi.h>
 #include <amdblocks/lpc.h>
 #include <amdblocks/smbus.h>
+#include <amdblocks/i2c.h>
 #include <console/console.h>
+#include <soc/i2c.h>
 #include <soc/southbridge.h>
 #include <soc/uart.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(I2C0_SCL_PIN, PULL_NONE), GPIO_I2C0_SCL },
+	{ PAD_GPI(I2C1_SCL_PIN, PULL_NONE), GPIO_I2C1_SCL },
+	{ PAD_GPI(I2C2_SCL_PIN, PULL_NONE), GPIO_I2C2_SCL },
+	{ PAD_GPI(I2C3_SCL_PIN, PULL_NONE), GPIO_I2C3_SCL },
+};
+
+static void reset_i2c_peripherals(void)
+{
+	const struct soc_amd_cezanne_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)
 {
@@ -19,6 +42,7 @@
 	fch_enable_legacy_io();
 	fch_disable_legacy_dma_io();
 	enable_aoac_devices();
+	reset_i2c_peripherals();
 
 	/*
 	 * On reset Range_0 defaults to enabled. We want to start with a clean
diff --git a/src/soc/amd/cezanne/i2c.c b/src/soc/amd/cezanne/i2c.c
new file mode 100644
index 0000000..ec6cb03
--- /dev/null
+++ b/src/soc/amd/cezanne/i2c.c
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <amdblocks/acpimmio.h>
+#include <amdblocks/i2c.h>
+#include <soc/i2c.h>
+#include <soc/southbridge.h>
+#include "chip.h"
+
+#if ENV_X86
+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" }
+};
+#else
+static struct soc_i2c_ctrlr_info i2c_ctrlr[I2C_CTRLR_CNT] = {
+	{ I2C_MASTER_MODE, 0, "" },
+	{ I2C_MASTER_MODE, 0, "" },
+	{ I2C_MASTER_MODE, 0, "" },
+	{ I2C_MASTER_MODE, 0, "" }
+};
+
+void i2c_set_bar(unsigned int bus, uintptr_t bar)
+{
+	if (bus >= ARRAY_SIZE(i2c_ctrlr)) {
+		printk(BIOS_ERR, "Error: i2c index out of bounds: %u.", bus);
+		return;
+	}
+
+	i2c_ctrlr[bus].bar = bar;
+}
+#endif
+
+__weak void mainboard_i2c_override(int bus, uint32_t *pad_settings) { }
+
+void soc_i2c_misc_init(unsigned int bus, const struct dw_i2c_bus_config *cfg)
+{
+	uint32_t pad_ctrl;
+	int misc_reg;
+
+	misc_reg = MISC_I2C0_PAD_CTRL + sizeof(uint32_t) * bus;
+	pad_ctrl = misc_read32(misc_reg);
+
+	pad_ctrl &= ~I2C_PAD_CTRL_NG_MASK;
+	pad_ctrl |= I2C_PAD_CTRL_NG_NORMAL;
+
+	pad_ctrl &= ~I2C_PAD_CTRL_RX_SEL_MASK;
+	pad_ctrl |= I2C_PAD_CTRL_RX_SEL_3_3V;
+
+	pad_ctrl &= ~I2C_PAD_CTRL_FALLSLEW_MASK;
+	pad_ctrl |= cfg->speed == I2C_SPEED_STANDARD ?
+		I2C_PAD_CTRL_FALLSLEW_STD : I2C_PAD_CTRL_FALLSLEW_LOW;
+	pad_ctrl |= I2C_PAD_CTRL_FALLSLEW_EN;
+
+	mainboard_i2c_override(bus, &pad_ctrl);
+	misc_write32(misc_reg, pad_ctrl);
+}
+
+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_cezanne_config *config = config_of_soc();
+
+	*num_buses = ARRAY_SIZE(config->i2c);
+	return config->i2c;
+}
diff --git a/src/soc/amd/cezanne/include/soc/i2c.h b/src/soc/amd/cezanne/include/soc/i2c.h
new file mode 100644
index 0000000..d69925d
--- /dev/null
+++ b/src/soc/amd/cezanne/include/soc/i2c.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <soc/gpio.h>
+
+#ifndef AMD_CEZANNE_I2C_H
+#define AMD_CEZANNE_I2C_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_I2C_MASK		(BIT(0) | BIT(1) | BIT(2) | BIT(3))
+
+
+#define I2C0_SCL_PIN			GPIO_145
+#define I2C1_SCL_PIN			GPIO_147
+#define I2C2_SCL_PIN			GPIO_113
+#define I2C3_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_113_IOMUX_GPIOxx
+#define I2C3_SCL_PIN_IOMUX_GPIOxx	GPIO_19_IOMUX_GPIOxx
+
+
+#endif /* AMD_CEZANNE_I2C_H */
diff --git a/src/soc/amd/cezanne/include/soc/iomap.h b/src/soc/amd/cezanne/include/soc/iomap.h
index 3a84fae..8f33794 100644
--- a/src/soc/amd/cezanne/include/soc/iomap.h
+++ b/src/soc/amd/cezanne/include/soc/iomap.h
@@ -16,11 +16,22 @@
 /* FCH AL2AHB Registers */
 #define ALINK_AHB_ADDRESS		0xfedc0000
 
+#define I2C_MASTER_DEV_COUNT		4
+#define I2C_MASTER_START_INDEX		0
+#define I2C_PERIPHERAL_DEV_COUNT	0 /* TODO: Only master for now. */
+#define I2C_CTRLR_COUNT			(I2C_MASTER_DEV_COUNT + I2C_PERIPHERAL_DEV_COUNT)
+
 #define APU_I2C0_BASE			0xfedc2000
 #define APU_I2C1_BASE			0xfedc3000
 #define APU_I2C2_BASE			0xfedc4000
 #define APU_I2C3_BASE			0xfedc5000
 
+/* I2C parameters for lpc_read_resources */
+#define I2C_BASE_ADDRESS		APU_I2C2_BASE
+#define I2C_DEVICE_SIZE			0x00001000
+#define I2C_DEVICE_COUNT		(I2C_MASTER_DEV_COUNT \
+					 - I2C_MASTER_START_INDEX)
+
 #define APU_DMAC0_BASE			0xfedc7000
 #define APU_DMAC1_BASE			0xfedc8000
 #define APU_UART0_BASE			0xfedc9000
diff --git a/src/soc/amd/cezanne/include/soc/southbridge.h b/src/soc/amd/cezanne/include/soc/southbridge.h
index 0b5882e..05dd9b3 100644
--- a/src/soc/amd/cezanne/include/soc/southbridge.h
+++ b/src/soc/amd/cezanne/include/soc/southbridge.h
@@ -65,6 +65,33 @@
 
 #define FCH_LEGACY_UART_DECODE		(ALINK_AHB_ADDRESS + 0x20) /* 0xfedc0020 */
 
+#define MISC_I2C0_PAD_CTRL		0xd8
+#define MISC_I2C1_PAD_CTRL		0xdc
+#define MISC_I2C2_PAD_CTRL		0xe0
+#define MISC_I2C3_PAD_CTRL		0xe4
+#define   I2C_PAD_CTRL_NG_MASK		(BIT(0) + BIT(1) + BIT(2) + BIT(3))
+#define     I2C_PAD_CTRL_NG_NORMAL	0xc
+#define   I2C_PAD_CTRL_RX_SEL_MASK	(BIT(4) + BIT(5))
+#define     I2C_PAD_CTRL_RX_SHIFT	4
+#define     I2C_PAD_CTRL_RX_SEL_OFF	(0 << I2C_PAD_CTRL_RX_SHIFT)
+#define     I2C_PAD_CTRL_RX_SEL_3_3V	(1 << I2C_PAD_CTRL_RX_SHIFT)
+#define     I2C_PAD_CTRL_RX_SEL_1_8V	(3 << I2C_PAD_CTRL_RX_SHIFT)
+#define   I2C_PAD_CTRL_PULLDOWN_EN	BIT(6)
+#define   I2C_PAD_CTRL_FALLSLEW_MASK	(BIT(7) + BIT(8))
+#define     I2C_PAD_CTRL_FALLSLEW_SHIFT	7
+#define     I2C_PAD_CTRL_FALLSLEW_STD	(0 << I2C_PAD_CTRL_FALLSLEW_SHIFT)
+#define     I2C_PAD_CTRL_FALLSLEW_LOW	(1 << I2C_PAD_CTRL_FALLSLEW_SHIFT)
+#define   I2C_PAD_CTRL_FALLSLEW_EN	BIT(9)
+#define   I2C_PAD_CTRL_SPIKE_RC_EN	BIT(10)
+#define   I2C_PAD_CTRL_SPIKE_RC_SEL	BIT(11) /* 0 = 50ns, 1 = 20ns */
+#define   I2C_PAD_CTRL_CAP_DOWN		BIT(12)
+#define   I2C_PAD_CTRL_CAP_UP		BIT(13)
+#define   I2C_PAD_CTRL_RES_DOWN		BIT(14)
+#define   I2C_PAD_CTRL_RES_UP		BIT(15)
+#define   I2C_PAD_CTRL_BIOS_CRT_EN	BIT(16)
+#define   I2C_PAD_CTRL_SPARE0		BIT(17)
+#define   I2C_PAD_CTRL_SPARE1		BIT(18)
+
 /* FCH AOAC device offsets for AOAC_DEV_D3_CTL/AOAC_DEV_D3_STATE */
 #define FCH_AOAC_DEV_CLK_GEN		0
 #define FCH_AOAC_DEV_I2C0		5
@@ -89,4 +116,7 @@
 void enable_aoac_devices(void);
 void wait_for_aoac_enabled(unsigned int dev);
 
+/* Allow the board to change the default I2C pad configuration */
+void mainboard_i2c_override(int bus, uint32_t *pad_settings);
+
 #endif /* AMD_CEZANNE_SOUTHBRIDGE_H */