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 */