soc/amd/common: Add I3C driver
Add an I3C driver that allows to use the I3C HW from the OS. It does: - Power on/off the I3C HW - Configures the IOMUX Add the SoC specific AOAC devices and GPIO pins to reconfigure the GPIO for I3C HW. New log messages are seen in coreboot: [DEBUG] MMIO: fedd2000 disabled TEST: The I3C driver loads on amd/glinda using Ubuntu 25.04. Change-Id: Ibca20e2a4f0cb0e6006cfa47fd4addbe27504645 Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/87960 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Matt DeVillier <matt.devillier@gmail.com> Reviewed-by: Felix Held <felix-coreboot@felixheld.de>
This commit is contained in:
parent
cf5d6f1c88
commit
f4825e5c12
7 changed files with 101 additions and 31 deletions
|
|
@ -1,28 +1,57 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#include <device/mmio.h>
|
||||
#include <acpi/acpigen.h>
|
||||
#include <amdblocks/aoac.h>
|
||||
#include <amdblocks/i2c.h>
|
||||
#include <console/console.h>
|
||||
#include <device/device.h>
|
||||
#include <types.h>
|
||||
|
||||
#if CONFIG(HAVE_ACPI_TABLES)
|
||||
static const char *i3c_acpi_name(const struct device *dev)
|
||||
static int get_i3c_bus_for_dev(const struct device *dev,
|
||||
const struct soc_i3c_ctrlr_info *ctrlr,
|
||||
const size_t num_ctrlrs)
|
||||
{
|
||||
size_t i;
|
||||
size_t num_ctrlrs;
|
||||
const struct soc_i3c_ctrlr_info *ctrlr = soc_get_i3c_ctrlr_info(&num_ctrlrs);
|
||||
if (!dev || !ctrlr)
|
||||
return -1;
|
||||
|
||||
if (!(uintptr_t)dev->path.mmio.addr) {
|
||||
printk(BIOS_ERR, "NULL MMIO address at %s\n", __func__);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_ctrlrs; i++) {
|
||||
if ((uintptr_t)dev->path.mmio.addr == ctrlr[i].bar)
|
||||
return ctrlr[i].acpi_name;
|
||||
for (int i = 0; i < num_ctrlrs; i++) {
|
||||
if (dev->path.mmio.addr != ctrlr[i].bar)
|
||||
continue;
|
||||
return i;
|
||||
}
|
||||
printk(BIOS_ERR, "%s: Could not find %lu\n", __func__, (uintptr_t)dev->path.mmio.addr);
|
||||
printk(BIOS_ERR, "%s: Could not find i3c bus for %s\n", __func__, dev_path(dev));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static const struct soc_i3c_ctrlr_info *
|
||||
get_i3c_info_for_dev(const struct device *dev)
|
||||
{
|
||||
size_t num_ctrlrs;
|
||||
const struct soc_i3c_ctrlr_info *ctrlr = soc_get_i3c_ctrlr_info(&num_ctrlrs);
|
||||
const int bus = get_i3c_bus_for_dev(dev, ctrlr, num_ctrlrs);
|
||||
|
||||
if (ctrlr && bus >= 0 && bus < num_ctrlrs)
|
||||
return &ctrlr[bus];
|
||||
|
||||
printk(BIOS_ERR, "%s: Could not find soc_i3c_ctrlr_info for %s\n", __func__, dev_path(dev));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if CONFIG(HAVE_ACPI_TABLES)
|
||||
static const char *i3c_acpi_name(const struct device *dev)
|
||||
{
|
||||
const struct soc_i3c_ctrlr_info *info = get_i3c_info_for_dev(dev);
|
||||
if (info)
|
||||
return info->acpi_name;
|
||||
|
||||
printk(BIOS_ERR, "%s: Could not find soc_i3c_ctrlr_info for %s\n", __func__, dev_path(dev));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -34,12 +63,47 @@ static void i3c_acpi_fill_ssdt(const struct device *dev)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Even though this is called enable, it gets called for both enabled and disabled devices. */
|
||||
static void i3c_enable(struct device *dev)
|
||||
{
|
||||
const struct soc_i3c_ctrlr_info *info = get_i3c_info_for_dev(dev);
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
if (dev->enabled) {
|
||||
power_on_aoac_device(info->aoac_device);
|
||||
wait_for_aoac_enabled(info->aoac_device);
|
||||
} else {
|
||||
power_off_aoac_device(info->aoac_device);
|
||||
}
|
||||
}
|
||||
|
||||
static void i3c_init(struct device *dev)
|
||||
{
|
||||
size_t num_ctrlrs, num_buses;
|
||||
const struct soc_i3c_ctrlr_info *ctrlr = soc_get_i3c_ctrlr_info(&num_ctrlrs);
|
||||
const int bus = get_i3c_bus_for_dev(dev, ctrlr, num_ctrlrs);
|
||||
if (bus < 0)
|
||||
return;
|
||||
|
||||
const struct dw_i2c_bus_config *cfg = soc_get_i2c_bus_config(&num_buses);
|
||||
|
||||
if (cfg)
|
||||
soc_i2c_misc_init(bus, cfg);
|
||||
}
|
||||
|
||||
static void i3c_read_resources(struct device *dev)
|
||||
{
|
||||
mmio_range(dev, 0, dev->path.mmio.addr, 4 * KiB);
|
||||
}
|
||||
|
||||
/*
|
||||
* Currently there's no I3C driver, thus the I3C hardware cannot be used pre ramstage.
|
||||
* It's sufficient to power switch the I3C controllers in the enable method.
|
||||
*/
|
||||
struct device_operations soc_amd_i3c_mmio_ops = {
|
||||
.enable = i3c_enable,
|
||||
.init = i3c_init,
|
||||
.read_resources = i3c_read_resources,
|
||||
.set_resources = noop_set_resources,
|
||||
#if CONFIG(HAVE_ACPI_TABLES)
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ struct i2c_pad_control {
|
|||
struct soc_i3c_ctrlr_info {
|
||||
uintptr_t bar;
|
||||
const char *acpi_name;
|
||||
unsigned int aoac_device;
|
||||
};
|
||||
|
||||
void fch_i2c_pad_init(unsigned int bus,
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#include <amdblocks/i2c.h>
|
||||
#include <soc/aoac_defs.h>
|
||||
#include <soc/iomap.h>
|
||||
#include <types.h>
|
||||
|
||||
static const struct soc_i3c_ctrlr_info i3c_ctrlr[I3C_CTRLR_COUNT] = {
|
||||
{ APU_I3C0_BASE, "I3C0" },
|
||||
{ APU_I3C1_BASE, "I3C1" },
|
||||
{ APU_I3C2_BASE, "I3C2" },
|
||||
{ APU_I3C3_BASE, "I3C3" }
|
||||
{ APU_I3C0_BASE, "I3C0", FCH_AOAC_DEV_I3C0},
|
||||
{ APU_I3C1_BASE, "I3C1", FCH_AOAC_DEV_I3C1},
|
||||
{ APU_I3C2_BASE, "I3C2", FCH_AOAC_DEV_I3C2},
|
||||
{ APU_I3C3_BASE, "I3C3", FCH_AOAC_DEV_I3C3}
|
||||
};
|
||||
|
||||
const struct soc_i3c_ctrlr_info *soc_get_i3c_ctrlr_info(size_t *num_ctrlrs)
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#include <amdblocks/i2c.h>
|
||||
#include <soc/aoac_defs.h>
|
||||
#include <soc/iomap.h>
|
||||
#include <types.h>
|
||||
|
||||
static const struct soc_i3c_ctrlr_info i3c_ctrlr[I3C_CTRLR_COUNT] = {
|
||||
{ APU_I3C0_BASE, "I3C0" },
|
||||
{ APU_I3C1_BASE, "I3C1" },
|
||||
{ APU_I3C2_BASE, "I3C2" },
|
||||
{ APU_I3C3_BASE, "I3C3" }
|
||||
{ APU_I3C0_BASE, "I3C0", FCH_AOAC_DEV_I3C0},
|
||||
{ APU_I3C1_BASE, "I3C1", FCH_AOAC_DEV_I3C1},
|
||||
{ APU_I3C2_BASE, "I3C2", FCH_AOAC_DEV_I3C2},
|
||||
{ APU_I3C3_BASE, "I3C3", FCH_AOAC_DEV_I3C3}
|
||||
};
|
||||
|
||||
const struct soc_i3c_ctrlr_info *soc_get_i3c_ctrlr_info(size_t *num_ctrlrs)
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#include <amdblocks/i2c.h>
|
||||
#include <soc/aoac_defs.h>
|
||||
#include <soc/iomap.h>
|
||||
#include <types.h>
|
||||
|
||||
static const struct soc_i3c_ctrlr_info i3c_ctrlr[I3C_CTRLR_COUNT] = {
|
||||
{ APU_I3C0_BASE, "I3C0" },
|
||||
{ APU_I3C1_BASE, "I3C1" },
|
||||
{ APU_I3C2_BASE, "I3C2" },
|
||||
{ APU_I3C3_BASE, "I3C3" }
|
||||
{ APU_I3C0_BASE, "I3C0", FCH_AOAC_DEV_I3C0},
|
||||
{ APU_I3C1_BASE, "I3C1", FCH_AOAC_DEV_I3C1},
|
||||
{ APU_I3C2_BASE, "I3C2", FCH_AOAC_DEV_I3C2},
|
||||
{ APU_I3C3_BASE, "I3C3", FCH_AOAC_DEV_I3C3}
|
||||
};
|
||||
|
||||
const struct soc_i3c_ctrlr_info *soc_get_i3c_ctrlr_info(size_t *num_ctrlrs)
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#include <amdblocks/i2c.h>
|
||||
#include <soc/aoac_defs.h>
|
||||
#include <soc/iomap.h>
|
||||
#include <types.h>
|
||||
|
||||
static const struct soc_i3c_ctrlr_info i3c_ctrlr[I3C_CTRLR_COUNT] = {
|
||||
{ APU_I3C0_BASE, "I3C0" },
|
||||
{ APU_I3C1_BASE, "I3C1" },
|
||||
{ APU_I3C2_BASE, "I3C2" },
|
||||
{ APU_I3C3_BASE, "I3C3" }
|
||||
{ APU_I3C0_BASE, "I3C0", FCH_AOAC_DEV_I3C0},
|
||||
{ APU_I3C1_BASE, "I3C1", FCH_AOAC_DEV_I3C1},
|
||||
{ APU_I3C2_BASE, "I3C2", FCH_AOAC_DEV_I3C2},
|
||||
{ APU_I3C3_BASE, "I3C3", FCH_AOAC_DEV_I3C3}
|
||||
};
|
||||
|
||||
const struct soc_i3c_ctrlr_info *soc_get_i3c_ctrlr_info(size_t *num_ctrlrs)
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#include <amdblocks/i2c.h>
|
||||
#include <soc/aoac_defs.h>
|
||||
#include <soc/iomap.h>
|
||||
#include <types.h>
|
||||
|
||||
static const struct soc_i3c_ctrlr_info i3c_ctrlr[I3C_CTRLR_COUNT] = {
|
||||
{ APU_I3C0_BASE, "I3C0" },
|
||||
{ APU_I3C1_BASE, "I3C1" },
|
||||
{ APU_I3C2_BASE, "I3C2" },
|
||||
{ APU_I3C3_BASE, "I3C3" }
|
||||
{ APU_I3C0_BASE, "I3C0", FCH_AOAC_DEV_I3C0},
|
||||
{ APU_I3C1_BASE, "I3C1", FCH_AOAC_DEV_I3C1},
|
||||
{ APU_I3C2_BASE, "I3C2", FCH_AOAC_DEV_I3C2},
|
||||
{ APU_I3C3_BASE, "I3C3", FCH_AOAC_DEV_I3C3}
|
||||
};
|
||||
|
||||
const struct soc_i3c_ctrlr_info *soc_get_i3c_ctrlr_info(size_t *num_ctrlrs)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue