imx6: pcie driver fixups

Add upstream patches needed for PCIe through a switch.

Signed-off-by: Tim Harvey <tharvey@gateworks.com>

SVN-Revision: 38511
lede-17.01
Luka Perkov 2013-10-23 22:16:03 +00:00
parent a0c9c711cd
commit cd43416a78
7 changed files with 235 additions and 24 deletions

View File

@ -0,0 +1,106 @@
From 93d2b52fe73294d59bbce3a6d4da031647b1f3b2 Mon Sep 17 00:00:00 2001
From: Tim Harvey <tharvey@gateworks.com>
Date: Tue, 22 Oct 2013 15:56:40 -0700
Subject: [PATCH] PCI: imx6: remove outbound io/mem ATU region mapping
The IMX6 iATU is used for address translation between the AXI bus
address space and PCI address space. This is used for type0 and type1
config cycles but is not necessary for outbound io/mem regions.
This patch removes the calls that inappropriately re-configures the ATU
viewport for outbound memory and IO after config cycles and removes them
altogether as they are not necessary.
This resolves issues with PCI devices behind switches and has been tested with
a Gige device behind a PLX PEX860x switch.
Signed-off-by: Tim Harvey <tharvey@gateworks.com>
---
drivers/pci/host/pcie-designware.c | 41 +++---------------------------------
1 file changed, 3 insertions(+), 38 deletions(-)
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -43,7 +43,6 @@
#define PCIE_ATU_VIEWPORT 0x900
#define PCIE_ATU_REGION_INBOUND (0x1 << 31)
#define PCIE_ATU_REGION_OUTBOUND (0x0 << 31)
-#define PCIE_ATU_REGION_INDEX1 (0x1 << 0)
#define PCIE_ATU_REGION_INDEX0 (0x0 << 0)
#define PCIE_ATU_CR1 0x904
#define PCIE_ATU_TYPE_MEM (0x0 << 0)
@@ -264,8 +263,8 @@ static void dw_pcie_prog_viewport_cfg0(s
static void dw_pcie_prog_viewport_cfg1(struct pcie_port *pp, u32 busdev)
{
- /* Program viewport 1 : OUTBOUND : CFG1 */
- dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1,
+ /* Program viewport 0 : OUTBOUND : CFG1 */
+ dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0,
PCIE_ATU_VIEWPORT);
dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_CFG1, PCIE_ATU_CR1);
dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
@@ -275,38 +274,8 @@ static void dw_pcie_prog_viewport_cfg1(s
PCIE_ATU_LIMIT);
dw_pcie_writel_rc(pp, busdev, PCIE_ATU_LOWER_TARGET);
dw_pcie_writel_rc(pp, 0, PCIE_ATU_UPPER_TARGET);
-}
-
-static void dw_pcie_prog_viewport_mem_outbound(struct pcie_port *pp)
-{
- /* Program viewport 0 : OUTBOUND : MEM */
- dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0,
- PCIE_ATU_VIEWPORT);
- dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_MEM, PCIE_ATU_CR1);
- dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
- dw_pcie_writel_rc(pp, pp->mem_base, PCIE_ATU_LOWER_BASE);
- dw_pcie_writel_rc(pp, (pp->mem_base >> 32), PCIE_ATU_UPPER_BASE);
- dw_pcie_writel_rc(pp, pp->mem_base + pp->config.mem_size - 1,
- PCIE_ATU_LIMIT);
- dw_pcie_writel_rc(pp, pp->config.mem_bus_addr, PCIE_ATU_LOWER_TARGET);
- dw_pcie_writel_rc(pp, upper_32_bits(pp->config.mem_bus_addr),
- PCIE_ATU_UPPER_TARGET);
-}
-
-static void dw_pcie_prog_viewport_io_outbound(struct pcie_port *pp)
-{
- /* Program viewport 1 : OUTBOUND : IO */
- dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1,
- PCIE_ATU_VIEWPORT);
- dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_IO, PCIE_ATU_CR1);
+ dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_CFG1, PCIE_ATU_CR1);
dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
- dw_pcie_writel_rc(pp, pp->io_base, PCIE_ATU_LOWER_BASE);
- dw_pcie_writel_rc(pp, (pp->io_base >> 32), PCIE_ATU_UPPER_BASE);
- dw_pcie_writel_rc(pp, pp->io_base + pp->config.io_size - 1,
- PCIE_ATU_LIMIT);
- dw_pcie_writel_rc(pp, pp->config.io_bus_addr, PCIE_ATU_LOWER_TARGET);
- dw_pcie_writel_rc(pp, upper_32_bits(pp->config.io_bus_addr),
- PCIE_ATU_UPPER_TARGET);
}
static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
@@ -322,11 +291,9 @@ static int dw_pcie_rd_other_conf(struct
if (bus->parent->number == pp->root_bus_nr) {
dw_pcie_prog_viewport_cfg0(pp, busdev);
ret = cfg_read(pp->va_cfg0_base + address, where, size, val);
- dw_pcie_prog_viewport_mem_outbound(pp);
} else {
dw_pcie_prog_viewport_cfg1(pp, busdev);
ret = cfg_read(pp->va_cfg1_base + address, where, size, val);
- dw_pcie_prog_viewport_io_outbound(pp);
}
return ret;
@@ -345,11 +312,9 @@ static int dw_pcie_wr_other_conf(struct
if (bus->parent->number == pp->root_bus_nr) {
dw_pcie_prog_viewport_cfg0(pp, busdev);
ret = cfg_write(pp->va_cfg0_base + address, where, size, val);
- dw_pcie_prog_viewport_mem_outbound(pp);
} else {
dw_pcie_prog_viewport_cfg1(pp, busdev);
ret = cfg_write(pp->va_cfg1_base + address, where, size, val);
- dw_pcie_prog_viewport_io_outbound(pp);
}
return ret;

View File

@ -0,0 +1,24 @@
From 8c8c877d8490c9d51210ee9e90d5f4d740f115c9 Mon Sep 17 00:00:00 2001
From: Tim Harvey <tharvey@gateworks.com>
Date: Thu, 17 Oct 2013 15:55:47 -0700
Subject: [PATCH 3/5] PCI: imx6: init must be early
If driver init is not early the pcie port driver gets initalized
first and interrupts are not configured for the imx6 pcie driver.
Signed-off-by: Tim Harvey <tharvey@gateworks.com>
---
drivers/pci/host/pci-imx6.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/pci/host/pci-imx6.c
+++ b/drivers/pci/host/pci-imx6.c
@@ -568,7 +568,7 @@ static int __init imx6_pcie_init(void)
{
return platform_driver_probe(&imx6_pcie_driver, imx6_pcie_probe);
}
-module_init(imx6_pcie_init);
+fs_initcall(imx6_pcie_init);
MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
MODULE_DESCRIPTION("Freescale i.MX6 PCIe host controller driver");

View File

@ -0,0 +1,36 @@
From 8590081d5328fe59d4f72aaadafb47fb91d8dc7c Mon Sep 17 00:00:00 2001
From: Tim Harvey <tharvey@gateworks.com>
Date: Thu, 17 Oct 2013 15:52:16 -0700
Subject: [PATCH] PCI: imx6: fix imprecise abort handler
An imprecise abort is triggered when a port behind a switch is accessed
and no device is present. At enumeration, imprecise aborts are not enabled
thus this ends up getting deferred until the kernel has completed init. At
that point we must not adjust PC - the handler must do nothing, but a handler
must exist.
This fixes random crashes that occur right after freeing init.
This is against linux-pci/host-imx6.
Acked-by: Marek Vasut <marex@denx.de>
Tested-by: Marek Vasut <marex@denx.de>
Signed-off-by: Tim Harvey <tharvey@gateworks.com>
---
drivers/pci/host/pci-imx6.c | 6 ------
1 file changed, 6 deletions(-)
--- a/drivers/pci/host/pci-imx6.c
+++ b/drivers/pci/host/pci-imx6.c
@@ -200,12 +200,6 @@ static int pcie_phy_write(void __iomem *
static int imx6q_pcie_abort_handler(unsigned long addr,
unsigned int fsr, struct pt_regs *regs)
{
- /*
- * If it was an imprecise abort, then we need to correct the
- * return address to be _after_ the instruction.
- */
- if (fsr & (1 << 10))
- regs->ARM_pc += 4;
return 0;
}

View File

@ -0,0 +1,24 @@
From 11e8d0ed8cc3b415767961555efc2885791a9391 Mon Sep 17 00:00:00 2001
From: Tim Harvey <tharvey@gateworks.com>
Date: Thu, 17 Oct 2013 15:57:28 -0700
Subject: [PATCH 4/5] PCI: imx6: increase link startup
An increase link startup delay is required when certain PCI switches are
attached to the root complex.
Signed-off-by: Tim Harvey <tharvey@gateworks.com>
---
drivers/pci/host/pci-imx6.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/pci/host/pci-imx6.c
+++ b/drivers/pci/host/pci-imx6.c
@@ -318,7 +318,7 @@ static void imx6_pcie_host_init(struct p
while (!dw_pcie_link_up(pp)) {
usleep_range(100, 1000);
count++;
- if (count >= 10) {
+ if (count >= 200) {
dev_err(pp->dev, "phy link never came up\n");
dev_dbg(pp->dev,
"DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n",

View File

@ -0,0 +1,28 @@
From 73a0e49b562da9b06e487fb8e051075543495be5 Mon Sep 17 00:00:00 2001
From: Tim Harvey <tharvey@gateworks.com>
Date: Thu, 17 Oct 2013 15:50:48 -0700
Subject: [PATCH 1/5] PCI: imx6: swizzle interrupts
Signed-off-by: Tim Harvey <tharvey@gateworks.com>
---
drivers/pci/host/pcie-designware.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -676,7 +676,13 @@ int dw_pcie_map_irq(const struct pci_dev
{
struct pcie_port *pp = sys_to_pcie(dev->bus->sysdata);
- return pp->irq;
+ switch (pin) {
+ case 1: return pp->irq;
+ case 2: return pp->irq - 1;
+ case 3: return pp->irq - 2;
+ case 4: return pp->irq - 3;
+ default: return -1;
+ }
}
static void dw_pcie_add_bus(struct pci_bus *bus)

View File

@ -26,3 +26,20 @@
+
+# PCI host controller drivers
+obj-y += host/
--- a/Documentation/devicetree/bindings/clock/imx6q-clock.txt
+++ b/Documentation/devicetree/bindings/clock/imx6q-clock.txt
@@ -208,10 +208,10 @@ clocks and IDs.
pll4_post_div 193
pll5_post_div 194
pll5_video_div 195
- lvds1_sel 204
- lvds2_sel 205
- lvds1_gate 206
- lvds2_gate 207
+ lvds1_sel 196
+ lvds2_sel 197
+ lvds1_gate 198
+ lvds2_gate 199
Examples:

View File

@ -1,24 +0,0 @@
--- a/drivers/pci/host/pci-imx6.c
+++ b/drivers/pci/host/pci-imx6.c
@@ -200,12 +200,6 @@ static int pcie_phy_write(void __iomem *
static int imx6q_pcie_abort_handler(unsigned long addr,
unsigned int fsr, struct pt_regs *regs)
{
- /*
- * If it was an imprecise abort, then we need to correct the
- * return address to be _after_ the instruction.
- */
- if (fsr & (1 << 10))
- regs->ARM_pc += 4;
return 0;
}
@@ -322,7 +316,7 @@ static void imx6_pcie_host_init(struct p
IMX6Q_GPR12_PCIE_CTL_2, 1 << 10);
while (!dw_pcie_link_up(pp)) {
- usleep_range(100, 1000);
+ usleep_range(2000, 3000);
count++;
if (count >= 10) {
dev_err(pp->dev, "phy link never came up\n");