提交 ce351636 编写于 作者: K Kazufumi Ikeda 提交者: Lorenzo Pieralisi

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.comSigned-off-by: NKazufumi Ikeda <kaz-ikeda@xc.jp.nec.com>
Signed-off-by: NGaku Inami <gaku.inami.xw@bp.renesas.com>
Signed-off-by: NMarek Vasut <marek.vasut+renesas@gmail.com>
Signed-off-by: NLorenzo 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
上级 2b9f2174
......@@ -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,
};
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册