Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1c2bef0a authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

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
parents 4c31ff0b 0bbf6b92
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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:
+154 −127
Original line number Diff line number Diff line
@@ -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,28 +85,27 @@
#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
@@ -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,12 +532,12 @@ 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, PCIETSTR) & DATA_LINK_ACTIVE))
		if (rcar_pci_read_reg(pcie, PCIEPHYSR) & PHYRDY)
			return 0;

		msleep(5);
@@ -543,6 +546,21 @@ static int rcar_pcie_wait_for_dl(struct rcar_pcie *pcie)
	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)
{
	int err;
@@ -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);