Skip to content

Commit 884a331

Browse files
ahunter6alexandrebelloni
authored andcommitted
i3c: mipi-i3c-hci-pci: Add LTR support for Intel controllers
Add support for Latency Tolerance Reporting (LTR) for Intel controllers. Implement PM ->set_latency_tolerance() callback to set LTR register values. Also expose LTR register values via debugfs. Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Reviewed-by: Frank Li <Frank.Li@nxp.com> Link: https://patch.msgid.link/20251128064038.55158-12-adrian.hunter@intel.com Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
1 parent 040dcd7 commit 884a331

1 file changed

Lines changed: 112 additions & 1 deletion

File tree

drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,21 @@
77
* Author: Jarkko Nikula <jarkko.nikula@linux.intel.com>
88
*/
99
#include <linux/acpi.h>
10+
#include <linux/bitfield.h>
11+
#include <linux/debugfs.h>
1012
#include <linux/idr.h>
1113
#include <linux/iopoll.h>
1214
#include <linux/kernel.h>
1315
#include <linux/module.h>
1416
#include <linux/pci.h>
1517
#include <linux/platform_device.h>
18+
#include <linux/pm_qos.h>
1619

1720
struct mipi_i3c_hci_pci {
1821
struct pci_dev *pci;
1922
struct platform_device *pdev;
2023
const struct mipi_i3c_hci_pci_info *info;
24+
void *private;
2125
};
2226

2327
struct mipi_i3c_hci_pci_info {
@@ -34,6 +38,99 @@ static DEFINE_IDA(mipi_i3c_hci_pci_ida);
3438
#define INTEL_RESETS_RESET_DONE BIT(1)
3539
#define INTEL_RESETS_TIMEOUT_US (10 * USEC_PER_MSEC)
3640

41+
#define INTEL_ACTIVELTR 0x0c
42+
#define INTEL_IDLELTR 0x10
43+
44+
#define INTEL_LTR_REQ BIT(15)
45+
#define INTEL_LTR_SCALE_MASK GENMASK(11, 10)
46+
#define INTEL_LTR_SCALE_1US FIELD_PREP(INTEL_LTR_SCALE_MASK, 2)
47+
#define INTEL_LTR_SCALE_32US FIELD_PREP(INTEL_LTR_SCALE_MASK, 3)
48+
#define INTEL_LTR_VALUE_MASK GENMASK(9, 0)
49+
50+
struct intel_host {
51+
void __iomem *priv;
52+
u32 active_ltr;
53+
u32 idle_ltr;
54+
struct dentry *debugfs_root;
55+
};
56+
57+
static void intel_cache_ltr(struct intel_host *host)
58+
{
59+
host->active_ltr = readl(host->priv + INTEL_ACTIVELTR);
60+
host->idle_ltr = readl(host->priv + INTEL_IDLELTR);
61+
}
62+
63+
static void intel_ltr_set(struct device *dev, s32 val)
64+
{
65+
struct mipi_i3c_hci_pci *hci = dev_get_drvdata(dev);
66+
struct intel_host *host = hci->private;
67+
u32 ltr;
68+
69+
/*
70+
* Program latency tolerance (LTR) accordingly what has been asked
71+
* by the PM QoS layer or disable it in case we were passed
72+
* negative value or PM_QOS_LATENCY_ANY.
73+
*/
74+
ltr = readl(host->priv + INTEL_ACTIVELTR);
75+
76+
if (val == PM_QOS_LATENCY_ANY || val < 0) {
77+
ltr &= ~INTEL_LTR_REQ;
78+
} else {
79+
ltr |= INTEL_LTR_REQ;
80+
ltr &= ~INTEL_LTR_SCALE_MASK;
81+
ltr &= ~INTEL_LTR_VALUE_MASK;
82+
83+
if (val > INTEL_LTR_VALUE_MASK) {
84+
val >>= 5;
85+
if (val > INTEL_LTR_VALUE_MASK)
86+
val = INTEL_LTR_VALUE_MASK;
87+
ltr |= INTEL_LTR_SCALE_32US | val;
88+
} else {
89+
ltr |= INTEL_LTR_SCALE_1US | val;
90+
}
91+
}
92+
93+
if (ltr == host->active_ltr)
94+
return;
95+
96+
writel(ltr, host->priv + INTEL_ACTIVELTR);
97+
writel(ltr, host->priv + INTEL_IDLELTR);
98+
99+
/* Cache the values into intel_host structure */
100+
intel_cache_ltr(host);
101+
}
102+
103+
static void intel_ltr_expose(struct device *dev)
104+
{
105+
dev->power.set_latency_tolerance = intel_ltr_set;
106+
dev_pm_qos_expose_latency_tolerance(dev);
107+
}
108+
109+
static void intel_ltr_hide(struct device *dev)
110+
{
111+
dev_pm_qos_hide_latency_tolerance(dev);
112+
dev->power.set_latency_tolerance = NULL;
113+
}
114+
115+
static void intel_add_debugfs(struct mipi_i3c_hci_pci *hci)
116+
{
117+
struct dentry *dir = debugfs_create_dir(dev_name(&hci->pci->dev), NULL);
118+
struct intel_host *host = hci->private;
119+
120+
intel_cache_ltr(host);
121+
122+
host->debugfs_root = dir;
123+
debugfs_create_x32("active_ltr", 0444, dir, &host->active_ltr);
124+
debugfs_create_x32("idle_ltr", 0444, dir, &host->idle_ltr);
125+
}
126+
127+
static void intel_remove_debugfs(struct mipi_i3c_hci_pci *hci)
128+
{
129+
struct intel_host *host = hci->private;
130+
131+
debugfs_remove_recursive(host->debugfs_root);
132+
}
133+
37134
static void intel_reset(void __iomem *priv)
38135
{
39136
u32 reg;
@@ -55,20 +152,34 @@ static void __iomem *intel_priv(struct pci_dev *pci)
55152

56153
static int intel_i3c_init(struct mipi_i3c_hci_pci *hci)
57154
{
155+
struct intel_host *host = devm_kzalloc(&hci->pci->dev, sizeof(*host), GFP_KERNEL);
58156
void __iomem *priv = intel_priv(hci->pci);
59157

60-
if (!priv)
158+
if (!host || !priv)
61159
return -ENOMEM;
62160

63161
dma_set_mask_and_coherent(&hci->pci->dev, DMA_BIT_MASK(64));
64162

163+
hci->private = host;
164+
host->priv = priv;
165+
65166
intel_reset(priv);
66167

168+
intel_ltr_expose(&hci->pci->dev);
169+
intel_add_debugfs(hci);
170+
67171
return 0;
68172
}
69173

174+
static void intel_i3c_exit(struct mipi_i3c_hci_pci *hci)
175+
{
176+
intel_remove_debugfs(hci);
177+
intel_ltr_hide(&hci->pci->dev);
178+
}
179+
70180
static const struct mipi_i3c_hci_pci_info intel_info = {
71181
.init = intel_i3c_init,
182+
.exit = intel_i3c_exit,
72183
};
73184

74185
static int mipi_i3c_hci_pci_probe(struct pci_dev *pci,

0 commit comments

Comments
 (0)