summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@intel.com>2026-01-06 19:44:15 +0300
committerAlexandre Belloni <alexandre.belloni@bootlin.com>2026-01-14 17:53:34 +0300
commit9b1679028e760259eaf817b8ceecad9b03a60118 (patch)
tree1fd241a18df781cb8db610b10dabed36244952b9
parent0590fe32f9040bccb5481915b32bba1595946b16 (diff)
downloadlinux-9b1679028e760259eaf817b8ceecad9b03a60118.tar.xz
i3c: mipi-i3c-hci-pci: Add support for Multi-Bus Instances
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>
-rw-r--r--drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c36
1 files 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,