]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
PCI: dwc: Add dw_pcie_program_t_power_on() to program T_POWER_ON
authorKrishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
Tue, 28 Apr 2026 08:37:16 +0000 (14:07 +0530)
committerManivannan Sadhasivam <mani@kernel.org>
Tue, 26 May 2026 14:44:46 +0000 (16:44 +0200)
The T_POWER_ON indicates the time (in μs) that a Port requires the port on
the opposite side of Link to wait in L1.2.Exit after sampling CLKREQ#
asserted before actively driving the interface. This value is used by the
ASPM driver to compute the LTR_L1.2_THRESHOLD.

Currently, some controllers expose T_POWER_ON value of zero in the L1SS
capability registers, leading to incorrect LTR_L1.2_THRESHOLD calculations,
which can result in improper L1.2 exit behavior and if AER happens to be
supported and enabled, the error may be *reported* via AER.

Add a helper to override T_POWER_ON value by the DWC controller drivers.

Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
[mani: changed t_power_on to u32]
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Tested-by: Shawn Lin <shawn.lin@rock-chips.com>
Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>
Link: https://patch.msgid.link/20260428-t_power_on_fux-v5-2-f1ef926a91ff@oss.qualcomm.com
drivers/pci/controller/dwc/pcie-designware.c
drivers/pci/controller/dwc/pcie-designware.h

index c11cf61b8319e66ca5b50915ffd1cc9691d54974..a78553a6f5d66eb5ed6b45ddb6789c48437ef644 100644 (file)
@@ -1249,6 +1249,34 @@ void dw_pcie_hide_unsupported_l1ss(struct dw_pcie *pci)
        dw_pcie_writel_dbi(pci, l1ss + PCI_L1SS_CAP, l1ss_cap);
 }
 
+/* TODO: Need to handle multi Root Ports */
+void dw_pcie_program_t_power_on(struct dw_pcie *pci, u32 t_power_on)
+{
+       u8 scale, value;
+       u16 offset;
+       u32 val;
+
+       if (!t_power_on)
+               return;
+
+       offset = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_L1SS);
+       if (!offset)
+               return;
+
+       pcie_encode_t_power_on(t_power_on, &scale, &value);
+
+       dw_pcie_dbi_ro_wr_en(pci);
+
+       val = dw_pcie_readl_dbi(pci, offset + PCI_L1SS_CAP);
+       val &= ~(PCI_L1SS_CAP_P_PWR_ON_SCALE | PCI_L1SS_CAP_P_PWR_ON_VALUE);
+       FIELD_MODIFY(PCI_L1SS_CAP_P_PWR_ON_SCALE, &val, scale);
+       FIELD_MODIFY(PCI_L1SS_CAP_P_PWR_ON_VALUE, &val, value);
+
+       dw_pcie_writel_dbi(pci, offset + PCI_L1SS_CAP, val);
+
+       dw_pcie_dbi_ro_wr_dis(pci);
+}
+
 void dw_pcie_setup(struct dw_pcie *pci)
 {
        u32 val;
index e759c5c7257e52926628e4c19e10412e2d005008..ace141b90774df545b4ba46d2df48e72c61cd47f 100644 (file)
@@ -606,6 +606,7 @@ int dw_pcie_prog_ep_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
                                u8 bar, size_t size);
 void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index);
 void dw_pcie_hide_unsupported_l1ss(struct dw_pcie *pci);
+void dw_pcie_program_t_power_on(struct dw_pcie *pci, u32 t_power_on);
 void dw_pcie_setup(struct dw_pcie *pci);
 void dw_pcie_iatu_detect(struct dw_pcie *pci);
 int dw_pcie_edma_detect(struct dw_pcie *pci);