|
@@ -11,6 +11,7 @@
|
|
* Author: Phil Edworthy <phil.edworthy@renesas.com>
|
|
* Author: Phil Edworthy <phil.edworthy@renesas.com>
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
+#include <linux/bitops.h>
|
|
#include <linux/clk.h>
|
|
#include <linux/clk.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/interrupt.h>
|
|
@@ -24,6 +25,7 @@
|
|
#include <linux/of_pci.h>
|
|
#include <linux/of_pci.h>
|
|
#include <linux/of_platform.h>
|
|
#include <linux/of_platform.h>
|
|
#include <linux/pci.h>
|
|
#include <linux/pci.h>
|
|
|
|
+#include <linux/phy/phy.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/pm_runtime.h>
|
|
#include <linux/pm_runtime.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/slab.h>
|
|
@@ -32,12 +34,14 @@
|
|
|
|
|
|
#define PCIECAR 0x000010
|
|
#define PCIECAR 0x000010
|
|
#define PCIECCTLR 0x000018
|
|
#define PCIECCTLR 0x000018
|
|
-#define CONFIG_SEND_ENABLE (1 << 31)
|
|
|
|
|
|
+#define CONFIG_SEND_ENABLE BIT(31)
|
|
#define TYPE0 (0 << 8)
|
|
#define TYPE0 (0 << 8)
|
|
-#define TYPE1 (1 << 8)
|
|
|
|
|
|
+#define TYPE1 BIT(8)
|
|
#define PCIECDR 0x000020
|
|
#define PCIECDR 0x000020
|
|
#define PCIEMSR 0x000028
|
|
#define PCIEMSR 0x000028
|
|
#define PCIEINTXR 0x000400
|
|
#define PCIEINTXR 0x000400
|
|
|
|
+#define PCIEPHYSR 0x0007f0
|
|
|
|
+#define PHYRDY BIT(0)
|
|
#define PCIEMSITXR 0x000840
|
|
#define PCIEMSITXR 0x000840
|
|
|
|
|
|
/* Transfer control */
|
|
/* Transfer control */
|
|
@@ -46,7 +50,7 @@
|
|
#define PCIETSTR 0x02004
|
|
#define PCIETSTR 0x02004
|
|
#define DATA_LINK_ACTIVE 1
|
|
#define DATA_LINK_ACTIVE 1
|
|
#define PCIEERRFR 0x02020
|
|
#define PCIEERRFR 0x02020
|
|
-#define UNSUPPORTED_REQUEST (1 << 4)
|
|
|
|
|
|
+#define UNSUPPORTED_REQUEST BIT(4)
|
|
#define PCIEMSIFR 0x02044
|
|
#define PCIEMSIFR 0x02044
|
|
#define PCIEMSIALR 0x02048
|
|
#define PCIEMSIALR 0x02048
|
|
#define MSIFE 1
|
|
#define MSIFE 1
|
|
@@ -59,17 +63,17 @@
|
|
/* local address reg & mask */
|
|
/* local address reg & mask */
|
|
#define PCIELAR(x) (0x02200 + ((x) * 0x20))
|
|
#define PCIELAR(x) (0x02200 + ((x) * 0x20))
|
|
#define PCIELAMR(x) (0x02208 + ((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 */
|
|
/* PCIe address reg & mask */
|
|
#define PCIEPALR(x) (0x03400 + ((x) * 0x20))
|
|
#define PCIEPALR(x) (0x03400 + ((x) * 0x20))
|
|
#define PCIEPAUR(x) (0x03404 + ((x) * 0x20))
|
|
#define PCIEPAUR(x) (0x03404 + ((x) * 0x20))
|
|
#define PCIEPAMR(x) (0x03408 + ((x) * 0x20))
|
|
#define PCIEPAMR(x) (0x03408 + ((x) * 0x20))
|
|
#define PCIEPTCTLR(x) (0x0340c + ((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 */
|
|
/* Configuration */
|
|
#define PCICONF(x) (0x010000 + ((x) * 0x4))
|
|
#define PCICONF(x) (0x010000 + ((x) * 0x4))
|
|
@@ -81,47 +85,46 @@
|
|
#define IDSETR1 0x011004
|
|
#define IDSETR1 0x011004
|
|
#define TLCTLR 0x011048
|
|
#define TLCTLR 0x011048
|
|
#define MACSR 0x011054
|
|
#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 (0xf << 16)
|
|
#define LINK_SPEED_2_5GTS (1 << 16)
|
|
#define LINK_SPEED_2_5GTS (1 << 16)
|
|
#define LINK_SPEED_5_0GTS (2 << 16)
|
|
#define LINK_SPEED_5_0GTS (2 << 16)
|
|
#define MACCTLR 0x011058
|
|
#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 MACS2R 0x011078
|
|
#define MACCGSPSETR 0x011084
|
|
#define MACCGSPSETR 0x011084
|
|
-#define SPCNGRSN (1 << 31)
|
|
|
|
|
|
+#define SPCNGRSN BIT(31)
|
|
|
|
|
|
/* R-Car H1 PHY */
|
|
/* R-Car H1 PHY */
|
|
#define H1_PCIEPHYADRR 0x04000c
|
|
#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 RATE_POS 12
|
|
#define LANE_POS 8
|
|
#define LANE_POS 8
|
|
#define ADR_POS 0
|
|
#define ADR_POS 0
|
|
#define H1_PCIEPHYDOUTR 0x040014
|
|
#define H1_PCIEPHYDOUTR 0x040014
|
|
-#define H1_PCIEPHYSR 0x040018
|
|
|
|
|
|
|
|
/* R-Car Gen2 PHY */
|
|
/* R-Car Gen2 PHY */
|
|
#define GEN2_PCIEPHYADDR 0x780
|
|
#define GEN2_PCIEPHYADDR 0x780
|
|
#define GEN2_PCIEPHYDATA 0x784
|
|
#define GEN2_PCIEPHYDATA 0x784
|
|
#define GEN2_PCIEPHYCTRL 0x78c
|
|
#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 {
|
|
struct rcar_msi {
|
|
DECLARE_BITMAP(used, INT_PCI_MSI_NR);
|
|
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 */
|
|
/* Structure representing the PCIe interface */
|
|
struct rcar_pcie {
|
|
struct rcar_pcie {
|
|
struct device *dev;
|
|
struct device *dev;
|
|
|
|
+ struct phy *phy;
|
|
void __iomem *base;
|
|
void __iomem *base;
|
|
struct list_head resources;
|
|
struct list_head resources;
|
|
int root_bus_nr;
|
|
int root_bus_nr;
|
|
- struct clk *clk;
|
|
|
|
struct clk *bus_clk;
|
|
struct clk *bus_clk;
|
|
struct rcar_msi msi;
|
|
struct rcar_msi msi;
|
|
};
|
|
};
|
|
@@ -529,12 +532,12 @@ static void phy_write_reg(struct rcar_pcie *pcie,
|
|
phy_wait_for_ack(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;
|
|
unsigned int timeout = 10;
|
|
|
|
|
|
while (timeout--) {
|
|
while (timeout--) {
|
|
- if ((rcar_pci_read_reg(pcie, PCIETSTR) & DATA_LINK_ACTIVE))
|
|
|
|
|
|
+ if (rcar_pci_read_reg(pcie, PCIEPHYSR) & PHYRDY)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
msleep(5);
|
|
msleep(5);
|
|
@@ -543,6 +546,21 @@ static int rcar_pcie_wait_for_dl(struct rcar_pcie *pcie)
|
|
return -ETIMEDOUT;
|
|
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;
|
|
|
|
+
|
|
|
|
+ udelay(5);
|
|
|
|
+ cpu_relax();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return -ETIMEDOUT;
|
|
|
|
+}
|
|
|
|
+
|
|
static int rcar_pcie_hw_init(struct rcar_pcie *pcie)
|
|
static int rcar_pcie_hw_init(struct rcar_pcie *pcie)
|
|
{
|
|
{
|
|
int err;
|
|
int err;
|
|
@@ -553,6 +571,10 @@ static int rcar_pcie_hw_init(struct rcar_pcie *pcie)
|
|
/* Set mode */
|
|
/* Set mode */
|
|
rcar_pci_write_reg(pcie, 1, PCIEMSR);
|
|
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
|
|
* Initial header for port config space is type 1, set the device
|
|
* class to match. Hardware takes care of propagating the IDSETR
|
|
* 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;
|
|
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 */
|
|
/* Initialize the phy */
|
|
phy_write_reg(pcie, 0, 0x42, 0x1, 0x0EC34191);
|
|
phy_write_reg(pcie, 0, 0x42, 0x1, 0x0EC34191);
|
|
phy_write_reg(pcie, 1, 0x42, 0x1, 0x0EC34180);
|
|
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, 0x64, 0x1, 0x3F0F1F0F);
|
|
phy_write_reg(pcie, 0, 0x66, 0x1, 0x00008000);
|
|
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
|
|
* 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, 0x00000001, GEN2_PCIEPHYCTRL);
|
|
rcar_pci_write_reg(pcie, 0x00000006, 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)
|
|
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,
|
|
.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)
|
|
static int rcar_pcie_enable_msi(struct rcar_pcie *pcie)
|
|
{
|
|
{
|
|
struct device *dev = pcie->dev;
|
|
struct device *dev = pcie->dev;
|
|
@@ -898,16 +936,35 @@ static int rcar_pcie_enable_msi(struct rcar_pcie *pcie)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
err:
|
|
err:
|
|
- irq_domain_remove(msi->domain);
|
|
|
|
|
|
+ rcar_pcie_unmap_msi(pcie);
|
|
return err;
|
|
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)
|
|
static int rcar_pcie_get_resources(struct rcar_pcie *pcie)
|
|
{
|
|
{
|
|
struct device *dev = pcie->dev;
|
|
struct device *dev = pcie->dev;
|
|
struct resource res;
|
|
struct resource res;
|
|
int err, i;
|
|
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);
|
|
err = of_address_to_resource(dev->of_node, 0, &res);
|
|
if (err)
|
|
if (err)
|
|
return err;
|
|
return err;
|
|
@@ -916,30 +973,17 @@ static int rcar_pcie_get_resources(struct rcar_pcie *pcie)
|
|
if (IS_ERR(pcie->base))
|
|
if (IS_ERR(pcie->base))
|
|
return PTR_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");
|
|
pcie->bus_clk = devm_clk_get(dev, "pcie_bus");
|
|
if (IS_ERR(pcie->bus_clk)) {
|
|
if (IS_ERR(pcie->bus_clk)) {
|
|
dev_err(dev, "cannot get pcie bus clock\n");
|
|
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);
|
|
i = irq_of_parse_and_map(dev->of_node, 0);
|
|
if (!i) {
|
|
if (!i) {
|
|
dev_err(dev, "cannot get platform resources for msi interrupt\n");
|
|
dev_err(dev, "cannot get platform resources for msi interrupt\n");
|
|
err = -ENOENT;
|
|
err = -ENOENT;
|
|
- goto err_map_reg;
|
|
|
|
|
|
+ goto err_irq1;
|
|
}
|
|
}
|
|
pcie->msi.irq1 = i;
|
|
pcie->msi.irq1 = i;
|
|
|
|
|
|
@@ -947,17 +991,15 @@ static int rcar_pcie_get_resources(struct rcar_pcie *pcie)
|
|
if (!i) {
|
|
if (!i) {
|
|
dev_err(dev, "cannot get platform resources for msi interrupt\n");
|
|
dev_err(dev, "cannot get platform resources for msi interrupt\n");
|
|
err = -ENOENT;
|
|
err = -ENOENT;
|
|
- goto err_map_reg;
|
|
|
|
|
|
+ goto err_irq2;
|
|
}
|
|
}
|
|
pcie->msi.irq2 = i;
|
|
pcie->msi.irq2 = i;
|
|
|
|
|
|
return 0;
|
|
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;
|
|
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[] = {
|
|
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",
|
|
{ .compatible = "renesas,pcie-r8a7790",
|
|
- .data = rcar_pcie_hw_init_gen2 },
|
|
|
|
|
|
+ .data = rcar_pcie_phy_init_gen2 },
|
|
{ .compatible = "renesas,pcie-r8a7791",
|
|
{ .compatible = "renesas,pcie-r8a7791",
|
|
- .data = rcar_pcie_hw_init_gen2 },
|
|
|
|
|
|
+ .data = rcar_pcie_phy_init_gen2 },
|
|
{ .compatible = "renesas,pcie-rcar-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)
|
|
static int rcar_pcie_probe(struct platform_device *pdev)
|
|
{
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
struct device *dev = &pdev->dev;
|
|
struct rcar_pcie *pcie;
|
|
struct rcar_pcie *pcie;
|
|
unsigned int data;
|
|
unsigned int data;
|
|
int err;
|
|
int err;
|
|
- int (*hw_init_fn)(struct rcar_pcie *);
|
|
|
|
|
|
+ int (*phy_init_fn)(struct rcar_pcie *);
|
|
struct pci_host_bridge *bridge;
|
|
struct pci_host_bridge *bridge;
|
|
|
|
|
|
bridge = pci_alloc_host_bridge(sizeof(*pcie));
|
|
bridge = pci_alloc_host_bridge(sizeof(*pcie));
|
|
@@ -1119,36 +1127,45 @@ static int rcar_pcie_probe(struct platform_device *pdev)
|
|
|
|
|
|
pcie->dev = dev;
|
|
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)
|
|
if (err)
|
|
goto err_free_bridge;
|
|
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);
|
|
err = rcar_pcie_get_resources(pcie);
|
|
if (err < 0) {
|
|
if (err < 0) {
|
|
dev_err(dev, "failed to request resources: %d\n", err);
|
|
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);
|
|
err = rcar_pcie_parse_map_dma_ranges(pcie, dev->of_node);
|
|
if (err)
|
|
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 */
|
|
/* 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");
|
|
dev_info(dev, "PCIe link down\n");
|
|
err = -ENODEV;
|
|
err = -ENODEV;
|
|
- goto err_pm_put;
|
|
|
|
|
|
+ goto err_clk_disable;
|
|
}
|
|
}
|
|
|
|
|
|
data = rcar_pci_read_reg(pcie, MACSR);
|
|
data = rcar_pci_read_reg(pcie, MACSR);
|
|
@@ -1160,24 +1177,34 @@ static int rcar_pcie_probe(struct platform_device *pdev)
|
|
dev_err(dev,
|
|
dev_err(dev,
|
|
"failed to enable MSI support: %d\n",
|
|
"failed to enable MSI support: %d\n",
|
|
err);
|
|
err);
|
|
- goto err_pm_put;
|
|
|
|
|
|
+ goto err_clk_disable;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
err = rcar_pcie_enable(pcie);
|
|
err = rcar_pcie_enable(pcie);
|
|
if (err)
|
|
if (err)
|
|
- goto err_pm_put;
|
|
|
|
|
|
+ goto err_msi_teardown;
|
|
|
|
|
|
return 0;
|
|
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:
|
|
err_pm_put:
|
|
pm_runtime_put(dev);
|
|
pm_runtime_put(dev);
|
|
|
|
|
|
err_pm_disable:
|
|
err_pm_disable:
|
|
pm_runtime_disable(dev);
|
|
pm_runtime_disable(dev);
|
|
-
|
|
|
|
-err_free_resource_list:
|
|
|
|
pci_free_resource_list(&pcie->resources);
|
|
pci_free_resource_list(&pcie->resources);
|
|
|
|
+
|
|
err_free_bridge:
|
|
err_free_bridge:
|
|
pci_free_host_bridge(bridge);
|
|
pci_free_host_bridge(bridge);
|
|
|
|
|