aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/imx6/patches-3.18/201-pci_imx6_ventana_fixup-for-IRQ-mismapping.patch
blob: 4db1569d895f8ca7b822ed129a1a11abaa06806b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
commit 2c0d0491438433a1f327f2e754c7b6b55fec51c4
Author: Tim Harvey <tharvey@gateworks.com>
Date:   Thu Feb 27 00:59:53 2014 -0800

    PCI: imx6: ventana: fixup for IRQ mismapping
    
    The TI XIO2001 PCIe-to-PCI bridge used on several Ventana expansion boards
    has its slot-to-bridge IRQ mapping reversed from the PCI specification:
    
      INTA->INTD
      INTB->INTC
      INTC->INTB
      INTD->INTA
    
    Implement a custom swizzle function that does a fixup on the interrupt for
    devices on a TI XIO2001 bridge.
    
    Signed-off-by: Tim Harvey <tharvey@gateworks.com>

--- a/drivers/pci/host/pci-imx6.c
+++ b/drivers/pci/host/pci-imx6.c
@@ -553,6 +553,39 @@ static int __init imx6_add_pcie_port(str
 	return 0;
 }
 
+/* TI XIO2001 PCIe-to-PCI bridge on GW16082 exp card has IRQs reversed */
+u8 ventana_swizzle(struct pci_dev *dev, u8 *pin)
+{
+	u8 i = 0;
+	struct pci_dev *pdev = dev;
+
+	/* count number of TI XIO2001 bridges on bus */
+	while (!pci_is_root_bus(pdev->bus)) {
+		if (pdev->bus && pdev->bus->self &&
+		    (pdev->bus->self->vendor == PCI_VENDOR_ID_TI) &&
+		    (pdev->bus->self->device == PCI_DEVICE_ID_TI_XIO2001)) {
+			i++;
+		}
+		pdev = pdev->bus->self;
+	}
+	while (!pci_is_root_bus(dev->bus)) {
+		/* if we are directly downstream from 1st TI XIO2001 bridge */
+		if (dev->bus && dev->bus->self &&
+		    (dev->bus->self->vendor == PCI_VENDOR_ID_TI) &&
+		    (dev->bus->self->device == PCI_DEVICE_ID_TI_XIO2001)) {
+			if (--i == 0) {
+				/* swap IRQs and swizzle backwards */
+				*pin = (15 - PCI_SLOT(dev->devfn)) + 1;
+				dev = dev->bus->self;
+				continue;
+			}
+		}
+		*pin = pci_swizzle_interrupt_pin(dev, *pin);
+		dev = dev->bus->self;
+	}
+	return PCI_SLOT(dev->devfn);
+}
+
 static int __init imx6_pcie_probe(struct platform_device *pdev)
 {
 	struct imx6_pcie *imx6_pcie;
@@ -618,6 +651,9 @@ static int __init imx6_pcie_probe(struct
 		return PTR_ERR(imx6_pcie->iomuxc_gpr);
 	}
 
+	if (of_machine_is_compatible("gw,ventana"))
+		pp->swizzle = ventana_swizzle;
+
 	ret = imx6_add_pcie_port(pp, pdev);
 	if (ret < 0)
 		return ret;
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -827,6 +827,7 @@
 #define PCI_DEVICE_ID_TI_XX12		0x8039
 #define PCI_DEVICE_ID_TI_XX12_FM	0x803b
 #define PCI_DEVICE_ID_TI_XIO2000A	0x8231
+#define PCI_DEVICE_ID_TI_XIO2001	0x8240
 #define PCI_DEVICE_ID_TI_1130		0xac12
 #define PCI_DEVICE_ID_TI_1031		0xac13
 #define PCI_DEVICE_ID_TI_1131		0xac15