From: Bjorn Helgaas Date: Mon, 15 Jan 2024 18:10:38 +0000 (-0600) Subject: Merge branch 'pci/controller/layerscape' X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=1800c660b08f3f1ab365063dcfe842b5d45d079c;p=linux.git Merge branch 'pci/controller/layerscape' - Add suspend/resume support for Layerscape LS1043a, including software-managed PME_Turn_Off and transitions between L0, L2/L3_Ready Link states (Frank Li) * pci/controller/layerscape: PCI: layerscape: Add suspend/resume for ls1043a PCI: layerscape(ep): Rename pf_* as pf_lut_* PCI: layerscape: Add suspend/resume for ls1021a PCI: layerscape: Add function pointer for exit_from_l2() --- 1800c660b08f3f1ab365063dcfe842b5d45d079c diff --cc drivers/pci/controller/dwc/pci-layerscape.c index 0c3d7ef729cb6,7cdada200de7e..ee6f525681337 --- a/drivers/pci/controller/dwc/pci-layerscape.c +++ b/drivers/pci/controller/dwc/pci-layerscape.c @@@ -168,13 -190,116 +190,116 @@@ static int ls_pcie_host_init(struct dw_ return 0; } + static void scfg_pcie_send_turnoff_msg(struct regmap *scfg, u32 reg, u32 mask) + { + /* Send PME_Turn_Off message */ + regmap_write_bits(scfg, reg, mask, mask); + + /* + * There is no specific register to check for PME_To_Ack from endpoint. + * So on the safe side, wait for PCIE_PME_TO_L2_TIMEOUT_US. + */ + mdelay(PCIE_PME_TO_L2_TIMEOUT_US/1000); + + /* + * Layerscape hardware reference manual recommends clearing the PMXMTTURNOFF bit + * to complete the PME_Turn_Off handshake. + */ + regmap_write_bits(scfg, reg, mask, 0); + } + + static void ls1021a_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_PEXPMWRCR(pcie->index), PMXMTTURNOFF); + } + + static int scfg_pcie_exit_from_l2(struct regmap *scfg, u32 reg, u32 mask) + { + /* Reset the PEX wrapper to bring the link out of L2 */ + regmap_write_bits(scfg, reg, mask, mask); + regmap_write_bits(scfg, reg, mask, 0); + + return 0; + } + + static int ls1021a_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); + + 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, + .init = ls_pcie_host_init, .pme_turn_off = ls_pcie_send_turnoff_msg, }; + static const struct dw_pcie_host_ops ls1021a_pcie_host_ops = { - .host_init = ls_pcie_host_init, ++ .init = ls_pcie_host_init, + .pme_turn_off = ls1021a_pcie_send_turnoff_msg, + }; + static const struct ls_pcie_drvdata ls1021a_drvdata = { - .pm_support = false, + .pm_support = true, + .scfg_support = true, + .ops = &ls1021a_pcie_host_ops, + .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, ++ .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 = {