Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Adrian Hunter and committed by
Alexandre Belloni
884a3313 040dcd76

+112 -1
+112 -1
drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c
··· 7 7 * Author: Jarkko Nikula <jarkko.nikula@linux.intel.com> 8 8 */ 9 9 #include <linux/acpi.h> 10 + #include <linux/bitfield.h> 11 + #include <linux/debugfs.h> 10 12 #include <linux/idr.h> 11 13 #include <linux/iopoll.h> 12 14 #include <linux/kernel.h> 13 15 #include <linux/module.h> 14 16 #include <linux/pci.h> 15 17 #include <linux/platform_device.h> 18 + #include <linux/pm_qos.h> 16 19 17 20 struct mipi_i3c_hci_pci { 18 21 struct pci_dev *pci; 19 22 struct platform_device *pdev; 20 23 const struct mipi_i3c_hci_pci_info *info; 24 + void *private; 21 25 }; 22 26 23 27 struct mipi_i3c_hci_pci_info { ··· 37 33 #define INTEL_RESETS_RESET BIT(0) 38 34 #define INTEL_RESETS_RESET_DONE BIT(1) 39 35 #define INTEL_RESETS_TIMEOUT_US (10 * USEC_PER_MSEC) 36 + 37 + #define INTEL_ACTIVELTR 0x0c 38 + #define INTEL_IDLELTR 0x10 39 + 40 + #define INTEL_LTR_REQ BIT(15) 41 + #define INTEL_LTR_SCALE_MASK GENMASK(11, 10) 42 + #define INTEL_LTR_SCALE_1US FIELD_PREP(INTEL_LTR_SCALE_MASK, 2) 43 + #define INTEL_LTR_SCALE_32US FIELD_PREP(INTEL_LTR_SCALE_MASK, 3) 44 + #define INTEL_LTR_VALUE_MASK GENMASK(9, 0) 45 + 46 + struct intel_host { 47 + void __iomem *priv; 48 + u32 active_ltr; 49 + u32 idle_ltr; 50 + struct dentry *debugfs_root; 51 + }; 52 + 53 + static void intel_cache_ltr(struct intel_host *host) 54 + { 55 + host->active_ltr = readl(host->priv + INTEL_ACTIVELTR); 56 + host->idle_ltr = readl(host->priv + INTEL_IDLELTR); 57 + } 58 + 59 + static void intel_ltr_set(struct device *dev, s32 val) 60 + { 61 + struct mipi_i3c_hci_pci *hci = dev_get_drvdata(dev); 62 + struct intel_host *host = hci->private; 63 + u32 ltr; 64 + 65 + /* 66 + * Program latency tolerance (LTR) accordingly what has been asked 67 + * by the PM QoS layer or disable it in case we were passed 68 + * negative value or PM_QOS_LATENCY_ANY. 69 + */ 70 + ltr = readl(host->priv + INTEL_ACTIVELTR); 71 + 72 + if (val == PM_QOS_LATENCY_ANY || val < 0) { 73 + ltr &= ~INTEL_LTR_REQ; 74 + } else { 75 + ltr |= INTEL_LTR_REQ; 76 + ltr &= ~INTEL_LTR_SCALE_MASK; 77 + ltr &= ~INTEL_LTR_VALUE_MASK; 78 + 79 + if (val > INTEL_LTR_VALUE_MASK) { 80 + val >>= 5; 81 + if (val > INTEL_LTR_VALUE_MASK) 82 + val = INTEL_LTR_VALUE_MASK; 83 + ltr |= INTEL_LTR_SCALE_32US | val; 84 + } else { 85 + ltr |= INTEL_LTR_SCALE_1US | val; 86 + } 87 + } 88 + 89 + if (ltr == host->active_ltr) 90 + return; 91 + 92 + writel(ltr, host->priv + INTEL_ACTIVELTR); 93 + writel(ltr, host->priv + INTEL_IDLELTR); 94 + 95 + /* Cache the values into intel_host structure */ 96 + intel_cache_ltr(host); 97 + } 98 + 99 + static void intel_ltr_expose(struct device *dev) 100 + { 101 + dev->power.set_latency_tolerance = intel_ltr_set; 102 + dev_pm_qos_expose_latency_tolerance(dev); 103 + } 104 + 105 + static void intel_ltr_hide(struct device *dev) 106 + { 107 + dev_pm_qos_hide_latency_tolerance(dev); 108 + dev->power.set_latency_tolerance = NULL; 109 + } 110 + 111 + static void intel_add_debugfs(struct mipi_i3c_hci_pci *hci) 112 + { 113 + struct dentry *dir = debugfs_create_dir(dev_name(&hci->pci->dev), NULL); 114 + struct intel_host *host = hci->private; 115 + 116 + intel_cache_ltr(host); 117 + 118 + host->debugfs_root = dir; 119 + debugfs_create_x32("active_ltr", 0444, dir, &host->active_ltr); 120 + debugfs_create_x32("idle_ltr", 0444, dir, &host->idle_ltr); 121 + } 122 + 123 + static void intel_remove_debugfs(struct mipi_i3c_hci_pci *hci) 124 + { 125 + struct intel_host *host = hci->private; 126 + 127 + debugfs_remove_recursive(host->debugfs_root); 128 + } 40 129 41 130 static void intel_reset(void __iomem *priv) 42 131 { ··· 152 55 153 56 static int intel_i3c_init(struct mipi_i3c_hci_pci *hci) 154 57 { 58 + struct intel_host *host = devm_kzalloc(&hci->pci->dev, sizeof(*host), GFP_KERNEL); 155 59 void __iomem *priv = intel_priv(hci->pci); 156 60 157 - if (!priv) 61 + if (!host || !priv) 158 62 return -ENOMEM; 159 63 160 64 dma_set_mask_and_coherent(&hci->pci->dev, DMA_BIT_MASK(64)); 161 65 66 + hci->private = host; 67 + host->priv = priv; 68 + 162 69 intel_reset(priv); 70 + 71 + intel_ltr_expose(&hci->pci->dev); 72 + intel_add_debugfs(hci); 163 73 164 74 return 0; 165 75 } 166 76 77 + static void intel_i3c_exit(struct mipi_i3c_hci_pci *hci) 78 + { 79 + intel_remove_debugfs(hci); 80 + intel_ltr_hide(&hci->pci->dev); 81 + } 82 + 167 83 static const struct mipi_i3c_hci_pci_info intel_info = { 168 84 .init = intel_i3c_init, 85 + .exit = intel_i3c_exit, 169 86 }; 170 87 171 88 static int mipi_i3c_hci_pci_probe(struct pci_dev *pci,