mirror of
https://github.com/torvalds/linux.git
synced 2026-05-28 09:04:39 +02:00
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
This commit is contained in:
commit
2b12e31cb3
|
|
@ -1060,6 +1060,8 @@ int dw_pcie_setup_rc(struct dw_pcie_rp *pp)
|
|||
PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
|
||||
dw_pcie_writel_dbi(pci, PCI_COMMAND, val);
|
||||
|
||||
dw_pcie_hide_unsupported_l1ss(pci);
|
||||
|
||||
dw_pcie_config_presets(pp);
|
||||
/*
|
||||
* If the platform provides its own child bus config accesses, it means
|
||||
|
|
|
|||
|
|
@ -1081,6 +1081,30 @@ void dw_pcie_edma_remove(struct dw_pcie *pci)
|
|||
dw_edma_remove(&pci->edma);
|
||||
}
|
||||
|
||||
void dw_pcie_hide_unsupported_l1ss(struct dw_pcie *pci)
|
||||
{
|
||||
u16 l1ss;
|
||||
u32 l1ss_cap;
|
||||
|
||||
if (pci->l1ss_support)
|
||||
return;
|
||||
|
||||
l1ss = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_L1SS);
|
||||
if (!l1ss)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Unless the driver claims "l1ss_support", don't advertise L1 PM
|
||||
* Substates because they require CLKREQ# and possibly other
|
||||
* device-specific configuration.
|
||||
*/
|
||||
l1ss_cap = dw_pcie_readl_dbi(pci, l1ss + PCI_L1SS_CAP);
|
||||
l1ss_cap &= ~(PCI_L1SS_CAP_PCIPM_L1_1 | PCI_L1SS_CAP_ASPM_L1_1 |
|
||||
PCI_L1SS_CAP_PCIPM_L1_2 | PCI_L1SS_CAP_ASPM_L1_2 |
|
||||
PCI_L1SS_CAP_L1_PM_SS);
|
||||
dw_pcie_writel_dbi(pci, l1ss + PCI_L1SS_CAP, l1ss_cap);
|
||||
}
|
||||
|
||||
void dw_pcie_setup(struct dw_pcie *pci)
|
||||
{
|
||||
u32 val;
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@
|
|||
#define PORT_LANE_SKEW_INSERT_MASK GENMASK(23, 0)
|
||||
|
||||
#define PCIE_PORT_DEBUG0 0x728
|
||||
#define PORT_LOGIC_LTSSM_STATE_MASK 0x1f
|
||||
#define PORT_LOGIC_LTSSM_STATE_MASK 0x3f
|
||||
#define PORT_LOGIC_LTSSM_STATE_L0 0x11
|
||||
#define PCIE_PORT_DEBUG1 0x72C
|
||||
#define PCIE_PORT_DEBUG1_LINK_UP BIT(4)
|
||||
|
|
@ -516,6 +516,7 @@ struct dw_pcie {
|
|||
int max_link_speed;
|
||||
u8 n_fts[2];
|
||||
struct dw_edma_chip edma;
|
||||
bool l1ss_support; /* L1 PM Substates support */
|
||||
struct clk_bulk_data app_clks[DW_PCIE_NUM_APP_CLKS];
|
||||
struct clk_bulk_data core_clks[DW_PCIE_NUM_CORE_CLKS];
|
||||
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,
|
|||
int type, u64 parent_bus_addr,
|
||||
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_setup(struct dw_pcie *pci);
|
||||
void dw_pcie_iatu_detect(struct dw_pcie *pci);
|
||||
int dw_pcie_edma_detect(struct dw_pcie *pci);
|
||||
|
|
|
|||
|
|
@ -62,6 +62,12 @@
|
|||
/* Interrupt Mask Register Related to Miscellaneous Operation */
|
||||
#define PCIE_CLIENT_INTR_MASK_MISC 0x24
|
||||
|
||||
/* Power Management Control Register */
|
||||
#define PCIE_CLIENT_POWER_CON 0x2c
|
||||
#define PCIE_CLKREQ_READY FIELD_PREP_WM16(BIT(0), 1)
|
||||
#define PCIE_CLKREQ_NOT_READY FIELD_PREP_WM16(BIT(0), 0)
|
||||
#define PCIE_CLKREQ_PULL_DOWN FIELD_PREP_WM16(GENMASK(13, 12), 1)
|
||||
|
||||
/* Hot Reset Control Register */
|
||||
#define PCIE_CLIENT_HOT_RESET_CTRL 0x180
|
||||
#define PCIE_LTSSM_APP_DLY2_EN BIT(1)
|
||||
|
|
@ -85,6 +91,7 @@ struct rockchip_pcie {
|
|||
struct regulator *vpcie3v3;
|
||||
struct irq_domain *irq_domain;
|
||||
const struct rockchip_pcie_of_data *data;
|
||||
bool supports_clkreq;
|
||||
};
|
||||
|
||||
struct rockchip_pcie_of_data {
|
||||
|
|
@ -200,6 +207,35 @@ static bool rockchip_pcie_link_up(struct dw_pcie *pci)
|
|||
return FIELD_GET(PCIE_LINKUP_MASK, val) == PCIE_LINKUP;
|
||||
}
|
||||
|
||||
/*
|
||||
* See e.g. section '11.6.6.4 L1 Substate' in the RK3588 TRM V1.0 for the steps
|
||||
* needed to support L1 substates. Currently, just enable L1 substates for RC
|
||||
* mode if CLKREQ# is properly connected and supports-clkreq is present in DT.
|
||||
* For EP mode, there are more things should be done to actually save power in
|
||||
* L1 substates, so disable L1 substates until there is proper support.
|
||||
*/
|
||||
static void rockchip_pcie_configure_l1ss(struct dw_pcie *pci)
|
||||
{
|
||||
struct rockchip_pcie *rockchip = to_rockchip_pcie(pci);
|
||||
|
||||
/* Enable L1 substates if CLKREQ# is properly connected */
|
||||
if (rockchip->supports_clkreq) {
|
||||
rockchip_pcie_writel_apb(rockchip, PCIE_CLKREQ_READY,
|
||||
PCIE_CLIENT_POWER_CON);
|
||||
pci->l1ss_support = true;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise, assert CLKREQ# unconditionally. Since
|
||||
* pci->l1ss_support is not set, the DWC core will prevent L1
|
||||
* Substates support from being advertised.
|
||||
*/
|
||||
rockchip_pcie_writel_apb(rockchip,
|
||||
PCIE_CLKREQ_PULL_DOWN | PCIE_CLKREQ_NOT_READY,
|
||||
PCIE_CLIENT_POWER_CON);
|
||||
}
|
||||
|
||||
static void rockchip_pcie_enable_l0s(struct dw_pcie *pci)
|
||||
{
|
||||
u32 cap, lnkcap;
|
||||
|
|
@ -264,6 +300,7 @@ static int rockchip_pcie_host_init(struct dw_pcie_rp *pp)
|
|||
irq_set_chained_handler_and_data(irq, rockchip_pcie_intx_handler,
|
||||
rockchip);
|
||||
|
||||
rockchip_pcie_configure_l1ss(pci);
|
||||
rockchip_pcie_enable_l0s(pci);
|
||||
|
||||
return 0;
|
||||
|
|
@ -412,6 +449,9 @@ static int rockchip_pcie_resource_get(struct platform_device *pdev,
|
|||
return dev_err_probe(&pdev->dev, PTR_ERR(rockchip->rst),
|
||||
"failed to get reset lines\n");
|
||||
|
||||
rockchip->supports_clkreq = of_property_read_bool(pdev->dev.of_node,
|
||||
"supports-clkreq");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1067,6 +1067,8 @@ static int qcom_pcie_init_2_7_0(struct qcom_pcie *pcie)
|
|||
val &= ~REQ_NOT_ENTR_L1;
|
||||
writel(val, pcie->parf + PARF_PM_CTRL);
|
||||
|
||||
pci->l1ss_support = true;
|
||||
|
||||
val = readl(pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT_V2);
|
||||
val |= EN;
|
||||
writel(val, pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT_V2);
|
||||
|
|
|
|||
|
|
@ -260,7 +260,6 @@ struct tegra_pcie_dw {
|
|||
u32 msi_ctrl_int;
|
||||
u32 num_lanes;
|
||||
u32 cid;
|
||||
u32 cfg_link_cap_l1sub;
|
||||
u32 ras_des_cap;
|
||||
u32 pcie_cap_base;
|
||||
u32 aspm_cmrt;
|
||||
|
|
@ -475,8 +474,7 @@ static irqreturn_t tegra_pcie_ep_irq_thread(int irq, void *arg)
|
|||
return IRQ_HANDLED;
|
||||
|
||||
/* If EP doesn't advertise L1SS, just return */
|
||||
val = dw_pcie_readl_dbi(pci, pcie->cfg_link_cap_l1sub);
|
||||
if (!(val & (PCI_L1SS_CAP_ASPM_L1_1 | PCI_L1SS_CAP_ASPM_L1_2)))
|
||||
if (!pci->l1ss_support)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
/* Check if BME is set to '1' */
|
||||
|
|
@ -608,24 +606,6 @@ static struct pci_ops tegra_pci_ops = {
|
|||
};
|
||||
|
||||
#if defined(CONFIG_PCIEASPM)
|
||||
static void disable_aspm_l11(struct tegra_pcie_dw *pcie)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = dw_pcie_readl_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub);
|
||||
val &= ~PCI_L1SS_CAP_ASPM_L1_1;
|
||||
dw_pcie_writel_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub, val);
|
||||
}
|
||||
|
||||
static void disable_aspm_l12(struct tegra_pcie_dw *pcie)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = dw_pcie_readl_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub);
|
||||
val &= ~PCI_L1SS_CAP_ASPM_L1_2;
|
||||
dw_pcie_writel_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub, val);
|
||||
}
|
||||
|
||||
static inline u32 event_counter_prog(struct tegra_pcie_dw *pcie, u32 event)
|
||||
{
|
||||
u32 val;
|
||||
|
|
@ -682,10 +662,9 @@ static int aspm_state_cnt(struct seq_file *s, void *data)
|
|||
static void init_host_aspm(struct tegra_pcie_dw *pcie)
|
||||
{
|
||||
struct dw_pcie *pci = &pcie->pci;
|
||||
u32 val;
|
||||
u32 l1ss, val;
|
||||
|
||||
val = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_L1SS);
|
||||
pcie->cfg_link_cap_l1sub = val + PCI_L1SS_CAP;
|
||||
l1ss = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_L1SS);
|
||||
|
||||
pcie->ras_des_cap = dw_pcie_find_ext_capability(&pcie->pci,
|
||||
PCI_EXT_CAP_ID_VNDR);
|
||||
|
|
@ -697,11 +676,14 @@ static void init_host_aspm(struct tegra_pcie_dw *pcie)
|
|||
PCIE_RAS_DES_EVENT_COUNTER_CONTROL, val);
|
||||
|
||||
/* Program T_cmrt and T_pwr_on values */
|
||||
val = dw_pcie_readl_dbi(pci, pcie->cfg_link_cap_l1sub);
|
||||
val = dw_pcie_readl_dbi(pci, l1ss + PCI_L1SS_CAP);
|
||||
val &= ~(PCI_L1SS_CAP_CM_RESTORE_TIME | PCI_L1SS_CAP_P_PWR_ON_VALUE);
|
||||
val |= (pcie->aspm_cmrt << 8);
|
||||
val |= (pcie->aspm_pwr_on_t << 19);
|
||||
dw_pcie_writel_dbi(pci, pcie->cfg_link_cap_l1sub, val);
|
||||
dw_pcie_writel_dbi(pci, l1ss + PCI_L1SS_CAP, val);
|
||||
|
||||
if (pcie->supports_clkreq)
|
||||
pci->l1ss_support = true;
|
||||
|
||||
/* Program L0s and L1 entrance latencies */
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR);
|
||||
|
|
@ -726,8 +708,6 @@ static void init_debugfs(struct tegra_pcie_dw *pcie)
|
|||
aspm_state_cnt);
|
||||
}
|
||||
#else
|
||||
static inline void disable_aspm_l12(struct tegra_pcie_dw *pcie) { return; }
|
||||
static inline void disable_aspm_l11(struct tegra_pcie_dw *pcie) { return; }
|
||||
static inline void init_host_aspm(struct tegra_pcie_dw *pcie) { return; }
|
||||
static inline void init_debugfs(struct tegra_pcie_dw *pcie) { return; }
|
||||
#endif
|
||||
|
|
@ -931,12 +911,6 @@ static int tegra_pcie_dw_host_init(struct dw_pcie_rp *pp)
|
|||
|
||||
init_host_aspm(pcie);
|
||||
|
||||
/* Disable ASPM-L1SS advertisement if there is no CLKREQ routing */
|
||||
if (!pcie->supports_clkreq) {
|
||||
disable_aspm_l11(pcie);
|
||||
disable_aspm_l12(pcie);
|
||||
}
|
||||
|
||||
if (!pcie->of_data->has_l1ss_exit_fix) {
|
||||
val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
|
||||
val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;
|
||||
|
|
@ -1871,12 +1845,6 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie)
|
|||
|
||||
init_host_aspm(pcie);
|
||||
|
||||
/* Disable ASPM-L1SS advertisement if there is no CLKREQ routing */
|
||||
if (!pcie->supports_clkreq) {
|
||||
disable_aspm_l11(pcie);
|
||||
disable_aspm_l12(pcie);
|
||||
}
|
||||
|
||||
if (!pcie->of_data->has_l1ss_exit_fix) {
|
||||
val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
|
||||
val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user