From ce351636c67f75a9f282ab69283be231d2c8e845 Mon Sep 17 00:00:00 2001 From: Kazufumi Ikeda Date: Sat, 14 Mar 2020 20:12:32 +0100 Subject: [PATCH] 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 Signed-off-by: Gaku Inami Signed-off-by: Marek Vasut Signed-off-by: Lorenzo Pieralisi Cc: Geert Uytterhoeven Cc: Phil Edworthy Cc: Simon Horman Cc: Wolfram Sang Cc: linux-renesas-soc@vger.kernel.org --- drivers/pci/controller/pcie-rcar.c | 90 +++++++++++++++++++++++++----- 1 file changed, 75 insertions(+), 15 deletions(-) diff --git a/drivers/pci/controller/pcie-rcar.c b/drivers/pci/controller/pcie-rcar.c index 1bae6a4abaaeb..59e55f56e3860 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 @@ static void rcar_pcie_force_speedup(struct rcar_pcie *pcie) (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 @@ static int rcar_pcie_probe(struct platform_device *pdev) 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, };