Skip to content

Commit 2b12e31

Browse files
committed
Merge branch 'pci/controller/dwc'
- Update PORT_LOGIC_LTSSM_STATE_MASK to be a 6-bit mask as per spec, not a 5-bit mask (Shawn Lin) - Clear L1 PM Substate Capability 'Supported' bits unless glue driver says it's supported, which prevents users from enabling non-working L1SS. Currently only qcom and tegra194 support L1SS (Bjorn Helgaas) - Remove now-superfluous L1SS disable code from tegra194 (Bjorn Helgaas) - Configure L1SS support in dw-rockchip when DT says 'supports-clkreq' (Shawn Lin) * pci/controller/dwc: PCI: dw-rockchip: Configure L1SS support PCI: tegra194: Remove unnecessary L1SS disable code PCI: dwc: Advertise L1 PM Substates only if driver requests it PCI: dwc: Fix wrong PORT_LOGIC_LTSSM_STATE_MASK definition
2 parents f4620f6 + b5e719f commit 2b12e31

6 files changed

Lines changed: 79 additions & 41 deletions

File tree

drivers/pci/controller/dwc/pcie-designware-host.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,6 +1060,8 @@ int dw_pcie_setup_rc(struct dw_pcie_rp *pp)
10601060
PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
10611061
dw_pcie_writel_dbi(pci, PCI_COMMAND, val);
10621062

1063+
dw_pcie_hide_unsupported_l1ss(pci);
1064+
10631065
dw_pcie_config_presets(pp);
10641066
/*
10651067
* If the platform provides its own child bus config accesses, it means

drivers/pci/controller/dwc/pcie-designware.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,6 +1081,30 @@ void dw_pcie_edma_remove(struct dw_pcie *pci)
10811081
dw_edma_remove(&pci->edma);
10821082
}
10831083

1084+
void dw_pcie_hide_unsupported_l1ss(struct dw_pcie *pci)
1085+
{
1086+
u16 l1ss;
1087+
u32 l1ss_cap;
1088+
1089+
if (pci->l1ss_support)
1090+
return;
1091+
1092+
l1ss = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_L1SS);
1093+
if (!l1ss)
1094+
return;
1095+
1096+
/*
1097+
* Unless the driver claims "l1ss_support", don't advertise L1 PM
1098+
* Substates because they require CLKREQ# and possibly other
1099+
* device-specific configuration.
1100+
*/
1101+
l1ss_cap = dw_pcie_readl_dbi(pci, l1ss + PCI_L1SS_CAP);
1102+
l1ss_cap &= ~(PCI_L1SS_CAP_PCIPM_L1_1 | PCI_L1SS_CAP_ASPM_L1_1 |
1103+
PCI_L1SS_CAP_PCIPM_L1_2 | PCI_L1SS_CAP_ASPM_L1_2 |
1104+
PCI_L1SS_CAP_L1_PM_SS);
1105+
dw_pcie_writel_dbi(pci, l1ss + PCI_L1SS_CAP, l1ss_cap);
1106+
}
1107+
10841108
void dw_pcie_setup(struct dw_pcie *pci)
10851109
{
10861110
u32 val;

drivers/pci/controller/dwc/pcie-designware.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@
9797
#define PORT_LANE_SKEW_INSERT_MASK GENMASK(23, 0)
9898

9999
#define PCIE_PORT_DEBUG0 0x728
100-
#define PORT_LOGIC_LTSSM_STATE_MASK 0x1f
100+
#define PORT_LOGIC_LTSSM_STATE_MASK 0x3f
101101
#define PORT_LOGIC_LTSSM_STATE_L0 0x11
102102
#define PCIE_PORT_DEBUG1 0x72C
103103
#define PCIE_PORT_DEBUG1_LINK_UP BIT(4)
@@ -516,6 +516,7 @@ struct dw_pcie {
516516
int max_link_speed;
517517
u8 n_fts[2];
518518
struct dw_edma_chip edma;
519+
bool l1ss_support; /* L1 PM Substates support */
519520
struct clk_bulk_data app_clks[DW_PCIE_NUM_APP_CLKS];
520521
struct clk_bulk_data core_clks[DW_PCIE_NUM_CORE_CLKS];
521522
struct reset_control_bulk_data app_rsts[DW_PCIE_NUM_APP_RSTS];
@@ -573,6 +574,7 @@ int dw_pcie_prog_ep_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
573574
int type, u64 parent_bus_addr,
574575
u8 bar, size_t size);
575576
void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index);
577+
void dw_pcie_hide_unsupported_l1ss(struct dw_pcie *pci);
576578
void dw_pcie_setup(struct dw_pcie *pci);
577579
void dw_pcie_iatu_detect(struct dw_pcie *pci);
578580
int dw_pcie_edma_detect(struct dw_pcie *pci);

drivers/pci/controller/dwc/pcie-dw-rockchip.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@
6262
/* Interrupt Mask Register Related to Miscellaneous Operation */
6363
#define PCIE_CLIENT_INTR_MASK_MISC 0x24
6464

65+
/* Power Management Control Register */
66+
#define PCIE_CLIENT_POWER_CON 0x2c
67+
#define PCIE_CLKREQ_READY FIELD_PREP_WM16(BIT(0), 1)
68+
#define PCIE_CLKREQ_NOT_READY FIELD_PREP_WM16(BIT(0), 0)
69+
#define PCIE_CLKREQ_PULL_DOWN FIELD_PREP_WM16(GENMASK(13, 12), 1)
70+
6571
/* Hot Reset Control Register */
6672
#define PCIE_CLIENT_HOT_RESET_CTRL 0x180
6773
#define PCIE_LTSSM_APP_DLY2_EN BIT(1)
@@ -85,6 +91,7 @@ struct rockchip_pcie {
8591
struct regulator *vpcie3v3;
8692
struct irq_domain *irq_domain;
8793
const struct rockchip_pcie_of_data *data;
94+
bool supports_clkreq;
8895
};
8996

9097
struct rockchip_pcie_of_data {
@@ -200,6 +207,35 @@ static bool rockchip_pcie_link_up(struct dw_pcie *pci)
200207
return FIELD_GET(PCIE_LINKUP_MASK, val) == PCIE_LINKUP;
201208
}
202209

210+
/*
211+
* See e.g. section '11.6.6.4 L1 Substate' in the RK3588 TRM V1.0 for the steps
212+
* needed to support L1 substates. Currently, just enable L1 substates for RC
213+
* mode if CLKREQ# is properly connected and supports-clkreq is present in DT.
214+
* For EP mode, there are more things should be done to actually save power in
215+
* L1 substates, so disable L1 substates until there is proper support.
216+
*/
217+
static void rockchip_pcie_configure_l1ss(struct dw_pcie *pci)
218+
{
219+
struct rockchip_pcie *rockchip = to_rockchip_pcie(pci);
220+
221+
/* Enable L1 substates if CLKREQ# is properly connected */
222+
if (rockchip->supports_clkreq) {
223+
rockchip_pcie_writel_apb(rockchip, PCIE_CLKREQ_READY,
224+
PCIE_CLIENT_POWER_CON);
225+
pci->l1ss_support = true;
226+
return;
227+
}
228+
229+
/*
230+
* Otherwise, assert CLKREQ# unconditionally. Since
231+
* pci->l1ss_support is not set, the DWC core will prevent L1
232+
* Substates support from being advertised.
233+
*/
234+
rockchip_pcie_writel_apb(rockchip,
235+
PCIE_CLKREQ_PULL_DOWN | PCIE_CLKREQ_NOT_READY,
236+
PCIE_CLIENT_POWER_CON);
237+
}
238+
203239
static void rockchip_pcie_enable_l0s(struct dw_pcie *pci)
204240
{
205241
u32 cap, lnkcap;
@@ -264,6 +300,7 @@ static int rockchip_pcie_host_init(struct dw_pcie_rp *pp)
264300
irq_set_chained_handler_and_data(irq, rockchip_pcie_intx_handler,
265301
rockchip);
266302

303+
rockchip_pcie_configure_l1ss(pci);
267304
rockchip_pcie_enable_l0s(pci);
268305

269306
return 0;
@@ -412,6 +449,9 @@ static int rockchip_pcie_resource_get(struct platform_device *pdev,
412449
return dev_err_probe(&pdev->dev, PTR_ERR(rockchip->rst),
413450
"failed to get reset lines\n");
414451

452+
rockchip->supports_clkreq = of_property_read_bool(pdev->dev.of_node,
453+
"supports-clkreq");
454+
415455
return 0;
416456
}
417457

drivers/pci/controller/dwc/pcie-qcom.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,6 +1067,8 @@ static int qcom_pcie_init_2_7_0(struct qcom_pcie *pcie)
10671067
val &= ~REQ_NOT_ENTR_L1;
10681068
writel(val, pcie->parf + PARF_PM_CTRL);
10691069

1070+
pci->l1ss_support = true;
1071+
10701072
val = readl(pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT_V2);
10711073
val |= EN;
10721074
writel(val, pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT_V2);

drivers/pci/controller/dwc/pcie-tegra194.c

Lines changed: 8 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,6 @@ struct tegra_pcie_dw {
260260
u32 msi_ctrl_int;
261261
u32 num_lanes;
262262
u32 cid;
263-
u32 cfg_link_cap_l1sub;
264263
u32 ras_des_cap;
265264
u32 pcie_cap_base;
266265
u32 aspm_cmrt;
@@ -475,8 +474,7 @@ static irqreturn_t tegra_pcie_ep_irq_thread(int irq, void *arg)
475474
return IRQ_HANDLED;
476475

477476
/* If EP doesn't advertise L1SS, just return */
478-
val = dw_pcie_readl_dbi(pci, pcie->cfg_link_cap_l1sub);
479-
if (!(val & (PCI_L1SS_CAP_ASPM_L1_1 | PCI_L1SS_CAP_ASPM_L1_2)))
477+
if (!pci->l1ss_support)
480478
return IRQ_HANDLED;
481479

482480
/* Check if BME is set to '1' */
@@ -608,24 +606,6 @@ static struct pci_ops tegra_pci_ops = {
608606
};
609607

610608
#if defined(CONFIG_PCIEASPM)
611-
static void disable_aspm_l11(struct tegra_pcie_dw *pcie)
612-
{
613-
u32 val;
614-
615-
val = dw_pcie_readl_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub);
616-
val &= ~PCI_L1SS_CAP_ASPM_L1_1;
617-
dw_pcie_writel_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub, val);
618-
}
619-
620-
static void disable_aspm_l12(struct tegra_pcie_dw *pcie)
621-
{
622-
u32 val;
623-
624-
val = dw_pcie_readl_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub);
625-
val &= ~PCI_L1SS_CAP_ASPM_L1_2;
626-
dw_pcie_writel_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub, val);
627-
}
628-
629609
static inline u32 event_counter_prog(struct tegra_pcie_dw *pcie, u32 event)
630610
{
631611
u32 val;
@@ -682,10 +662,9 @@ static int aspm_state_cnt(struct seq_file *s, void *data)
682662
static void init_host_aspm(struct tegra_pcie_dw *pcie)
683663
{
684664
struct dw_pcie *pci = &pcie->pci;
685-
u32 val;
665+
u32 l1ss, val;
686666

687-
val = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_L1SS);
688-
pcie->cfg_link_cap_l1sub = val + PCI_L1SS_CAP;
667+
l1ss = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_L1SS);
689668

690669
pcie->ras_des_cap = dw_pcie_find_ext_capability(&pcie->pci,
691670
PCI_EXT_CAP_ID_VNDR);
@@ -697,11 +676,14 @@ static void init_host_aspm(struct tegra_pcie_dw *pcie)
697676
PCIE_RAS_DES_EVENT_COUNTER_CONTROL, val);
698677

699678
/* Program T_cmrt and T_pwr_on values */
700-
val = dw_pcie_readl_dbi(pci, pcie->cfg_link_cap_l1sub);
679+
val = dw_pcie_readl_dbi(pci, l1ss + PCI_L1SS_CAP);
701680
val &= ~(PCI_L1SS_CAP_CM_RESTORE_TIME | PCI_L1SS_CAP_P_PWR_ON_VALUE);
702681
val |= (pcie->aspm_cmrt << 8);
703682
val |= (pcie->aspm_pwr_on_t << 19);
704-
dw_pcie_writel_dbi(pci, pcie->cfg_link_cap_l1sub, val);
683+
dw_pcie_writel_dbi(pci, l1ss + PCI_L1SS_CAP, val);
684+
685+
if (pcie->supports_clkreq)
686+
pci->l1ss_support = true;
705687

706688
/* Program L0s and L1 entrance latencies */
707689
val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR);
@@ -726,8 +708,6 @@ static void init_debugfs(struct tegra_pcie_dw *pcie)
726708
aspm_state_cnt);
727709
}
728710
#else
729-
static inline void disable_aspm_l12(struct tegra_pcie_dw *pcie) { return; }
730-
static inline void disable_aspm_l11(struct tegra_pcie_dw *pcie) { return; }
731711
static inline void init_host_aspm(struct tegra_pcie_dw *pcie) { return; }
732712
static inline void init_debugfs(struct tegra_pcie_dw *pcie) { return; }
733713
#endif
@@ -931,12 +911,6 @@ static int tegra_pcie_dw_host_init(struct dw_pcie_rp *pp)
931911

932912
init_host_aspm(pcie);
933913

934-
/* Disable ASPM-L1SS advertisement if there is no CLKREQ routing */
935-
if (!pcie->supports_clkreq) {
936-
disable_aspm_l11(pcie);
937-
disable_aspm_l12(pcie);
938-
}
939-
940914
if (!pcie->of_data->has_l1ss_exit_fix) {
941915
val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
942916
val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;
@@ -1871,12 +1845,6 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie)
18711845

18721846
init_host_aspm(pcie);
18731847

1874-
/* Disable ASPM-L1SS advertisement if there is no CLKREQ routing */
1875-
if (!pcie->supports_clkreq) {
1876-
disable_aspm_l11(pcie);
1877-
disable_aspm_l12(pcie);
1878-
}
1879-
18801848
if (!pcie->of_data->has_l1ss_exit_fix) {
18811849
val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
18821850
val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;

0 commit comments

Comments
 (0)