Skip to content

Commit 30bb1ce

Browse files
jhnikulaalexandrebelloni
authored andcommitted
i3c: mipi-i3c-hci: Add support for MIPI I3C HCI on PCI bus
Add a glue code for the MIPI I3C HCI on PCI bus with Intel Panther Lake I3C controller PCI IDs. MIPI I3C HCI on Intel platforms has additional logic around the MIPI I3C HCI core logic. Those together create so called I3C slice on PCI bus. Intel specific initialization code does a reset cycle to the I3C slice before probing the MIPI I3C HCI part. Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com> Link: https://lore.kernel.org/r/20241231115904.620052-2-jarkko.nikula@linux.intel.com Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
1 parent ccdb2e0 commit 30bb1ce

File tree

3 files changed

+160
-0
lines changed

3 files changed

+160
-0
lines changed

drivers/i3c/master/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,14 @@ config MIPI_I3C_HCI
5757

5858
This driver can also be built as a module. If so, the module will be
5959
called mipi-i3c-hci.
60+
61+
config MIPI_I3C_HCI_PCI
62+
tristate "MIPI I3C Host Controller Interface PCI support"
63+
depends on MIPI_I3C_HCI
64+
depends on PCI
65+
help
66+
Support for MIPI I3C Host Controller Interface compatible hardware
67+
on the PCI bus.
68+
69+
This driver can also be built as a module. If so, the module will be
70+
called mipi-i3c-hci-pci.

drivers/i3c/master/mipi-i3c-hci/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ mipi-i3c-hci-y := core.o ext_caps.o pio.o dma.o \
55
cmd_v1.o cmd_v2.o \
66
dat_v1.o dct_v1.o \
77
hci_quirks.o
8+
obj-$(CONFIG_MIPI_I3C_HCI_PCI) += mipi-i3c-hci-pci.o
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* PCI glue code for MIPI I3C HCI driver
4+
*
5+
* Copyright (C) 2024 Intel Corporation
6+
*
7+
* Author: Jarkko Nikula <jarkko.nikula@linux.intel.com>
8+
*/
9+
#include <linux/acpi.h>
10+
#include <linux/idr.h>
11+
#include <linux/kernel.h>
12+
#include <linux/module.h>
13+
#include <linux/pci.h>
14+
#include <linux/platform_device.h>
15+
16+
struct mipi_i3c_hci_pci_info {
17+
int (*init)(struct pci_dev *pci);
18+
};
19+
20+
#define INTEL_PRIV_OFFSET 0x2b0
21+
#define INTEL_PRIV_SIZE 0x28
22+
#define INTEL_PRIV_RESETS 0x04
23+
#define INTEL_PRIV_RESETS_RESET BIT(0)
24+
#define INTEL_PRIV_RESETS_RESET_DONE BIT(1)
25+
26+
static DEFINE_IDA(mipi_i3c_hci_pci_ida);
27+
28+
static int mipi_i3c_hci_pci_intel_init(struct pci_dev *pci)
29+
{
30+
unsigned long timeout;
31+
void __iomem *priv;
32+
33+
priv = devm_ioremap(&pci->dev,
34+
pci_resource_start(pci, 0) + INTEL_PRIV_OFFSET,
35+
INTEL_PRIV_SIZE);
36+
if (!priv)
37+
return -ENOMEM;
38+
39+
/* Assert reset, wait for completion and release reset */
40+
writel(0, priv + INTEL_PRIV_RESETS);
41+
timeout = jiffies + msecs_to_jiffies(10);
42+
while (!(readl(priv + INTEL_PRIV_RESETS) &
43+
INTEL_PRIV_RESETS_RESET_DONE)) {
44+
if (time_after(jiffies, timeout))
45+
break;
46+
cpu_relax();
47+
}
48+
writel(INTEL_PRIV_RESETS_RESET, priv + INTEL_PRIV_RESETS);
49+
50+
return 0;
51+
}
52+
53+
static struct mipi_i3c_hci_pci_info intel_info = {
54+
.init = mipi_i3c_hci_pci_intel_init,
55+
};
56+
57+
static int mipi_i3c_hci_pci_probe(struct pci_dev *pci,
58+
const struct pci_device_id *id)
59+
{
60+
struct mipi_i3c_hci_pci_info *info;
61+
struct platform_device *pdev;
62+
struct resource res[2];
63+
int dev_id, ret;
64+
65+
ret = pcim_enable_device(pci);
66+
if (ret)
67+
return ret;
68+
69+
pci_set_master(pci);
70+
71+
memset(&res, 0, sizeof(res));
72+
73+
res[0].flags = IORESOURCE_MEM;
74+
res[0].start = pci_resource_start(pci, 0);
75+
res[0].end = pci_resource_end(pci, 0);
76+
77+
res[1].flags = IORESOURCE_IRQ;
78+
res[1].start = pci->irq;
79+
res[1].end = pci->irq;
80+
81+
dev_id = ida_alloc(&mipi_i3c_hci_pci_ida, GFP_KERNEL);
82+
if (dev_id < 0)
83+
return dev_id;
84+
85+
pdev = platform_device_alloc("mipi-i3c-hci", dev_id);
86+
if (!pdev)
87+
return -ENOMEM;
88+
89+
pdev->dev.parent = &pci->dev;
90+
device_set_node(&pdev->dev, dev_fwnode(&pci->dev));
91+
92+
ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res));
93+
if (ret)
94+
goto err;
95+
96+
info = (struct mipi_i3c_hci_pci_info *)id->driver_data;
97+
if (info && info->init) {
98+
ret = info->init(pci);
99+
if (ret)
100+
goto err;
101+
}
102+
103+
ret = platform_device_add(pdev);
104+
if (ret)
105+
goto err;
106+
107+
pci_set_drvdata(pci, pdev);
108+
109+
return 0;
110+
111+
err:
112+
platform_device_put(pdev);
113+
ida_free(&mipi_i3c_hci_pci_ida, dev_id);
114+
return ret;
115+
}
116+
117+
static void mipi_i3c_hci_pci_remove(struct pci_dev *pci)
118+
{
119+
struct platform_device *pdev = pci_get_drvdata(pci);
120+
int dev_id = pdev->id;
121+
122+
platform_device_unregister(pdev);
123+
ida_free(&mipi_i3c_hci_pci_ida, dev_id);
124+
}
125+
126+
static const struct pci_device_id mipi_i3c_hci_pci_devices[] = {
127+
/* Panther Lake-H */
128+
{ PCI_VDEVICE(INTEL, 0xe37c), (kernel_ulong_t)&intel_info},
129+
{ PCI_VDEVICE(INTEL, 0xe36f), (kernel_ulong_t)&intel_info},
130+
/* Panther Lake-P */
131+
{ PCI_VDEVICE(INTEL, 0xe47c), (kernel_ulong_t)&intel_info},
132+
{ PCI_VDEVICE(INTEL, 0xe46f), (kernel_ulong_t)&intel_info},
133+
{ },
134+
};
135+
MODULE_DEVICE_TABLE(pci, mipi_i3c_hci_pci_devices);
136+
137+
static struct pci_driver mipi_i3c_hci_pci_driver = {
138+
.name = "mipi_i3c_hci_pci",
139+
.id_table = mipi_i3c_hci_pci_devices,
140+
.probe = mipi_i3c_hci_pci_probe,
141+
.remove = mipi_i3c_hci_pci_remove,
142+
};
143+
144+
module_pci_driver(mipi_i3c_hci_pci_driver);
145+
146+
MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@intel.com>");
147+
MODULE_LICENSE("GPL");
148+
MODULE_DESCRIPTION("MIPI I3C HCI driver on PCI bus");

0 commit comments

Comments
 (0)