]> Gentwo Git Trees - linux/.git/commitdiff
PCI: qcom: Use frequency and level based OPP lookup
authorKrishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
Mon, 13 Oct 2025 10:53:32 +0000 (16:23 +0530)
committerBjorn Helgaas <bhelgaas@google.com>
Fri, 31 Oct 2025 21:20:46 +0000 (16:20 -0500)
PCIe link configurations such as 8GT/s x2 and 16GT/s x1 may operate at the
same frequency, but differ in other characteristics like RPMh votes.  But
the existing OPP selection which is solely based on frequency (the 'opp-hz'
DT property) cannot distinguish between such cases.

Hence, use the newly introduced dev_pm_opp_find_key_exact() API to match
both frequency and level (the 'opp-level' property) when selecting an OPP,
here level indicates PCIe data rate.

To support older device trees where opp-level is not defined, check if
opp-level is present or not using dev_pm_opp_find_level_exact(). If
not present fallback to frequency only match.

Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
[mani: zero initialize dev_pm_opp_key struct]
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
[bhelgaas: add 'opp-hz' and 'opp-level' in commit log]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Link: https://patch.msgid.link/20251013-opp_pcie-v5-5-eb64db2b4bd3@oss.qualcomm.com
drivers/pci/controller/dwc/pcie-qcom.c

index 805edbbfe7eba496bc99ca82051dee43d240f359..5677416c0144348f8bff36d7864273860b0493ca 100644 (file)
@@ -1565,6 +1565,7 @@ static void qcom_pcie_icc_opp_update(struct qcom_pcie *pcie)
 {
        u32 offset, status, width, speed;
        struct dw_pcie *pci = pcie->pci;
+       struct dev_pm_opp_key key = {};
        unsigned long freq_kbps;
        struct dev_pm_opp *opp;
        int ret, freq_mbps;
@@ -1592,8 +1593,20 @@ static void qcom_pcie_icc_opp_update(struct qcom_pcie *pcie)
                        return;
 
                freq_kbps = freq_mbps * KILO;
-               opp = dev_pm_opp_find_freq_exact(pci->dev, freq_kbps * width,
-                                                true);
+               opp = dev_pm_opp_find_level_exact(pci->dev, speed);
+               if (IS_ERR(opp)) {
+                        /* opp-level is not defined use only frequency */
+                       opp = dev_pm_opp_find_freq_exact(pci->dev, freq_kbps * width,
+                                                        true);
+               } else {
+                       /* put opp-level OPP */
+                       dev_pm_opp_put(opp);
+
+                       key.freq = freq_kbps * width;
+                       key.level = speed;
+                       key.bw = 0;
+                       opp = dev_pm_opp_find_key_exact(pci->dev, &key, true);
+               }
                if (!IS_ERR(opp)) {
                        ret = dev_pm_opp_set_opp(pci->dev, opp);
                        if (ret)