diff options
author | Kazufumi Ikeda <kaz-ikeda@xc.jp.nec.com> | 2020-03-14 20:12:32 +0100 |
---|---|---|
committer | Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> | 2020-05-07 09:34:50 +0100 |
commit | ce351636c67f75a9f282ab69283be231d2c8e845 (patch) | |
tree | e47e8497bb59d422780c2f1e12a246e9c8ad9758 | |
parent | 2b9f217433e31d125fb697ca7974d3de3ecc3e92 (diff) |
PCI: rcar: Add suspend/resume
Add suspend/resume support for rcar. The resume handler reprograms the
hardware based on the software state kept in specific device structures,
so there is no need to save registers on suspend.
Link: https://lore.kernel.org/r/20200314191232.3122290-1-marek.vasut@gmail.com
Link: https://lore.kernel.org/r/20200426123148.56051-1-marek.vasut@gmail.com
Signed-off-by: Kazufumi Ikeda <kaz-ikeda@xc.jp.nec.com>
Signed-off-by: Gaku Inami <gaku.inami.xw@bp.renesas.com>
Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Geert Uytterhoeven <geert+renesas@glider.be>
Cc: Phil Edworthy <phil.edworthy@renesas.com>
Cc: Simon Horman <horms+renesas@verge.net.au>
Cc: Wolfram Sang <wsa@the-dreams.de>
Cc: linux-renesas-soc@vger.kernel.org
-rw-r--r-- | drivers/pci/controller/pcie-rcar.c | 90 |
1 files changed, 75 insertions, 15 deletions
diff --git a/drivers/pci/controller/pcie-rcar.c b/drivers/pci/controller/pcie-rcar.c index 1bae6a4abaae..59e55f56e386 100644 --- a/drivers/pci/controller/pcie-rcar.c +++ b/drivers/pci/controller/pcie-rcar.c @@ -153,6 +153,7 @@ struct rcar_pcie { int root_bus_nr; struct clk *bus_clk; struct rcar_msi msi; + int (*phy_init_fn)(struct rcar_pcie *pcie); }; static void rcar_pci_write_reg(struct rcar_pcie *pcie, u32 val, @@ -453,6 +454,32 @@ done: (macsr & LINK_SPEED) == LINK_SPEED_5_0GTS ? "5" : "2.5"); } +static void rcar_pcie_hw_enable(struct rcar_pcie *pci) +{ + struct resource_entry *win; + LIST_HEAD(res); + int i = 0; + + /* Try setting 5 GT/s link speed */ + rcar_pcie_force_speedup(pci); + + /* Setup PCI resources */ + resource_list_for_each_entry(win, &pci->resources) { + struct resource *res = win->res; + + if (!res->flags) + continue; + + switch (resource_type(res)) { + case IORESOURCE_IO: + case IORESOURCE_MEM: + rcar_pcie_setup_window(i, pci, win); + i++; + break; + } + } +} + static int rcar_pcie_enable(struct rcar_pcie *pcie) { struct device *dev = pcie->dev; @@ -892,11 +919,25 @@ static void rcar_pcie_unmap_msi(struct rcar_pcie *pcie) irq_domain_remove(msi->domain); } +static void rcar_pcie_hw_enable_msi(struct rcar_pcie *pcie) +{ + struct rcar_msi *msi = &pcie->msi; + unsigned long base; + + /* setup MSI data target */ + base = virt_to_phys((void *)msi->pages); + + rcar_pci_write_reg(pcie, lower_32_bits(base) | MSIFE, PCIEMSIALR); + rcar_pci_write_reg(pcie, upper_32_bits(base), PCIEMSIAUR); + + /* enable all MSI interrupts */ + rcar_pci_write_reg(pcie, 0xffffffff, PCIEMSIIER); +} + static int rcar_pcie_enable_msi(struct rcar_pcie *pcie) { struct device *dev = pcie->dev; struct rcar_msi *msi = &pcie->msi; - phys_addr_t base; int err, i; mutex_init(&msi->lock); @@ -935,17 +976,7 @@ static int rcar_pcie_enable_msi(struct rcar_pcie *pcie) /* setup MSI data target */ msi->pages = __get_free_pages(GFP_KERNEL, 0); - if (!msi->pages) { - err = -ENOMEM; - goto err; - } - base = virt_to_phys((void *)msi->pages); - - rcar_pci_write_reg(pcie, lower_32_bits(base) | MSIFE, PCIEMSIALR); - rcar_pci_write_reg(pcie, upper_32_bits(base), PCIEMSIAUR); - - /* enable all MSI interrupts */ - rcar_pci_write_reg(pcie, 0xffffffff, PCIEMSIIER); + rcar_pcie_hw_enable_msi(pcie); return 0; @@ -1117,7 +1148,6 @@ static int rcar_pcie_probe(struct platform_device *pdev) struct rcar_pcie *pcie; u32 data; int err; - int (*phy_init_fn)(struct rcar_pcie *); struct pci_host_bridge *bridge; bridge = pci_alloc_host_bridge(sizeof(*pcie)); @@ -1157,8 +1187,8 @@ static int rcar_pcie_probe(struct platform_device *pdev) if (err) goto err_clk_disable; - phy_init_fn = of_device_get_match_data(dev); - err = phy_init_fn(pcie); + pcie->phy_init_fn = of_device_get_match_data(dev); + err = pcie->phy_init_fn(pcie); if (err) { dev_err(dev, "failed to init PCIe PHY\n"); goto err_clk_disable; @@ -1220,6 +1250,35 @@ err_free_bridge: return err; } +static int __maybe_unused rcar_pcie_resume(struct device *dev) +{ + struct rcar_pcie *pcie = dev_get_drvdata(dev); + unsigned int data; + int err; + + err = rcar_pcie_parse_map_dma_ranges(pcie); + if (err) + return 0; + + /* Failure to get a link might just be that no cards are inserted */ + err = pcie->phy_init_fn(pcie); + if (err) { + dev_info(dev, "PCIe link down\n"); + return 0; + } + + data = rcar_pci_read_reg(pcie, MACSR); + dev_info(dev, "PCIe x%d: link up\n", (data >> 20) & 0x3f); + + /* Enable MSI */ + if (IS_ENABLED(CONFIG_PCI_MSI)) + rcar_pcie_hw_enable_msi(pcie); + + rcar_pcie_hw_enable(pcie); + + return 0; +} + static int rcar_pcie_resume_noirq(struct device *dev) { struct rcar_pcie *pcie = dev_get_drvdata(dev); @@ -1235,6 +1294,7 @@ static int rcar_pcie_resume_noirq(struct device *dev) } static const struct dev_pm_ops rcar_pcie_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(NULL, rcar_pcie_resume) .resume_noirq = rcar_pcie_resume_noirq, }; |