linux-pci.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/6] PCI: tegra: Fixes and Tegra124 support
@ 2014-08-26 14:57 Thierry Reding
  2014-08-26 14:57 ` [PATCH v2 1/6] resource: Add device-managed request/release_resource() Thierry Reding
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Thierry Reding @ 2014-08-26 14:57 UTC (permalink / raw)
  To: Bjorn Helgaas; +Cc: Stephen Warren, linux-pci, linux-tegra, linux-kernel

From: Thierry Reding <treding@nvidia.com>

This series implements various fixes and adds support for Tegra124 to the
Tegra PCIe controller driver.

Patches 1 and 2 were already sent out separately earlier on but haven't been
applied yet, so I'm including them here for convenience.

Patches 3 to 5 are various fixes that should make the driver more reliable,
though they don't (except maybe for patch 4) fix any known issues.

Patch 6 finally adds support for Tegra124.

Thierry

Eric Yuen (1):
  PCI: tegra: Make sure the PCIe PLL is really reset

Peter Daifuku (1):
  PCI: tegra: Fix extended configuration space mapping

Thierry Reding (4):
  resource: Add device-managed request/release_resource()
  PCI: tegra: Implement a proper resource hierarchy
  PCI: tegra: Clear CLKREQ# enable on port disable
  PCI: tegra: Add Tegra124 support

 .../bindings/pci/nvidia,tegra20-pcie.txt           |  25 +-
 Documentation/driver-model/devres.txt              |   2 +
 drivers/pci/host/pci-tegra.c                       | 257 ++++++++++++++++++---
 include/linux/ioport.h                             |   5 +
 kernel/resource.c                                  |  70 ++++++
 5 files changed, 323 insertions(+), 36 deletions(-)

-- 
2.0.4


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2 1/6] resource: Add device-managed request/release_resource()
  2014-08-26 14:57 [PATCH v2 0/6] PCI: tegra: Fixes and Tegra124 support Thierry Reding
@ 2014-08-26 14:57 ` Thierry Reding
  2014-08-26 14:57 ` [PATCH v2 2/6] PCI: tegra: Implement a proper resource hierarchy Thierry Reding
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Thierry Reding @ 2014-08-26 14:57 UTC (permalink / raw)
  To: Bjorn Helgaas; +Cc: Stephen Warren, linux-pci, linux-tegra, linux-kernel

From: Thierry Reding <treding@nvidia.com>

Provide device-managed implementations of the request_resource() and
release_resource() functions. Upon failure to request a resource, the
new devm_request_resource() function will output an error message for
consistent error reporting.

Acked-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
Changes in v2:
- use more natural flow for error handling
- don't needlessly check for NULL pointers

 Documentation/driver-model/devres.txt |  2 +
 include/linux/ioport.h                |  5 +++
 kernel/resource.c                     | 70 +++++++++++++++++++++++++++++++++++
 3 files changed, 77 insertions(+)

diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index d14710b04439..befc3fe12ba6 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -264,8 +264,10 @@ IIO
 IO region
   devm_release_mem_region()
   devm_release_region()
+  devm_release_resource()
   devm_request_mem_region()
   devm_request_region()
+  devm_request_resource()
 
 IOMAP
   devm_ioport_map()
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index 142ec544167c..2c5250222278 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -215,6 +215,11 @@ static inline int __deprecated check_region(resource_size_t s,
 
 /* Wrappers for managed devices */
 struct device;
+
+extern int devm_request_resource(struct device *dev, struct resource *root,
+				 struct resource *new);
+extern void devm_release_resource(struct device *dev, struct resource *new);
+
 #define devm_request_region(dev,start,n,name) \
 	__devm_request_region(dev, &ioport_resource, (start), (n), (name))
 #define devm_request_mem_region(dev,start,n,name) \
diff --git a/kernel/resource.c b/kernel/resource.c
index 60c5a3856ab7..46322019ab7d 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -1245,6 +1245,76 @@ int release_mem_region_adjustable(struct resource *parent,
 /*
  * Managed region resource
  */
+static void devm_resource_release(struct device *dev, void *ptr)
+{
+	struct resource **r = ptr;
+
+	release_resource(*r);
+}
+
+/**
+ * devm_request_resource() - request and reserve an I/O or memory resource
+ * @dev: device for which to request the resource
+ * @root: root of the resource tree from which to request the resource
+ * @new: descriptor of the resource to request
+ *
+ * This is a device-managed version of request_resource(). There is usually
+ * no need to release resources requested by this function explicitly since
+ * that will be taken care of when the device is unbound from its driver.
+ * If for some reason the resource needs to be released explicitly, because
+ * of ordering issues for example, drivers must call devm_release_resource()
+ * rather than the regular release_resource().
+ *
+ * When a conflict is detected between any existing resources and the newly
+ * requested resource, an error message will be printed.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int devm_request_resource(struct device *dev, struct resource *root,
+			  struct resource *new)
+{
+	struct resource *conflict, **ptr;
+
+	ptr = devres_alloc(devm_resource_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return -ENOMEM;
+
+	*ptr = new;
+
+	conflict = request_resource_conflict(root, new);
+	if (conflict) {
+		dev_err(dev, "resource collision: %pR conflicts with %s %pR\n",
+			new, conflict->name, conflict);
+		devres_free(ptr);
+		return -EBUSY;
+	}
+
+	devres_add(dev, ptr);
+	return 0;
+}
+EXPORT_SYMBOL(devm_request_resource);
+
+static int devm_resource_match(struct device *dev, void *res, void *data)
+{
+	struct resource **ptr = res;
+
+	return *ptr == data;
+}
+
+/**
+ * devm_release_resource() - release a previously requested resource
+ * @dev: device for which to release the resource
+ * @new: descriptor of the resource to release
+ *
+ * Releases a resource previously requested using devm_request_resource().
+ */
+void devm_release_resource(struct device *dev, struct resource *new)
+{
+	WARN_ON(devres_release(dev, devm_resource_release, devm_resource_match,
+			       new));
+}
+EXPORT_SYMBOL(devm_release_resource);
+
 struct region_devres {
 	struct resource *parent;
 	resource_size_t start;
-- 
2.0.4


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 2/6] PCI: tegra: Implement a proper resource hierarchy
  2014-08-26 14:57 [PATCH v2 0/6] PCI: tegra: Fixes and Tegra124 support Thierry Reding
  2014-08-26 14:57 ` [PATCH v2 1/6] resource: Add device-managed request/release_resource() Thierry Reding
@ 2014-08-26 14:57 ` Thierry Reding
  2014-08-26 14:57 ` [PATCH v2 3/6] PCI: tegra: Clear CLKREQ# enable on port disable Thierry Reding
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Thierry Reding @ 2014-08-26 14:57 UTC (permalink / raw)
  To: Bjorn Helgaas; +Cc: Stephen Warren, linux-pci, linux-tegra, linux-kernel

From: Thierry Reding <treding@nvidia.com>

Currently the resource hierarchy generated from the PCIe host bridge is
completely flat:

	$ cat /proc/iomem
	00000000-00000fff : /pcie-controller@00003000/pci@1,0
	00003000-000037ff : pads
	00003800-000039ff : afi
	10000000-1fffffff : cs
	28000000-28003fff : r8169
	28004000-28004fff : r8169
	...

The host bridge driver doesn't request all the resources that are used.
Windows allocated to each of the root ports aren't tracked, so there is
no way for resources allocated to individual devices to be matched up
with the correct parent resource by the PCI core.

This patch addresses this in two steps. It first takes the union of all
regions associated with the PCIe host bridge (control registers, root
port registers, configuration space, I/O and prefetchable as well as
non-prefetchable memory regions) and uses it as the new root of the
resource hierarchy.

Subsequently, regions are allocated from within this new root resource
so that the resource tree looks much more like what's expected:

	# cat /proc/iomem
	00000000-3fffffff : /pcie-controller@00003000
	  00000000-00000fff : /pcie-controller@00003000/pci@1,0
	  00003000-000037ff : pads
	  00003800-000039ff : afi
	  10000000-1fffffff : cs
	  20000000-27ffffff : non-prefetchable
	  28000000-3fffffff : prefetchable
	    28000000-280fffff : PCI Bus 0000:01
	      28000000-28003fff : 0000:01:00.0
	        28000000-28003fff : r8169
	      28004000-28004fff : 0000:01:00.0
	        28004000-28004fff : r8169
	...

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/pci/host/pci-tegra.c | 32 +++++++++++++++++++++++++++++---
 1 file changed, 29 insertions(+), 3 deletions(-)

diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c
index 0fb0fdb223d5..83fa33e16650 100644
--- a/drivers/pci/host/pci-tegra.c
+++ b/drivers/pci/host/pci-tegra.c
@@ -253,6 +253,7 @@ struct tegra_pcie {
 	struct list_head buses;
 	struct resource *cs;
 
+	struct resource all;
 	struct resource io;
 	struct resource mem;
 	struct resource prefetch;
@@ -626,6 +627,15 @@ DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_relax_enable);
 static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
 {
 	struct tegra_pcie *pcie = sys_to_pcie(sys);
+	int err;
+
+	err = devm_request_resource(pcie->dev, &pcie->all, &pcie->mem);
+	if (err < 0)
+		return err;
+
+	err = devm_request_resource(pcie->dev, &pcie->all, &pcie->prefetch);
+	if (err)
+		return err;
 
 	pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset);
 	pci_add_resource_offset(&sys->resources, &pcie->prefetch,
@@ -1514,6 +1524,12 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
 	struct resource res;
 	int err;
 
+	memset(&pcie->all, 0, sizeof(pcie->all));
+	pcie->all.flags = IORESOURCE_MEM;
+	pcie->all.name = np->full_name;
+	pcie->all.start = ~0;
+	pcie->all.end = 0;
+
 	if (of_pci_range_parser_init(&parser, np)) {
 		dev_err(pcie->dev, "missing \"ranges\" property\n");
 		return -EINVAL;
@@ -1525,21 +1541,31 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
 		switch (res.flags & IORESOURCE_TYPE_BITS) {
 		case IORESOURCE_IO:
 			memcpy(&pcie->io, &res, sizeof(res));
-			pcie->io.name = "I/O";
+			pcie->io.name = np->full_name;
 			break;
 
 		case IORESOURCE_MEM:
 			if (res.flags & IORESOURCE_PREFETCH) {
 				memcpy(&pcie->prefetch, &res, sizeof(res));
-				pcie->prefetch.name = "PREFETCH";
+				pcie->prefetch.name = "prefetchable";
 			} else {
 				memcpy(&pcie->mem, &res, sizeof(res));
-				pcie->mem.name = "MEM";
+				pcie->mem.name = "non-prefetchable";
 			}
 			break;
 		}
+
+		if (res.start <= pcie->all.start)
+			pcie->all.start = res.start;
+
+		if (res.end >= pcie->all.end)
+			pcie->all.end = res.end;
 	}
 
+	err = devm_request_resource(pcie->dev, &iomem_resource, &pcie->all);
+	if (err < 0)
+		return err;
+
 	err = of_pci_parse_bus_range(np, &pcie->busn);
 	if (err < 0) {
 		dev_err(pcie->dev, "failed to parse ranges property: %d\n",
-- 
2.0.4


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 3/6] PCI: tegra: Clear CLKREQ# enable on port disable
  2014-08-26 14:57 [PATCH v2 0/6] PCI: tegra: Fixes and Tegra124 support Thierry Reding
  2014-08-26 14:57 ` [PATCH v2 1/6] resource: Add device-managed request/release_resource() Thierry Reding
  2014-08-26 14:57 ` [PATCH v2 2/6] PCI: tegra: Implement a proper resource hierarchy Thierry Reding
@ 2014-08-26 14:57 ` Thierry Reding
  2014-08-26 14:57 ` [PATCH v2 4/6] PCI: tegra: Fix extended configuration space mapping Thierry Reding
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Thierry Reding @ 2014-08-26 14:57 UTC (permalink / raw)
  To: Bjorn Helgaas; +Cc: Stephen Warren, linux-pci, linux-tegra, linux-kernel

From: Thierry Reding <treding@nvidia.com>

When a root port is disabled, disable the CLKREQ# signal if available.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/pci/host/pci-tegra.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c
index 83fa33e16650..bd53b123218b 100644
--- a/drivers/pci/host/pci-tegra.c
+++ b/drivers/pci/host/pci-tegra.c
@@ -569,6 +569,7 @@ static void tegra_pcie_port_enable(struct tegra_pcie_port *port)
 
 static void tegra_pcie_port_disable(struct tegra_pcie_port *port)
 {
+	const struct tegra_pcie_soc_data *soc = port->pcie->soc_data;
 	unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port);
 	unsigned long value;
 
@@ -579,6 +580,10 @@ static void tegra_pcie_port_disable(struct tegra_pcie_port *port)
 
 	/* disable reference clock */
 	value = afi_readl(port->pcie, ctrl);
+
+	if (soc->has_pex_clkreq_en)
+		value &= ~AFI_PEX_CTRL_CLKREQ_EN;
+
 	value &= ~AFI_PEX_CTRL_REFCLK_EN;
 	afi_writel(port->pcie, value, ctrl);
 }
-- 
2.0.4


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 4/6] PCI: tegra: Fix extended configuration space mapping
  2014-08-26 14:57 [PATCH v2 0/6] PCI: tegra: Fixes and Tegra124 support Thierry Reding
                   ` (2 preceding siblings ...)
  2014-08-26 14:57 ` [PATCH v2 3/6] PCI: tegra: Clear CLKREQ# enable on port disable Thierry Reding
@ 2014-08-26 14:57 ` Thierry Reding
  2014-08-26 14:57 ` [PATCH v2 5/6] PCI: tegra: Make sure the PCIe PLL is really reset Thierry Reding
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Thierry Reding @ 2014-08-26 14:57 UTC (permalink / raw)
  To: Bjorn Helgaas; +Cc: Stephen Warren, linux-pci, linux-tegra, linux-kernel

From: Peter Daifuku <pdaifuku@nvidia.com>

The 16 chunks of 64 KiB that need to be stitched together to make up the
configuration space for one bus (1 MiB) are located 24 bits (== 16 MiB)
apart in physical address space. This is determined by the start of the
extended register field (bits 24-27) in the physical mapping.

Signed-off-by: Peter Daifuku <pdaifuku@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/pci/host/pci-tegra.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c
index bd53b123218b..8264bce77750 100644
--- a/drivers/pci/host/pci-tegra.c
+++ b/drivers/pci/host/pci-tegra.c
@@ -383,7 +383,7 @@ static struct tegra_pcie_bus *tegra_pcie_bus_alloc(struct tegra_pcie *pcie,
 	for (i = 0; i < 16; i++) {
 		unsigned long virt = (unsigned long)bus->area->addr +
 				     i * SZ_64K;
-		phys_addr_t phys = cs + i * SZ_1M + busnr * SZ_64K;
+		phys_addr_t phys = cs + i * SZ_16M + busnr * SZ_64K;
 
 		err = ioremap_page_range(virt, virt + SZ_64K, phys, prot);
 		if (err < 0) {
-- 
2.0.4


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 5/6] PCI: tegra: Make sure the PCIe PLL is really reset
  2014-08-26 14:57 [PATCH v2 0/6] PCI: tegra: Fixes and Tegra124 support Thierry Reding
                   ` (3 preceding siblings ...)
  2014-08-26 14:57 ` [PATCH v2 4/6] PCI: tegra: Fix extended configuration space mapping Thierry Reding
@ 2014-08-26 14:57 ` Thierry Reding
  2014-08-26 14:57 ` [PATCH v2 6/6] PCI: tegra: Add Tegra124 support Thierry Reding
  2014-08-26 15:08 ` [PATCH v2 0/6] PCI: tegra: Fixes and " Thierry Reding
  6 siblings, 0 replies; 8+ messages in thread
From: Thierry Reding @ 2014-08-26 14:57 UTC (permalink / raw)
  To: Bjorn Helgaas; +Cc: Stephen Warren, linux-pci, linux-tegra, linux-kernel

From: Eric Yuen <eyuen@nvidia.com>

Depending on the prior state of the controller, the PLL reset may not be
pulsed. Clear the register bit and set it after a small delay to ensure
that the PLL is really reset.

Signed-off-by: Eric Yuen <eyuen@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/pci/host/pci-tegra.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c
index 8264bce77750..0ce43764dd36 100644
--- a/drivers/pci/host/pci-tegra.c
+++ b/drivers/pci/host/pci-tegra.c
@@ -849,6 +849,13 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
 	value |= PADS_PLL_CTL_REFCLK_INTERNAL_CML | soc->tx_ref_sel;
 	pads_writel(pcie, value, soc->pads_pll_ctl);
 
+	/* reset PLL */
+	value = pads_readl(pcie, soc->pads_pll_ctl);
+	value &= ~PADS_PLL_CTL_RST_B4SM;
+	pads_writel(pcie, value, soc->pads_pll_ctl);
+
+	usleep_range(20, 100);
+
 	/* take PLL out of reset  */
 	value = pads_readl(pcie, soc->pads_pll_ctl);
 	value |= PADS_PLL_CTL_RST_B4SM;
-- 
2.0.4


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 6/6] PCI: tegra: Add Tegra124 support
  2014-08-26 14:57 [PATCH v2 0/6] PCI: tegra: Fixes and Tegra124 support Thierry Reding
                   ` (4 preceding siblings ...)
  2014-08-26 14:57 ` [PATCH v2 5/6] PCI: tegra: Make sure the PCIe PLL is really reset Thierry Reding
@ 2014-08-26 14:57 ` Thierry Reding
  2014-08-26 15:08 ` [PATCH v2 0/6] PCI: tegra: Fixes and " Thierry Reding
  6 siblings, 0 replies; 8+ messages in thread
From: Thierry Reding @ 2014-08-26 14:57 UTC (permalink / raw)
  To: Bjorn Helgaas; +Cc: Stephen Warren, linux-pci, linux-tegra, linux-kernel

From: Thierry Reding <treding@nvidia.com>

The PCIe controller on Tegra124 has two root ports that can be used in a
x4/x1 or x2/x1 configuration and can run at PCIe 2.0 link speeds (up to
5 GT/s). The PHY programming has been moved into a separate controller,
so the driver now needs to request an external PHY referenced using the
device tree.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 .../bindings/pci/nvidia,tegra20-pcie.txt           |  25 ++-
 drivers/pci/host/pci-tegra.c                       | 211 ++++++++++++++++++---
 2 files changed, 204 insertions(+), 32 deletions(-)

diff --git a/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt b/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt
index 0823362548dc..bc0b09b0dfb5 100644
--- a/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt
+++ b/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt
@@ -1,7 +1,10 @@
 NVIDIA Tegra PCIe controller
 
 Required properties:
-- compatible: "nvidia,tegra20-pcie" or "nvidia,tegra30-pcie"
+- compatible: Must be one of:
+  - "nvidia,tegra20-pcie"
+  - "nvidia,tegra30-pcie"
+  - "nvidia,tegra124-pcie"
 - device_type: Must be "pci"
 - reg: A list of physical base address and length for each set of controller
   registers. Must contain an entry for each entry in the reg-names property.
@@ -57,6 +60,11 @@ Required properties:
   - afi
   - pcie_x
 
+Required properties on Tegra124 and later:
+- phys: Must contain an entry for each entry in phy-names.
+- phy-names: Must include the following entries:
+  - pcie
+
 Power supplies for Tegra20:
 - avdd-pex-supply: Power supply for analog PCIe logic. Must supply 1.05 V.
 - vdd-pex-supply: Power supply for digital PCIe I/O. Must supply 1.05 V.
@@ -84,6 +92,21 @@ Power supplies for Tegra30:
     - avdd-pexb-supply: Power supply for analog PCIe logic. Must supply 1.05 V.
     - vdd-pexb-supply: Power supply for digital PCIe I/O. Must supply 1.05 V.
 
+Power supplies for Tegra124:
+- Required:
+  - avddio-pex-supply: Power supply for analog PCIe logic. Must supply 1.05 V.
+  - vddio-pex-supply: Power supply for digital PCIe I/O. Must supply 1.05 V.
+  - avdd-pex-pll-supply: Power supply for dedicated (internal) PCIe PLL. Must
+    supply 1.05 V.
+  - hvdd-pex-supply: High-voltage supply for PCIe I/O and PCIe output clocks.
+    Must supply 3.3 V.
+  - hvdd-pex-plle-supply: High-voltage supply for PLLE (shared with USB3).
+    Must supply 3.3 V.
+  - vddio-pex-ctl-supply: Power supply for PCIe control I/O partition. Must
+    supply 2.8-3.3 V.
+  - avdd-plle-supply: Power supply for PLLE (shared with USB3). Must
+    supply 1.05 V.
+
 Root ports are defined as subnodes of the PCIe controller node.
 
 Required properties:
diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c
index 0ce43764dd36..a04525a93487 100644
--- a/drivers/pci/host/pci-tegra.c
+++ b/drivers/pci/host/pci-tegra.c
@@ -38,6 +38,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/reset.h>
 #include <linux/sizes.h>
@@ -115,13 +116,20 @@
 
 #define AFI_INTR_CODE			0xb8
 #define  AFI_INTR_CODE_MASK		0xf
-#define  AFI_INTR_AXI_SLAVE_ERROR	1
-#define  AFI_INTR_AXI_DECODE_ERROR	2
+#define  AFI_INTR_INI_SLAVE_ERROR	1
+#define  AFI_INTR_INI_DECODE_ERROR	2
 #define  AFI_INTR_TARGET_ABORT		3
 #define  AFI_INTR_MASTER_ABORT		4
 #define  AFI_INTR_INVALID_WRITE		5
 #define  AFI_INTR_LEGACY		6
 #define  AFI_INTR_FPCI_DECODE_ERROR	7
+#define  AFI_INTR_AXI_DECODE_ERROR	8
+#define  AFI_INTR_FPCI_TIMEOUT		9
+#define  AFI_INTR_PE_PRSNT_SENSE	10
+#define  AFI_INTR_PE_CLKREQ_SENSE	11
+#define  AFI_INTR_CLKCLAMP_SENSE	12
+#define  AFI_INTR_RDY4PD_SENSE		13
+#define  AFI_INTR_P2P_ERROR		14
 
 #define AFI_INTR_SIGNATURE	0xbc
 #define AFI_UPPER_FPCI_ADDRESS	0xc0
@@ -152,8 +160,10 @@
 #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK	(0xf << 20)
 #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE	(0x0 << 20)
 #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_420	(0x0 << 20)
+#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X2_X1	(0x0 << 20)
 #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL	(0x1 << 20)
 #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_222	(0x1 << 20)
+#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1	(0x1 << 20)
 #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411	(0x2 << 20)
 
 #define AFI_FUSE			0x104
@@ -165,12 +175,21 @@
 #define  AFI_PEX_CTRL_RST		(1 << 0)
 #define  AFI_PEX_CTRL_CLKREQ_EN		(1 << 1)
 #define  AFI_PEX_CTRL_REFCLK_EN		(1 << 3)
+#define  AFI_PEX_CTRL_OVERRIDE_EN	(1 << 4)
+
+#define AFI_PLLE_CONTROL		0x160
+#define  AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL (1 << 9)
+#define  AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN (1 << 1)
 
 #define AFI_PEXBIAS_CTRL_0		0x168
 
 #define RP_VEND_XP	0x00000F00
 #define  RP_VEND_XP_DL_UP	(1 << 30)
 
+#define RP_PRIV_MISC	0x00000FE0
+#define  RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT (0xE << 0)
+#define  RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT (0xF << 0)
+
 #define RP_LINK_CONTROL_STATUS			0x00000090
 #define  RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE	0x20000000
 #define  RP_LINK_CONTROL_STATUS_LINKSTAT_MASK	0x3fff0000
@@ -197,6 +216,7 @@
 
 #define PADS_REFCLK_CFG0			0x000000C8
 #define PADS_REFCLK_CFG1			0x000000CC
+#define PADS_REFCLK_BIAS			0x000000D0
 
 /*
  * Fields in PADS_REFCLK_CFG*. Those registers form an array of 16-bit
@@ -236,6 +256,7 @@ struct tegra_pcie_soc_data {
 	bool has_pex_bias_ctrl;
 	bool has_intr_prsnt_sense;
 	bool has_cml_clk;
+	bool has_gen2;
 };
 
 static inline struct tegra_msi *to_tegra_msi(struct msi_chip *chip)
@@ -268,6 +289,8 @@ struct tegra_pcie {
 	struct reset_control *afi_rst;
 	struct reset_control *pcie_xrst;
 
+	struct phy *phy;
+
 	struct tegra_msi msi;
 
 	struct list_head ports;
@@ -562,6 +585,8 @@ static void tegra_pcie_port_enable(struct tegra_pcie_port *port)
 	if (soc->has_pex_clkreq_en)
 		value |= AFI_PEX_CTRL_CLKREQ_EN;
 
+	value |= AFI_PEX_CTRL_OVERRIDE_EN;
+
 	afi_writel(port->pcie, value, ctrl);
 
 	tegra_pcie_port_reset(port);
@@ -699,9 +724,15 @@ static irqreturn_t tegra_pcie_isr(int irq, void *arg)
 		"Target abort",
 		"Master abort",
 		"Invalid write",
+		"Legacy interrupt",
 		"Response decoding error",
 		"AXI response decoding error",
 		"Transaction timeout",
+		"Slot present pin change",
+		"Slot clock request change",
+		"TMS clock ramp change",
+		"TMS ready for power down",
+		"Peer2Peer error",
 	};
 	struct tegra_pcie *pcie = arg;
 	u32 code, signature;
@@ -807,30 +838,27 @@ static void tegra_pcie_setup_translations(struct tegra_pcie *pcie)
 	afi_writel(pcie, 0, AFI_MSI_BAR_SZ);
 }
 
-static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
+static int tegra_pcie_pll_wait(struct tegra_pcie *pcie, unsigned long timeout)
 {
 	const struct tegra_pcie_soc_data *soc = pcie->soc_data;
-	struct tegra_pcie_port *port;
-	unsigned int timeout;
-	unsigned long value;
-
-	/* power down PCIe slot clock bias pad */
-	if (soc->has_pex_bias_ctrl)
-		afi_writel(pcie, 0, AFI_PEXBIAS_CTRL_0);
+	u32 value;
 
-	/* configure mode and disable all ports */
-	value = afi_readl(pcie, AFI_PCIE_CONFIG);
-	value &= ~AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK;
-	value |= AFI_PCIE_CONFIG_PCIE_DISABLE_ALL | pcie->xbar_config;
+	timeout = jiffies + msecs_to_jiffies(timeout);
 
-	list_for_each_entry(port, &pcie->ports, list)
-		value &= ~AFI_PCIE_CONFIG_PCIE_DISABLE(port->index);
+	while (time_before(jiffies, timeout)) {
+		value = pads_readl(pcie, soc->pads_pll_ctl);
+		if (value & PADS_PLL_CTL_LOCKDET)
+			return 0;
+	}
 
-	afi_writel(pcie, value, AFI_PCIE_CONFIG);
+	return -ETIMEDOUT;
+}
 
-	value = afi_readl(pcie, AFI_FUSE);
-	value |= AFI_FUSE_PCIE_T0_GEN2_DIS;
-	afi_writel(pcie, value, AFI_FUSE);
+static int tegra_pcie_phy_enable(struct tegra_pcie *pcie)
+{
+	const struct tegra_pcie_soc_data *soc = pcie->soc_data;
+	u32 value;
+	int err;
 
 	/* initialize internal PHY, enable up to 16 PCIE lanes */
 	pads_writel(pcie, 0x0, PADS_CTL_SEL);
@@ -868,15 +896,11 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
 		pads_writel(pcie, PADS_REFCLK_CFG_VALUE, PADS_REFCLK_CFG1);
 
 	/* wait for the PLL to lock */
-	timeout = 300;
-	do {
-		value = pads_readl(pcie, soc->pads_pll_ctl);
-		usleep_range(1000, 2000);
-		if (--timeout == 0) {
-			pr_err("Tegra PCIe error: timeout waiting for PLL\n");
-			return -EBUSY;
-		}
-	} while (!(value & PADS_PLL_CTL_LOCKDET));
+	err = tegra_pcie_pll_wait(pcie, 500);
+	if (err < 0) {
+		dev_err(pcie->dev, "PLL failed to lock: %d\n", err);
+		return err;
+	}
 
 	/* turn off IDDQ override */
 	value = pads_readl(pcie, PADS_CTL);
@@ -888,6 +912,58 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
 	value |= PADS_CTL_TX_DATA_EN_1L | PADS_CTL_RX_DATA_EN_1L;
 	pads_writel(pcie, value, PADS_CTL);
 
+	return 0;
+}
+
+static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
+{
+	const struct tegra_pcie_soc_data *soc = pcie->soc_data;
+	struct tegra_pcie_port *port;
+	unsigned long value;
+	int err;
+
+	/* enable PLL power down */
+	if (pcie->phy) {
+		value = afi_readl(pcie, AFI_PLLE_CONTROL);
+		value &= ~AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL;
+		value |= AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN;
+		afi_writel(pcie, value, AFI_PLLE_CONTROL);
+	}
+
+	/* power down PCIe slot clock bias pad */
+	if (soc->has_pex_bias_ctrl)
+		afi_writel(pcie, 0, AFI_PEXBIAS_CTRL_0);
+
+	/* configure mode and disable all ports */
+	value = afi_readl(pcie, AFI_PCIE_CONFIG);
+	value &= ~AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK;
+	value |= AFI_PCIE_CONFIG_PCIE_DISABLE_ALL | pcie->xbar_config;
+
+	list_for_each_entry(port, &pcie->ports, list)
+		value &= ~AFI_PCIE_CONFIG_PCIE_DISABLE(port->index);
+
+	afi_writel(pcie, value, AFI_PCIE_CONFIG);
+
+	if (soc->has_gen2) {
+		value = afi_readl(pcie, AFI_FUSE);
+		value &= ~AFI_FUSE_PCIE_T0_GEN2_DIS;
+		afi_writel(pcie, value, AFI_FUSE);
+	} else {
+		value = afi_readl(pcie, AFI_FUSE);
+		value |= AFI_FUSE_PCIE_T0_GEN2_DIS;
+		afi_writel(pcie, value, AFI_FUSE);
+	}
+
+	if (!pcie->phy)
+		err = tegra_pcie_phy_enable(pcie);
+	else
+		err = phy_power_on(pcie->phy);
+
+	if (err < 0) {
+		dev_err(pcie->dev, "failed to power on PHY: %d\n", err);
+		return err;
+	}
+
 	/* take the PCIe interface module out of reset */
 	reset_control_deassert(pcie->pcie_xrst);
 
@@ -921,6 +997,10 @@ static void tegra_pcie_power_off(struct tegra_pcie *pcie)
 
 	/* TODO: disable and unprepare clocks? */
 
+	err = phy_power_off(pcie->phy);
+	if (err < 0)
+		dev_warn(pcie->dev, "failed to power off PHY: %d\n", err);
+
 	reset_control_assert(pcie->pcie_xrst);
 	reset_control_assert(pcie->afi_rst);
 	reset_control_assert(pcie->pex_rst);
@@ -1042,6 +1122,19 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie)
 		return err;
 	}
 
+	pcie->phy = devm_phy_optional_get(pcie->dev, "pcie");
+	if (IS_ERR(pcie->phy)) {
+		err = PTR_ERR(pcie->phy);
+		dev_err(&pdev->dev, "failed to get PHY: %d\n", err);
+		return err;
+	}
+
+	err = phy_init(pcie->phy);
+	if (err < 0) {
+		dev_err(&pdev->dev, "failed to initialize PHY: %d\n", err);
+		return err;
+	}
+
 	err = tegra_pcie_power_on(pcie);
 	if (err) {
 		dev_err(&pdev->dev, "failed to power up: %d\n", err);
@@ -1100,10 +1193,17 @@ poweroff:
 
 static int tegra_pcie_put_resources(struct tegra_pcie *pcie)
 {
+	int err;
+
 	if (pcie->irq > 0)
 		free_irq(pcie->irq, pcie);
 
 	tegra_pcie_power_off(pcie);
+
+	err = phy_exit(pcie->phy);
+	if (err < 0)
+		dev_err(pcie->dev, "failed to teardown PHY: %d\n", err);
+
 	return 0;
 }
 
@@ -1349,7 +1449,19 @@ static int tegra_pcie_get_xbar_config(struct tegra_pcie *pcie, u32 lanes,
 {
 	struct device_node *np = pcie->dev->of_node;
 
-	if (of_device_is_compatible(np, "nvidia,tegra30-pcie")) {
+	if (of_device_is_compatible(np, "nvidia,tegra124-pcie")) {
+		switch (lanes) {
+		case 0x0000104:
+			dev_info(pcie->dev, "4x1, 1x1 configuration\n");
+			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1;
+			return 0;
+
+		case 0x0000102:
+			dev_info(pcie->dev, "2x1, 1x1 configuration\n");
+			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X2_X1;
+			return 0;
+		}
+	} else if (of_device_is_compatible(np, "nvidia,tegra30-pcie")) {
 		switch (lanes) {
 		case 0x00000204:
 			dev_info(pcie->dev, "4x1, 2x1 configuration\n");
@@ -1457,7 +1569,23 @@ static int tegra_pcie_get_regulators(struct tegra_pcie *pcie, u32 lane_mask)
 	struct device_node *np = pcie->dev->of_node;
 	unsigned int i = 0;
 
-	if (of_device_is_compatible(np, "nvidia,tegra30-pcie")) {
+	if (of_device_is_compatible(np, "nvidia,tegra124-pcie")) {
+		pcie->num_supplies = 7;
+
+		pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies,
+					      sizeof(*pcie->supplies),
+					      GFP_KERNEL);
+		if (!pcie->supplies)
+			return -ENOMEM;
+
+		pcie->supplies[i++].supply = "avddio-pex";
+		pcie->supplies[i++].supply = "vddio-pex";
+		pcie->supplies[i++].supply = "avdd-pex-pll";
+		pcie->supplies[i++].supply = "hvdd-pex";
+		pcie->supplies[i++].supply = "hvdd-pex-plle";
+		pcie->supplies[i++].supply = "vddio-pex-ctl";
+		pcie->supplies[i++].supply = "avdd-plle";
+	} else if (of_device_is_compatible(np, "nvidia,tegra30-pcie")) {
 		bool need_pexa = false, need_pexb = false;
 
 		/* VDD_PEXA and AVDD_PEXA supply lanes 0 to 3 */
@@ -1679,6 +1807,12 @@ static bool tegra_pcie_port_check_link(struct tegra_pcie_port *port)
 	unsigned int retries = 3;
 	unsigned long value;
 
+	/* override presence detection */
+	value = readl(port->base + RP_PRIV_MISC);
+	value &= ~RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT;
+	value |= RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT;
+	writel(value, port->base + RP_PRIV_MISC);
+
 	do {
 		unsigned int timeout = TEGRA_PCIE_LINKUP_TIMEOUT;
 
@@ -1759,6 +1893,7 @@ static const struct tegra_pcie_soc_data tegra20_pcie_data = {
 	.has_pex_bias_ctrl = false,
 	.has_intr_prsnt_sense = false,
 	.has_cml_clk = false,
+	.has_gen2 = false,
 };
 
 static const struct tegra_pcie_soc_data tegra30_pcie_data = {
@@ -1770,9 +1905,23 @@ static const struct tegra_pcie_soc_data tegra30_pcie_data = {
 	.has_pex_bias_ctrl = true,
 	.has_intr_prsnt_sense = true,
 	.has_cml_clk = true,
+	.has_gen2 = false,
+};
+
+static const struct tegra_pcie_soc_data tegra124_pcie_data = {
+	.num_ports = 2,
+	.msi_base_shift = 8,
+	.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
+	.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
+	.has_pex_clkreq_en = true,
+	.has_pex_bias_ctrl = true,
+	.has_intr_prsnt_sense = true,
+	.has_cml_clk = true,
+	.has_gen2 = true,
 };
 
 static const struct of_device_id tegra_pcie_of_match[] = {
+	{ .compatible = "nvidia,tegra124-pcie", .data = &tegra124_pcie_data },
 	{ .compatible = "nvidia,tegra30-pcie", .data = &tegra30_pcie_data },
 	{ .compatible = "nvidia,tegra20-pcie", .data = &tegra20_pcie_data },
 	{ },
-- 
2.0.4


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 0/6] PCI: tegra: Fixes and Tegra124 support
  2014-08-26 14:57 [PATCH v2 0/6] PCI: tegra: Fixes and Tegra124 support Thierry Reding
                   ` (5 preceding siblings ...)
  2014-08-26 14:57 ` [PATCH v2 6/6] PCI: tegra: Add Tegra124 support Thierry Reding
@ 2014-08-26 15:08 ` Thierry Reding
  6 siblings, 0 replies; 8+ messages in thread
From: Thierry Reding @ 2014-08-26 15:08 UTC (permalink / raw)
  To: Bjorn Helgaas; +Cc: Stephen Warren, linux-pci, linux-tegra, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1625 bytes --]

On Tue, Aug 26, 2014 at 04:57:38PM +0200, Thierry Reding wrote:
> From: Thierry Reding <treding@nvidia.com>
> 
> This series implements various fixes and adds support for Tegra124 to the
> Tegra PCIe controller driver.
> 
> Patches 1 and 2 were already sent out separately earlier on but haven't been
> applied yet, so I'm including them here for convenience.
> 
> Patches 3 to 5 are various fixes that should make the driver more reliable,
> though they don't (except maybe for patch 4) fix any known issues.
> 
> Patch 6 finally adds support for Tegra124.
> 
> Thierry
> 
> Eric Yuen (1):
>   PCI: tegra: Make sure the PCIe PLL is really reset
> 
> Peter Daifuku (1):
>   PCI: tegra: Fix extended configuration space mapping
> 
> Thierry Reding (4):
>   resource: Add device-managed request/release_resource()
>   PCI: tegra: Implement a proper resource hierarchy
>   PCI: tegra: Clear CLKREQ# enable on port disable
>   PCI: tegra: Add Tegra124 support
> 
>  .../bindings/pci/nvidia,tegra20-pcie.txt           |  25 +-
>  Documentation/driver-model/devres.txt              |   2 +
>  drivers/pci/host/pci-tegra.c                       | 257 ++++++++++++++++++---
>  include/linux/ioport.h                             |   5 +
>  kernel/resource.c                                  |  70 ++++++
>  5 files changed, 323 insertions(+), 36 deletions(-)

Hi Bjorn,

Right after sending this out I noticed that this series is missing a
change to the device tree binding that I've only had in my local tree,
so please don't apply this. I'll send out a v3 with that fixed shortly.

Thierry

[-- Attachment #2: Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2014-08-26 15:08 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-08-26 14:57 [PATCH v2 0/6] PCI: tegra: Fixes and Tegra124 support Thierry Reding
2014-08-26 14:57 ` [PATCH v2 1/6] resource: Add device-managed request/release_resource() Thierry Reding
2014-08-26 14:57 ` [PATCH v2 2/6] PCI: tegra: Implement a proper resource hierarchy Thierry Reding
2014-08-26 14:57 ` [PATCH v2 3/6] PCI: tegra: Clear CLKREQ# enable on port disable Thierry Reding
2014-08-26 14:57 ` [PATCH v2 4/6] PCI: tegra: Fix extended configuration space mapping Thierry Reding
2014-08-26 14:57 ` [PATCH v2 5/6] PCI: tegra: Make sure the PCIe PLL is really reset Thierry Reding
2014-08-26 14:57 ` [PATCH v2 6/6] PCI: tegra: Add Tegra124 support Thierry Reding
2014-08-26 15:08 ` [PATCH v2 0/6] PCI: tegra: Fixes and " Thierry Reding

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).