diff options
author | Frank Li <Frank.Li@nxp.com> | 2023-12-04 11:08:29 -0500 |
---|---|---|
committer | Lorenzo Pieralisi <lpieralisi@kernel.org> | 2023-12-12 11:17:25 +0100 |
commit | 27b3bcbf8a797d3b18c2aa95928fe65a50066159 (patch) | |
tree | a8045cca1b086d3431bd2f1c338f9861b16aa51a /drivers/pci | |
parent | 762ef94b45d97c220f865f4ea288d2c488c9fd3c (diff) | |
download | linux-27b3bcbf8a797d3b18c2aa95928fe65a50066159.tar.gz linux-27b3bcbf8a797d3b18c2aa95928fe65a50066159.tar.bz2 linux-27b3bcbf8a797d3b18c2aa95928fe65a50066159.zip |
PCI: layerscape: Add suspend/resume for ls1043a
Add suspend/resume support for Layerscape LS1043a.
In the suspend path, PME_Turn_Off message is sent to the endpoint to
transition the link to L2/L3_Ready state. In this SoC, there is no way to
check if the controller has received the PME_To_Ack from the endpoint or
not. So to be on the safer side, the driver just waits for
PCIE_PME_TO_L2_TIMEOUT_US before asserting the SoC specific PMXMTTURNOFF
bit to complete the PME_Turn_Off handshake. Then the link would enter L2/L3
state depending on the VAUX supply.
In the resume path, the link is brought back from L2 to L0 by doing a
software reset.
Link: https://lore.kernel.org/r/20231204160829.2498703-5-Frank.Li@nxp.com
Signed-off-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Lorenzo Pieralisi <lpieralisi@kernel.org>
Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Acked-by: Roy Zang <Roy.Zang@nxp.com>
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/controller/dwc/pci-layerscape.c | 63 |
1 files changed, 62 insertions, 1 deletions
diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c index f3dfb70066fb..7cdada200de7 100644 --- a/drivers/pci/controller/dwc/pci-layerscape.c +++ b/drivers/pci/controller/dwc/pci-layerscape.c @@ -41,6 +41,15 @@ #define SCFG_PEXSFTRSTCR 0x190 #define PEXSR(idx) BIT(idx) +/* LS1043A PEX PME control register */ +#define SCFG_PEXPMECR 0x144 +#define PEXPME(idx) BIT(31 - (idx) * 4) + +/* LS1043A PEX LUT debug register */ +#define LS_PCIE_LDBG 0x7fc +#define LDBG_SR BIT(30) +#define LDBG_WE BIT(31) + #define PCIE_IATU_NUM 6 struct ls_pcie_drvdata { @@ -224,6 +233,45 @@ static int ls1021a_pcie_exit_from_l2(struct dw_pcie_rp *pp) return scfg_pcie_exit_from_l2(pcie->scfg, SCFG_PEXSFTRSTCR, PEXSR(pcie->index)); } +static void ls1043a_pcie_send_turnoff_msg(struct dw_pcie_rp *pp) +{ + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + struct ls_pcie *pcie = to_ls_pcie(pci); + + scfg_pcie_send_turnoff_msg(pcie->scfg, SCFG_PEXPMECR, PEXPME(pcie->index)); +} + +static int ls1043a_pcie_exit_from_l2(struct dw_pcie_rp *pp) +{ + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + struct ls_pcie *pcie = to_ls_pcie(pci); + u32 val; + + /* + * Reset the PEX wrapper to bring the link out of L2. + * LDBG_WE: allows the user to have write access to the PEXDBG[SR] for both setting and + * clearing the soft reset on the PEX module. + * LDBG_SR: When SR is set to 1, the PEX module enters soft reset. + */ + val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG); + val |= LDBG_WE; + ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val); + + val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG); + val |= LDBG_SR; + ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val); + + val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG); + val &= ~LDBG_SR; + ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val); + + val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG); + val &= ~LDBG_WE; + ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val); + + return 0; +} + static const struct dw_pcie_host_ops ls_pcie_host_ops = { .host_init = ls_pcie_host_init, .pme_turn_off = ls_pcie_send_turnoff_msg, @@ -241,6 +289,19 @@ static const struct ls_pcie_drvdata ls1021a_drvdata = { .exit_from_l2 = ls1021a_pcie_exit_from_l2, }; +static const struct dw_pcie_host_ops ls1043a_pcie_host_ops = { + .host_init = ls_pcie_host_init, + .pme_turn_off = ls1043a_pcie_send_turnoff_msg, +}; + +static const struct ls_pcie_drvdata ls1043a_drvdata = { + .pf_lut_off = 0x10000, + .pm_support = true, + .scfg_support = true, + .ops = &ls1043a_pcie_host_ops, + .exit_from_l2 = ls1043a_pcie_exit_from_l2, +}; + static const struct ls_pcie_drvdata layerscape_drvdata = { .pf_lut_off = 0xc0000, .pm_support = true, @@ -252,7 +313,7 @@ static const struct of_device_id ls_pcie_of_match[] = { { .compatible = "fsl,ls1012a-pcie", .data = &layerscape_drvdata }, { .compatible = "fsl,ls1021a-pcie", .data = &ls1021a_drvdata }, { .compatible = "fsl,ls1028a-pcie", .data = &layerscape_drvdata }, - { .compatible = "fsl,ls1043a-pcie", .data = &ls1021a_drvdata }, + { .compatible = "fsl,ls1043a-pcie", .data = &ls1043a_drvdata }, { .compatible = "fsl,ls1046a-pcie", .data = &layerscape_drvdata }, { .compatible = "fsl,ls2080a-pcie", .data = &layerscape_drvdata }, { .compatible = "fsl,ls2085a-pcie", .data = &layerscape_drvdata }, |