[PATCH V3 10/11] i3c: mipi-i3c-hci-pci: Add support for Multi-Bus Instances

Adrian Hunter
2025-12-16T16:57:12Z

Add support for MIPI I3C Host Controllers with the Multi-Bus Instance
capability. These controllers can host multiple I3C buses (up to 15)
within a single hardware function (e.g., PCIe B/D/F), providing one
indepedent HCI register set and corresponding I3C bus controller logic
per bus.

Create an MFD cell for each instance and use platform_data to pass the
starting address of the instance's register set.

The MIPI I3C HCI specification defines an Extended Capability that holds
the offset of each instance register set. Parsing this information is
relatively complex, so include the offsets in driver data for now.

Driver data for additional instances beyond instance 0 will be added in a
subsequent patch.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---

Changes in V3:

Make hci a parameter of mipi_i3c_hci_pci_alloc()
Adjust for doing away with dynamic devid allocation
Enhance commit message

Changes in V2:
Conversion to MFD split into separate patch
Simplify ID allocation / free
Correct use of __free()
Also define instance 0 in driver_data

.../master/mipi-i3c-hci/mipi-i3c-hci-pci.c | 36 +++++++++++++------
1 file changed, 26 insertions(+), 10 deletions(-)

diff --git a/drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c b/drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c
index 7ef17255c312..782f46989423 100644
--- a/drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c
+++ b/drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c
@@ -19,6 +19,12 @@
#include <linux/platform_device.h>
#include <linux/pm_qos.h>

+/*
+ * There can up to 15 instances, but implementations have at most 2 at this
+ * time.
+ */
+#define INST_MAX 2
+
struct mipi_i3c_hci_pci {
struct pci_dev *pci;
void __iomem *base;
@@ -30,7 +36,9 @@ struct mipi_i3c_hci_pci_info {
int (*init)(struct mipi_i3c_hci_pci *hci);
void (*exit)(struct mipi_i3c_hci_pci *hci);
const char *name;
- int id;
+ int id[INST_MAX];
+ u32 instance_offset[INST_MAX];
+ int instance_count;
};

#define INTEL_PRIV_OFFSET 0x2b0
@@ -177,14 +185,18 @@ static const struct mipi_i3c_hci_pci_info intel_1_info = {
.init = intel_i3c_init,
.exit = intel_i3c_exit,
.name = "intel-lpss-i3c",
- .id = 0,
+ .id = {0},
+ .instance_offset = {0},
+ .instance_count = 1,
};

static const struct mipi_i3c_hci_pci_info intel_2_info = {
.init = intel_i3c_init,
.exit = intel_i3c_exit,
.name = "intel-lpss-i3c",
- .id = 2,
+ .id = {2},
+ .instance_offset = {0},
+ .instance_count = 1,
};

struct mipi_i3c_hci_pci_cell_data {
@@ -192,34 +204,38 @@ struct mipi_i3c_hci_pci_cell_data {
struct resource res;
};

-static void mipi_i3c_hci_pci_setup_cell(struct mipi_i3c_hci_pci *hci,
+static void mipi_i3c_hci_pci_setup_cell(struct mipi_i3c_hci_pci *hci, int idx,
struct mipi_i3c_hci_pci_cell_data *data,
struct mfd_cell *cell)
{
- data->pdata.base_regs = hci->base;
+ data->pdata.base_regs = hci->base + hci->info->instance_offset[idx];

data->res = DEFINE_RES_IRQ(0);

cell->name = hci->info->name;
- cell->id = hci->info->id;
+ cell->id = hci->info->id[idx];
cell->platform_data = &data->pdata;
cell->pdata_size = sizeof(data->pdata);
cell->num_resources = 1;
cell->resources = &data->res;
}

+#define mipi_i3c_hci_pci_alloc(h, x) kcalloc((h)->info->instance_count, sizeof(*(x)), GFP_KERNEL)
+
static int mipi_i3c_hci_pci_add_instances(struct mipi_i3c_hci_pci *hci)
{
- struct mipi_i3c_hci_pci_cell_data *data __free(kfree) = kzalloc(sizeof(*data), GFP_KERNEL);
- struct mfd_cell *cells __free(kfree) = kzalloc(sizeof(*cells), GFP_KERNEL);
+ struct mipi_i3c_hci_pci_cell_data *data __free(kfree) = mipi_i3c_hci_pci_alloc(hci, data);
+ struct mfd_cell *cells __free(kfree) = mipi_i3c_hci_pci_alloc(hci, cells);
int irq = pci_irq_vector(hci->pci, 0);
+ int nr = hci->info->instance_count;

if (!cells || !data)
return -ENOMEM;

- mipi_i3c_hci_pci_setup_cell(hci, data, cells);
+ for (int i = 0; i < nr; i++)
+ mipi_i3c_hci_pci_setup_cell(hci, i, data + i, cells + i);

- return mfd_add_devices(&hci->pci->dev, 0, cells, 1, NULL, irq, NULL);
+ return mfd_add_devices(&hci->pci->dev, 0, cells, nr, NULL, irq, NULL);
}

static int mipi_i3c_hci_pci_probe(struct pci_dev *pci,