]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
i3c: mipi-i3c-hci-pci: Add support for Multi-Bus Instances
authorAdrian Hunter <adrian.hunter@intel.com>
Tue, 6 Jan 2026 16:44:15 +0000 (18:44 +0200)
committerAlexandre Belloni <alexandre.belloni@bootlin.com>
Wed, 14 Jan 2026 14:53:34 +0000 (15:53 +0100)
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>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20260106164416.67074-11-adrian.hunter@intel.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c

index 7ef17255c31229dfc6ec27e36ec7d4b6f4fe6c3a..782f46989423aeedfec03e5a433a8d06658d7b51 100644 (file)
 #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,