From: Krishna Chaitanya Chundru Date: Tue, 28 Apr 2026 08:37:16 +0000 (+0530) Subject: PCI: dwc: Add dw_pcie_program_t_power_on() to program T_POWER_ON X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d697e90672484186e2676426bf810ad6fe269579;p=thirdparty%2Flinux.git PCI: dwc: Add dw_pcie_program_t_power_on() to program T_POWER_ON 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 [mani: changed t_power_on to u32] Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Tested-by: Shawn Lin Reviewed-by: Shawn Lin Link: https://patch.msgid.link/20260428-t_power_on_fux-v5-2-f1ef926a91ff@oss.qualcomm.com --- diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index c11cf61b8319..a78553a6f5d6 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -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; diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index e759c5c7257e..ace141b90774 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -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);