summaryrefslogtreecommitdiff
path: root/src/soc/amd/common/block/i2c/i2c.c
diff options
context:
space:
mode:
authorKarthikeyan Ramasubramanian <kramasub@google.com>2021-03-18 23:16:29 -0600
committerMartin Roth <martinroth@google.com>2021-03-22 03:40:42 +0000
commit4f87ae1d4a3a597f1260534001bd99160cc8ca99 (patch)
treed9b2e6f2a396744b9a10f8f3cc7106d85c0afdc7 /src/soc/amd/common/block/i2c/i2c.c
parent0dbea48d46013c004014a024ad8717d049e67c8d (diff)
soc/amd/common/block/i2c: Move SoC agnostic parts into common
The logic behind I2C bus initialization, I2C MMIO base address getter and setter, I2C bus ACPI name resolution are identical for all the AMD SoCs. Hence moving all the SoC agnotic parts of the driver into the common driver and just configure the SoC specific parts into individual I2C drivers. BUG=None TEST=Build Dalboz and Grunt. Boot to OS in Dalboz. Ensure that the I2C peripherals are detected as earlier in Dalboz. Verify some I2C peripheral functionality like trackpad and touchscreen. Change-Id: Ic9c99ec769d7d8ad7e1e566fdf42a5206657183d Signed-off-by: Karthikeyan Ramasubramanian <kramasub@google.com> Suggested-by: Kyosti Malkki <kyosti.malkki@gmail.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/51509 Reviewed-by: Furquan Shaikh <furquan@google.com> Reviewed-by: Raul Rangel <rrangel@chromium.org> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Diffstat (limited to 'src/soc/amd/common/block/i2c/i2c.c')
-rw-r--r--src/soc/amd/common/block/i2c/i2c.c120
1 files changed, 119 insertions, 1 deletions
diff --git a/src/soc/amd/common/block/i2c/i2c.c b/src/soc/amd/common/block/i2c/i2c.c
index 59e885d807..95e25798d2 100644
--- a/src/soc/amd/common/block/i2c/i2c.c
+++ b/src/soc/amd/common/block/i2c/i2c.c
@@ -1,14 +1,132 @@
/* SPDX-License-Identifier: GPL-2.0-only */
+#include <acpi/acpi.h>
#include <assert.h>
-#include <delay.h>
#include <amdblocks/acpimmio.h>
#include <amdblocks/gpio_banks.h>
#include <amdblocks/gpio_defs.h>
#include <amdblocks/i2c.h>
+#include <console/console.h>
+#include <delay.h>
+#include <device/device.h>
+#include <device/i2c.h>
+#include <device/mmio.h>
+#include <drivers/i2c/designware/dw_i2c.h>
#define MAX_PIN_COUNT 4
+uintptr_t dw_i2c_base_address(unsigned int bus)
+{
+ size_t num_ctrlrs;
+ const struct soc_i2c_ctrlr_info *ctrlr = soc_get_i2c_ctrlr_info(&num_ctrlrs);
+
+ if (bus >= num_ctrlrs) {
+ printk(BIOS_ERR, "Bus ID %d is >= number of I2C controllers %zu\n",
+ bus, num_ctrlrs);
+ return 0;
+ }
+
+ return ctrlr[bus].bar;
+}
+
+const struct dw_i2c_bus_config *dw_i2c_get_soc_cfg(unsigned int bus)
+{
+ size_t num_buses = 0;
+ const struct dw_i2c_bus_config *cfg = soc_get_i2c_bus_config(&num_buses);
+
+ if (bus >= num_buses) {
+ printk(BIOS_ERR, "Bus ID %d is >= number of I2C buses %zu\n", bus, num_buses);
+ return NULL;
+ }
+
+ return &cfg[bus];
+}
+
+static const char *i2c_acpi_name(const struct device *dev)
+{
+ size_t i;
+ size_t num_ctrlrs;
+ const struct soc_i2c_ctrlr_info *ctrlr = soc_get_i2c_ctrlr_info(&num_ctrlrs);
+
+ if (!(uintptr_t)dev->path.mmio.addr)
+ die("NULL MMIO address at %s\n", __func__);
+
+ for (i = 0; i < num_ctrlrs; i++) {
+ if ((uintptr_t)dev->path.mmio.addr == ctrlr[i].bar)
+ return ctrlr[i].acpi_name;
+ }
+ printk(BIOS_ERR, "%s: Could not find %lu\n", __func__, (uintptr_t)dev->path.mmio.addr);
+ return NULL;
+}
+
+int dw_i2c_soc_dev_to_bus(const struct device *dev)
+{
+ size_t i;
+ size_t num_ctrlrs;
+ const struct soc_i2c_ctrlr_info *ctrlr = soc_get_i2c_ctrlr_info(&num_ctrlrs);
+
+ if (!(uintptr_t)dev->path.mmio.addr)
+ die("NULL MMIO address at %s\n", __func__);
+
+ for (i = 0; i < num_ctrlrs; i++) {
+ if ((uintptr_t)dev->path.mmio.addr == ctrlr[i].bar)
+ return i;
+ }
+ printk(BIOS_ERR, "%s: Could not find %lu\n", __func__, (uintptr_t)dev->path.mmio.addr);
+ return -1;
+}
+
+void __weak soc_i2c_misc_init(unsigned int bus, const struct dw_i2c_bus_config *cfg)
+{
+ /* Nothing by default. */
+}
+
+static void dw_i2c_soc_init(bool is_early_init)
+{
+ unsigned int bus;
+ size_t num_buses = 0, num_ctrlrs = 0;
+ const struct dw_i2c_bus_config *cfg = soc_get_i2c_bus_config(&num_buses);
+ const struct soc_i2c_ctrlr_info *ctrlr = soc_get_i2c_ctrlr_info(&num_ctrlrs);
+
+ /* Ensure that the number of controllers in devicetree and SoC match. */
+ assert(num_buses == num_ctrlrs);
+
+ for (bus = 0; bus < num_buses; bus++, cfg++, ctrlr++) {
+ /*
+ * Skip initialization when controller is in peripheral mode or base address
+ * is not configured or is not the expected stage to initialize.
+ */
+ if (ctrlr->mode == I2C_PERIPHERAL_MODE || !ctrlr->bar ||
+ cfg->early_init != is_early_init)
+ continue;
+
+ if (dw_i2c_init(bus, cfg))
+ printk(BIOS_ERR, "Failed to init i2c bus %d\n", bus);
+ continue;
+
+ soc_i2c_misc_init(bus, cfg);
+ }
+}
+
+void i2c_soc_early_init(void)
+{
+ dw_i2c_soc_init(true);
+}
+
+void i2c_soc_init(void)
+{
+ dw_i2c_soc_init(false);
+}
+
+struct device_operations soc_amd_i2c_mmio_ops = {
+ /* TODO(kramasub): Move I2C resource info here. */
+ .read_resources = noop_read_resources,
+ .set_resources = noop_set_resources,
+ .scan_bus = scan_smbus,
+ .acpi_name = i2c_acpi_name,
+ .acpi_fill_ssdt = dw_i2c_acpi_fill_ssdt,
+};
+
struct common_i2c_save {
uint32_t control_value;
uint8_t mux_value;