mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 12:42:02 +00:00
Merge branch 'lorenzo/pci/rcar'
- clean up clocks, MSI, IRQ mappings in R-Car probe failure paths (Marek Vasut) - poll more frequently (5us vs 5ms) while waiting for R-Car data link active (Marek Vasut) - use generic OF parsing interface in R-Car (Vladimir Zapolskiy) - add R-Car V3H (R8A77980) "compatible" string (Sergei Shtylyov) - add R-Car gen3 PHY support (Sergei Shtylyov) - improve R-Car PHYRDY polling (Sergei Shtylyov) - clean up R-Car macros (Marek Vasut) - use runtime PM for R-Car controller clock (Dien Pham) * lorenzo/pci/rcar: PCI: rcar: Remove IRQ mappings in rcar_pcie_enable_msi() failpath PCI: rcar: Teardown MSI setup if rcar_pcie_enable() fails PCI: rcar: Add missing irq_dispose_mapping() into failpath PCI: rcar: Pull bus clock enable/disable from rcar_pcie_get_resources() PCI: rcar: Poll more often in rcar_pcie_wait_for_dl() PCI: rcar: Reuse generic pci_parse_request_of_pci_ranges() function DT: pci: rcar-pci: document R8A77980 bindings PCI: rcar: Factor out rcar_pcie_hw_init() call PCI: rcar: Add R-Car gen3 PHY support PCI: rcar: Remove PHYRDY polling from rcar_pcie_hw_init_h1() PCI: rcar: Poll PHYRDY in rcar_pcie_hw_init() PCI: rcar: Clean up the macros PCI: rcar: Use runtime PM to control controller clock # Conflicts: # drivers/pci/host/pcie-rcar.c
This commit is contained in:
commit
1c2bef0a3f
@ -8,6 +8,7 @@ compatible: "renesas,pcie-r8a7743" for the R8A7743 SoC;
|
||||
"renesas,pcie-r8a7793" for the R8A7793 SoC;
|
||||
"renesas,pcie-r8a7795" for the R8A7795 SoC;
|
||||
"renesas,pcie-r8a7796" for the R8A7796 SoC;
|
||||
"renesas,pcie-r8a77980" for the R8A77980 SoC;
|
||||
"renesas,pcie-rcar-gen2" for a generic R-Car Gen2 or
|
||||
RZ/G1 compatible device.
|
||||
"renesas,pcie-rcar-gen3" for a generic R-Car Gen3 compatible device.
|
||||
@ -32,6 +33,11 @@ compatible: "renesas,pcie-r8a7743" for the R8A7743 SoC;
|
||||
and PCIe bus clocks.
|
||||
- clock-names: from common clock binding: should be "pcie" and "pcie_bus".
|
||||
|
||||
Optional properties:
|
||||
- phys: from common PHY binding: PHY phandle and specifier (only make sense
|
||||
for R-Car gen3 SoCs where the PCIe PHYs have their own register blocks).
|
||||
- phy-names: from common PHY binding: should be "pcie".
|
||||
|
||||
Example:
|
||||
|
||||
SoC-specific DT Entry:
|
||||
|
@ -11,6 +11,7 @@
|
||||
* Author: Phil Edworthy <phil.edworthy@renesas.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
@ -24,6 +25,7 @@
|
||||
#include <linux/of_pci.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/slab.h>
|
||||
@ -32,12 +34,14 @@
|
||||
|
||||
#define PCIECAR 0x000010
|
||||
#define PCIECCTLR 0x000018
|
||||
#define CONFIG_SEND_ENABLE (1 << 31)
|
||||
#define CONFIG_SEND_ENABLE BIT(31)
|
||||
#define TYPE0 (0 << 8)
|
||||
#define TYPE1 (1 << 8)
|
||||
#define TYPE1 BIT(8)
|
||||
#define PCIECDR 0x000020
|
||||
#define PCIEMSR 0x000028
|
||||
#define PCIEINTXR 0x000400
|
||||
#define PCIEPHYSR 0x0007f0
|
||||
#define PHYRDY BIT(0)
|
||||
#define PCIEMSITXR 0x000840
|
||||
|
||||
/* Transfer control */
|
||||
@ -46,7 +50,7 @@
|
||||
#define PCIETSTR 0x02004
|
||||
#define DATA_LINK_ACTIVE 1
|
||||
#define PCIEERRFR 0x02020
|
||||
#define UNSUPPORTED_REQUEST (1 << 4)
|
||||
#define UNSUPPORTED_REQUEST BIT(4)
|
||||
#define PCIEMSIFR 0x02044
|
||||
#define PCIEMSIALR 0x02048
|
||||
#define MSIFE 1
|
||||
@ -59,17 +63,17 @@
|
||||
/* local address reg & mask */
|
||||
#define PCIELAR(x) (0x02200 + ((x) * 0x20))
|
||||
#define PCIELAMR(x) (0x02208 + ((x) * 0x20))
|
||||
#define LAM_PREFETCH (1 << 3)
|
||||
#define LAM_64BIT (1 << 2)
|
||||
#define LAR_ENABLE (1 << 1)
|
||||
#define LAM_PREFETCH BIT(3)
|
||||
#define LAM_64BIT BIT(2)
|
||||
#define LAR_ENABLE BIT(1)
|
||||
|
||||
/* PCIe address reg & mask */
|
||||
#define PCIEPALR(x) (0x03400 + ((x) * 0x20))
|
||||
#define PCIEPAUR(x) (0x03404 + ((x) * 0x20))
|
||||
#define PCIEPAMR(x) (0x03408 + ((x) * 0x20))
|
||||
#define PCIEPTCTLR(x) (0x0340c + ((x) * 0x20))
|
||||
#define PAR_ENABLE (1 << 31)
|
||||
#define IO_SPACE (1 << 8)
|
||||
#define PAR_ENABLE BIT(31)
|
||||
#define IO_SPACE BIT(8)
|
||||
|
||||
/* Configuration */
|
||||
#define PCICONF(x) (0x010000 + ((x) * 0x4))
|
||||
@ -81,47 +85,46 @@
|
||||
#define IDSETR1 0x011004
|
||||
#define TLCTLR 0x011048
|
||||
#define MACSR 0x011054
|
||||
#define SPCHGFIN (1 << 4)
|
||||
#define SPCHGFAIL (1 << 6)
|
||||
#define SPCHGSUC (1 << 7)
|
||||
#define SPCHGFIN BIT(4)
|
||||
#define SPCHGFAIL BIT(6)
|
||||
#define SPCHGSUC BIT(7)
|
||||
#define LINK_SPEED (0xf << 16)
|
||||
#define LINK_SPEED_2_5GTS (1 << 16)
|
||||
#define LINK_SPEED_5_0GTS (2 << 16)
|
||||
#define MACCTLR 0x011058
|
||||
#define SPEED_CHANGE (1 << 24)
|
||||
#define SCRAMBLE_DISABLE (1 << 27)
|
||||
#define SPEED_CHANGE BIT(24)
|
||||
#define SCRAMBLE_DISABLE BIT(27)
|
||||
#define MACS2R 0x011078
|
||||
#define MACCGSPSETR 0x011084
|
||||
#define SPCNGRSN (1 << 31)
|
||||
#define SPCNGRSN BIT(31)
|
||||
|
||||
/* R-Car H1 PHY */
|
||||
#define H1_PCIEPHYADRR 0x04000c
|
||||
#define WRITE_CMD (1 << 16)
|
||||
#define PHY_ACK (1 << 24)
|
||||
#define WRITE_CMD BIT(16)
|
||||
#define PHY_ACK BIT(24)
|
||||
#define RATE_POS 12
|
||||
#define LANE_POS 8
|
||||
#define ADR_POS 0
|
||||
#define H1_PCIEPHYDOUTR 0x040014
|
||||
#define H1_PCIEPHYSR 0x040018
|
||||
|
||||
/* R-Car Gen2 PHY */
|
||||
#define GEN2_PCIEPHYADDR 0x780
|
||||
#define GEN2_PCIEPHYDATA 0x784
|
||||
#define GEN2_PCIEPHYCTRL 0x78c
|
||||
|
||||
#define INT_PCI_MSI_NR 32
|
||||
#define INT_PCI_MSI_NR 32
|
||||
|
||||
#define RCONF(x) (PCICONF(0)+(x))
|
||||
#define RPMCAP(x) (PMCAP(0)+(x))
|
||||
#define REXPCAP(x) (EXPCAP(0)+(x))
|
||||
#define RVCCAP(x) (VCCAP(0)+(x))
|
||||
#define RCONF(x) (PCICONF(0) + (x))
|
||||
#define RPMCAP(x) (PMCAP(0) + (x))
|
||||
#define REXPCAP(x) (EXPCAP(0) + (x))
|
||||
#define RVCCAP(x) (VCCAP(0) + (x))
|
||||
|
||||
#define PCIE_CONF_BUS(b) (((b) & 0xff) << 24)
|
||||
#define PCIE_CONF_DEV(d) (((d) & 0x1f) << 19)
|
||||
#define PCIE_CONF_FUNC(f) (((f) & 0x7) << 16)
|
||||
#define PCIE_CONF_BUS(b) (((b) & 0xff) << 24)
|
||||
#define PCIE_CONF_DEV(d) (((d) & 0x1f) << 19)
|
||||
#define PCIE_CONF_FUNC(f) (((f) & 0x7) << 16)
|
||||
|
||||
#define RCAR_PCI_MAX_RESOURCES 4
|
||||
#define MAX_NR_INBOUND_MAPS 6
|
||||
#define RCAR_PCI_MAX_RESOURCES 4
|
||||
#define MAX_NR_INBOUND_MAPS 6
|
||||
|
||||
struct rcar_msi {
|
||||
DECLARE_BITMAP(used, INT_PCI_MSI_NR);
|
||||
@ -141,10 +144,10 @@ static inline struct rcar_msi *to_rcar_msi(struct msi_controller *chip)
|
||||
/* Structure representing the PCIe interface */
|
||||
struct rcar_pcie {
|
||||
struct device *dev;
|
||||
struct phy *phy;
|
||||
void __iomem *base;
|
||||
struct list_head resources;
|
||||
int root_bus_nr;
|
||||
struct clk *clk;
|
||||
struct clk *bus_clk;
|
||||
struct rcar_msi msi;
|
||||
};
|
||||
@ -529,15 +532,30 @@ static void phy_write_reg(struct rcar_pcie *pcie,
|
||||
phy_wait_for_ack(pcie);
|
||||
}
|
||||
|
||||
static int rcar_pcie_wait_for_dl(struct rcar_pcie *pcie)
|
||||
static int rcar_pcie_wait_for_phyrdy(struct rcar_pcie *pcie)
|
||||
{
|
||||
unsigned int timeout = 10;
|
||||
|
||||
while (timeout--) {
|
||||
if (rcar_pci_read_reg(pcie, PCIEPHYSR) & PHYRDY)
|
||||
return 0;
|
||||
|
||||
msleep(5);
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int rcar_pcie_wait_for_dl(struct rcar_pcie *pcie)
|
||||
{
|
||||
unsigned int timeout = 10000;
|
||||
|
||||
while (timeout--) {
|
||||
if ((rcar_pci_read_reg(pcie, PCIETSTR) & DATA_LINK_ACTIVE))
|
||||
return 0;
|
||||
|
||||
msleep(5);
|
||||
udelay(5);
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
@ -553,6 +571,10 @@ static int rcar_pcie_hw_init(struct rcar_pcie *pcie)
|
||||
/* Set mode */
|
||||
rcar_pci_write_reg(pcie, 1, PCIEMSR);
|
||||
|
||||
err = rcar_pcie_wait_for_phyrdy(pcie);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* Initial header for port config space is type 1, set the device
|
||||
* class to match. Hardware takes care of propagating the IDSETR
|
||||
@ -607,10 +629,8 @@ static int rcar_pcie_hw_init(struct rcar_pcie *pcie)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rcar_pcie_hw_init_h1(struct rcar_pcie *pcie)
|
||||
static int rcar_pcie_phy_init_h1(struct rcar_pcie *pcie)
|
||||
{
|
||||
unsigned int timeout = 10;
|
||||
|
||||
/* Initialize the phy */
|
||||
phy_write_reg(pcie, 0, 0x42, 0x1, 0x0EC34191);
|
||||
phy_write_reg(pcie, 1, 0x42, 0x1, 0x0EC34180);
|
||||
@ -629,17 +649,10 @@ static int rcar_pcie_hw_init_h1(struct rcar_pcie *pcie)
|
||||
phy_write_reg(pcie, 0, 0x64, 0x1, 0x3F0F1F0F);
|
||||
phy_write_reg(pcie, 0, 0x66, 0x1, 0x00008000);
|
||||
|
||||
while (timeout--) {
|
||||
if (rcar_pci_read_reg(pcie, H1_PCIEPHYSR))
|
||||
return rcar_pcie_hw_init(pcie);
|
||||
|
||||
msleep(5);
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rcar_pcie_hw_init_gen2(struct rcar_pcie *pcie)
|
||||
static int rcar_pcie_phy_init_gen2(struct rcar_pcie *pcie)
|
||||
{
|
||||
/*
|
||||
* These settings come from the R-Car Series, 2nd Generation User's
|
||||
@ -656,7 +669,18 @@ static int rcar_pcie_hw_init_gen2(struct rcar_pcie *pcie)
|
||||
rcar_pci_write_reg(pcie, 0x00000001, GEN2_PCIEPHYCTRL);
|
||||
rcar_pci_write_reg(pcie, 0x00000006, GEN2_PCIEPHYCTRL);
|
||||
|
||||
return rcar_pcie_hw_init(pcie);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rcar_pcie_phy_init_gen3(struct rcar_pcie *pcie)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = phy_init(pcie->phy);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return phy_power_on(pcie->phy);
|
||||
}
|
||||
|
||||
static int rcar_msi_alloc(struct rcar_msi *chip)
|
||||
@ -844,6 +868,20 @@ static const struct irq_domain_ops msi_domain_ops = {
|
||||
.map = rcar_msi_map,
|
||||
};
|
||||
|
||||
static void rcar_pcie_unmap_msi(struct rcar_pcie *pcie)
|
||||
{
|
||||
struct rcar_msi *msi = &pcie->msi;
|
||||
int i, irq;
|
||||
|
||||
for (i = 0; i < INT_PCI_MSI_NR; i++) {
|
||||
irq = irq_find_mapping(msi->domain, i);
|
||||
if (irq > 0)
|
||||
irq_dispose_mapping(irq);
|
||||
}
|
||||
|
||||
irq_domain_remove(msi->domain);
|
||||
}
|
||||
|
||||
static int rcar_pcie_enable_msi(struct rcar_pcie *pcie)
|
||||
{
|
||||
struct device *dev = pcie->dev;
|
||||
@ -898,16 +936,35 @@ static int rcar_pcie_enable_msi(struct rcar_pcie *pcie)
|
||||
return 0;
|
||||
|
||||
err:
|
||||
irq_domain_remove(msi->domain);
|
||||
rcar_pcie_unmap_msi(pcie);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void rcar_pcie_teardown_msi(struct rcar_pcie *pcie)
|
||||
{
|
||||
struct rcar_msi *msi = &pcie->msi;
|
||||
|
||||
/* Disable all MSI interrupts */
|
||||
rcar_pci_write_reg(pcie, 0, PCIEMSIIER);
|
||||
|
||||
/* Disable address decoding of the MSI interrupt, MSIFE */
|
||||
rcar_pci_write_reg(pcie, 0, PCIEMSIALR);
|
||||
|
||||
free_pages(msi->pages, 0);
|
||||
|
||||
rcar_pcie_unmap_msi(pcie);
|
||||
}
|
||||
|
||||
static int rcar_pcie_get_resources(struct rcar_pcie *pcie)
|
||||
{
|
||||
struct device *dev = pcie->dev;
|
||||
struct resource res;
|
||||
int err, i;
|
||||
|
||||
pcie->phy = devm_phy_optional_get(dev, "pcie");
|
||||
if (IS_ERR(pcie->phy))
|
||||
return PTR_ERR(pcie->phy);
|
||||
|
||||
err = of_address_to_resource(dev->of_node, 0, &res);
|
||||
if (err)
|
||||
return err;
|
||||
@ -916,30 +973,17 @@ static int rcar_pcie_get_resources(struct rcar_pcie *pcie)
|
||||
if (IS_ERR(pcie->base))
|
||||
return PTR_ERR(pcie->base);
|
||||
|
||||
pcie->clk = devm_clk_get(dev, "pcie");
|
||||
if (IS_ERR(pcie->clk)) {
|
||||
dev_err(dev, "cannot get platform clock\n");
|
||||
return PTR_ERR(pcie->clk);
|
||||
}
|
||||
err = clk_prepare_enable(pcie->clk);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
pcie->bus_clk = devm_clk_get(dev, "pcie_bus");
|
||||
if (IS_ERR(pcie->bus_clk)) {
|
||||
dev_err(dev, "cannot get pcie bus clock\n");
|
||||
err = PTR_ERR(pcie->bus_clk);
|
||||
goto fail_clk;
|
||||
return PTR_ERR(pcie->bus_clk);
|
||||
}
|
||||
err = clk_prepare_enable(pcie->bus_clk);
|
||||
if (err)
|
||||
goto fail_clk;
|
||||
|
||||
i = irq_of_parse_and_map(dev->of_node, 0);
|
||||
if (!i) {
|
||||
dev_err(dev, "cannot get platform resources for msi interrupt\n");
|
||||
err = -ENOENT;
|
||||
goto err_map_reg;
|
||||
goto err_irq1;
|
||||
}
|
||||
pcie->msi.irq1 = i;
|
||||
|
||||
@ -947,17 +991,15 @@ static int rcar_pcie_get_resources(struct rcar_pcie *pcie)
|
||||
if (!i) {
|
||||
dev_err(dev, "cannot get platform resources for msi interrupt\n");
|
||||
err = -ENOENT;
|
||||
goto err_map_reg;
|
||||
goto err_irq2;
|
||||
}
|
||||
pcie->msi.irq2 = i;
|
||||
|
||||
return 0;
|
||||
|
||||
err_map_reg:
|
||||
clk_disable_unprepare(pcie->bus_clk);
|
||||
fail_clk:
|
||||
clk_disable_unprepare(pcie->clk);
|
||||
|
||||
err_irq2:
|
||||
irq_dispose_mapping(pcie->msi.irq1);
|
||||
err_irq1:
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -1053,62 +1095,28 @@ static int rcar_pcie_parse_map_dma_ranges(struct rcar_pcie *pcie,
|
||||
}
|
||||
|
||||
static const struct of_device_id rcar_pcie_of_match[] = {
|
||||
{ .compatible = "renesas,pcie-r8a7779", .data = rcar_pcie_hw_init_h1 },
|
||||
{ .compatible = "renesas,pcie-r8a7779",
|
||||
.data = rcar_pcie_phy_init_h1 },
|
||||
{ .compatible = "renesas,pcie-r8a7790",
|
||||
.data = rcar_pcie_hw_init_gen2 },
|
||||
.data = rcar_pcie_phy_init_gen2 },
|
||||
{ .compatible = "renesas,pcie-r8a7791",
|
||||
.data = rcar_pcie_hw_init_gen2 },
|
||||
.data = rcar_pcie_phy_init_gen2 },
|
||||
{ .compatible = "renesas,pcie-rcar-gen2",
|
||||
.data = rcar_pcie_hw_init_gen2 },
|
||||
{ .compatible = "renesas,pcie-r8a7795", .data = rcar_pcie_hw_init },
|
||||
{ .compatible = "renesas,pcie-rcar-gen3", .data = rcar_pcie_hw_init },
|
||||
.data = rcar_pcie_phy_init_gen2 },
|
||||
{ .compatible = "renesas,pcie-r8a7795",
|
||||
.data = rcar_pcie_phy_init_gen3 },
|
||||
{ .compatible = "renesas,pcie-rcar-gen3",
|
||||
.data = rcar_pcie_phy_init_gen3 },
|
||||
{},
|
||||
};
|
||||
|
||||
static int rcar_pcie_parse_request_of_pci_ranges(struct rcar_pcie *pci)
|
||||
{
|
||||
int err;
|
||||
struct device *dev = pci->dev;
|
||||
resource_size_t iobase;
|
||||
struct resource_entry *win, *tmp;
|
||||
|
||||
err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
|
||||
&pci->resources, &iobase);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = devm_request_pci_bus_resources(dev, &pci->resources);
|
||||
if (err)
|
||||
goto out_release_res;
|
||||
|
||||
resource_list_for_each_entry_safe(win, tmp, &pci->resources) {
|
||||
struct resource *res = win->res;
|
||||
|
||||
if (resource_type(res) == IORESOURCE_IO) {
|
||||
err = pci_remap_iospace(res, iobase);
|
||||
if (err) {
|
||||
dev_warn(dev, "error %d: failed to map resource %pR\n",
|
||||
err, res);
|
||||
|
||||
resource_list_destroy_entry(win);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_release_res:
|
||||
pci_free_resource_list(&pci->resources);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int rcar_pcie_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct rcar_pcie *pcie;
|
||||
unsigned int data;
|
||||
int err;
|
||||
int (*hw_init_fn)(struct rcar_pcie *);
|
||||
int (*phy_init_fn)(struct rcar_pcie *);
|
||||
struct pci_host_bridge *bridge;
|
||||
|
||||
bridge = pci_alloc_host_bridge(sizeof(*pcie));
|
||||
@ -1119,36 +1127,45 @@ static int rcar_pcie_probe(struct platform_device *pdev)
|
||||
|
||||
pcie->dev = dev;
|
||||
|
||||
INIT_LIST_HEAD(&pcie->resources);
|
||||
|
||||
err = rcar_pcie_parse_request_of_pci_ranges(pcie);
|
||||
err = pci_parse_request_of_pci_ranges(dev, &pcie->resources, NULL);
|
||||
if (err)
|
||||
goto err_free_bridge;
|
||||
|
||||
pm_runtime_enable(pcie->dev);
|
||||
err = pm_runtime_get_sync(pcie->dev);
|
||||
if (err < 0) {
|
||||
dev_err(pcie->dev, "pm_runtime_get_sync failed\n");
|
||||
goto err_pm_disable;
|
||||
}
|
||||
|
||||
err = rcar_pcie_get_resources(pcie);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "failed to request resources: %d\n", err);
|
||||
goto err_free_resource_list;
|
||||
goto err_pm_put;
|
||||
}
|
||||
|
||||
err = clk_prepare_enable(pcie->bus_clk);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to enable bus clock: %d\n", err);
|
||||
goto err_unmap_msi_irqs;
|
||||
}
|
||||
|
||||
err = rcar_pcie_parse_map_dma_ranges(pcie, dev->of_node);
|
||||
if (err)
|
||||
goto err_free_resource_list;
|
||||
goto err_clk_disable;
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
err = pm_runtime_get_sync(dev);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "pm_runtime_get_sync failed\n");
|
||||
goto err_pm_disable;
|
||||
phy_init_fn = of_device_get_match_data(dev);
|
||||
err = phy_init_fn(pcie);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to init PCIe PHY\n");
|
||||
goto err_clk_disable;
|
||||
}
|
||||
|
||||
/* Failure to get a link might just be that no cards are inserted */
|
||||
hw_init_fn = of_device_get_match_data(dev);
|
||||
err = hw_init_fn(pcie);
|
||||
if (err) {
|
||||
if (rcar_pcie_hw_init(pcie)) {
|
||||
dev_info(dev, "PCIe link down\n");
|
||||
err = -ENODEV;
|
||||
goto err_pm_put;
|
||||
goto err_clk_disable;
|
||||
}
|
||||
|
||||
data = rcar_pci_read_reg(pcie, MACSR);
|
||||
@ -1160,24 +1177,34 @@ static int rcar_pcie_probe(struct platform_device *pdev)
|
||||
dev_err(dev,
|
||||
"failed to enable MSI support: %d\n",
|
||||
err);
|
||||
goto err_pm_put;
|
||||
goto err_clk_disable;
|
||||
}
|
||||
}
|
||||
|
||||
err = rcar_pcie_enable(pcie);
|
||||
if (err)
|
||||
goto err_pm_put;
|
||||
goto err_msi_teardown;
|
||||
|
||||
return 0;
|
||||
|
||||
err_msi_teardown:
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI))
|
||||
rcar_pcie_teardown_msi(pcie);
|
||||
|
||||
err_clk_disable:
|
||||
clk_disable_unprepare(pcie->bus_clk);
|
||||
|
||||
err_unmap_msi_irqs:
|
||||
irq_dispose_mapping(pcie->msi.irq2);
|
||||
irq_dispose_mapping(pcie->msi.irq1);
|
||||
|
||||
err_pm_put:
|
||||
pm_runtime_put(dev);
|
||||
|
||||
err_pm_disable:
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
err_free_resource_list:
|
||||
pci_free_resource_list(&pcie->resources);
|
||||
|
||||
err_free_bridge:
|
||||
pci_free_host_bridge(bridge);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user