All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/5] Add Keystone PCIe controller driver
@ 2014-06-30 21:45 ` Murali Karicheri
  0 siblings, 0 replies; 33+ messages in thread
From: Murali Karicheri @ 2014-06-30 21:45 UTC (permalink / raw)
  To: linux-pci, linux-kernel, devicetree
  Cc: Murali Karicheri, Santosh Shilimkar, Russell King, Grant Likely,
	Rob Herring, Mohit Kumar, Jingoo Han, Bjorn Helgaas,
	Pratyush Anand, Richard Zhu, Kishon Vijay Abraham I, Marek Vasut,
	Arnd Bergmann, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Randy Dunlap

This patch add PCIe controller driver for Keystone SoCs. This
is based on v2 of the series posted to the mailing list.
Keystone PCI controller is based on version 3.65 of the DW
hardware. This driver re-uses some of the DW core driver
functions and required modification in some to support
the old DW h/w based Keystone driver.

Please review and let me know if you have any comments.

CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
CC: Russell King <linux@arm.linux.org.uk>
CC: Grant Likely <grant.likely@linaro.org>
CC: Rob Herring <robh+dt@kernel.org>
CC: Mohit Kumar <mohit.kumar@st.com>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>
CC: Pratyush Anand <pratyush.anand@st.com>
CC: Richard Zhu <r65037@freescale.com>
CC: Kishon Vijay Abraham I <kishon@ti.com>
CC: Marek Vasut <marex@denx.de>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Pawel Moll <pawel.moll@arm.com>
CC: Mark Rutland <mark.rutland@arm.com>
CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
CC: Kumar Gala <galak@codeaurora.org>
CC: Randy Dunlap <rdunlap@infradead.org>
CC: Grant Likely <grant.likely@linaro.org> 

Changelog:

v3
 - DW application register handling code is now part of
   Keystone PCI driver. RFC had this code part of Keystone
   PCI driver, then V1 moved this to a separate file to
   re-use on other platforms that uses this version of the
   DW h/w. Then based on comments against v2, this is moved
   back to Keystone driver.
 - Keystone SerDes phy driver is removed from this series so that
   this can be merged independent of that patch
 - added msi_set_irq()/clear_irq() API's to support Keystone

V2
 - Split the designware pcie enhancement patch to multiple
   patches based on functionality added
 - Remove the quirk code and add a patch to fix mps/mrss
   tuning for ARM. Use kernel command line parameter
   pci=pcie_bus_perf to work with Keystone PCI Controller.
   Following patch addressed this.
     [PATCH v1] ARM: pci: add call to pcie_bus_configure_settings()
 - Add documentation for device tree bindings
 - Add separate interrupt controller nodes for MSI and Legacy
   IRQs and use irq map for legacy IRQ
 - Use compatibility to identify v3.65 version of the DW hardware
   and use it to customize the designware common code.
 - Use reg property for configuration space instead of range
 - Other minor updates based on code inspection. 

V1
 - Add an interrupt controller node for Legacy irq chip and use
   interrupt map/map-mask property to map legacy IRQs A/B/C/D
 - Add a Phy driver to replace the original serdes driver
 - Move common application register handling code to a separate
   file to allow re-use across other platforms that use older
   DW PCIe h/w
 - PCI quirk for maximum read request size. Check and override only
   if the maximum is higher than what controller can handle.
 - Converted to a module platform driver.

Murali Karicheri (5):
  PCI: designware: add rd[wr]_other_conf API
  PCI: designware: refactor MSI code to work with v3.65 dw hardware
  PCI: designware: refactor host init code to re-use on keystone PCI
  PCI: designware: enhance dw core driver to support Keystone PCI host
    controller
  PCI: add PCI controller for Keystone PCIe h/w

 .../devicetree/bindings/pci/designware-pcie.txt    |    2 +
 .../devicetree/bindings/pci/pci-keystone.txt       |   69 +++
 drivers/pci/host/Kconfig                           |    5 +
 drivers/pci/host/Makefile                          |    1 +
 drivers/pci/host/pci-keystone-dw.c                 |  523 ++++++++++++++++++++
 drivers/pci/host/pci-keystone.c                    |  381 ++++++++++++++
 drivers/pci/host/pci-keystone.h                    |   56 +++
 drivers/pci/host/pcie-designware.c                 |  206 ++++++--
 drivers/pci/host/pcie-designware.h                 |   17 +-
 9 files changed, 1207 insertions(+), 53 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pci/pci-keystone.txt
 create mode 100644 drivers/pci/host/pci-keystone-dw.c
 create mode 100644 drivers/pci/host/pci-keystone.c
 create mode 100644 drivers/pci/host/pci-keystone.h

-- 
1.7.9.5


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

* [PATCH v3 0/5] Add Keystone PCIe controller driver
@ 2014-06-30 21:45 ` Murali Karicheri
  0 siblings, 0 replies; 33+ messages in thread
From: Murali Karicheri @ 2014-06-30 21:45 UTC (permalink / raw)
  To: linux-pci, linux-kernel, devicetree
  Cc: Murali Karicheri, Santosh Shilimkar, Russell King, Grant Likely,
	Rob Herring, Mohit Kumar, Jingoo Han, Bjorn Helgaas,
	Pratyush Anand, Richard Zhu, Kishon Vijay Abraham I, Marek Vasut,
	Arnd Bergmann, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Randy Dunlap

This patch add PCIe controller driver for Keystone SoCs. This
is based on v2 of the series posted to the mailing list.
Keystone PCI controller is based on version 3.65 of the DW
hardware. This driver re-uses some of the DW core driver
functions and required modification in some to support
the old DW h/w based Keystone driver.

Please review and let me know if you have any comments.

CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
CC: Russell King <linux@arm.linux.org.uk>
CC: Grant Likely <grant.likely@linaro.org>
CC: Rob Herring <robh+dt@kernel.org>
CC: Mohit Kumar <mohit.kumar@st.com>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>
CC: Pratyush Anand <pratyush.anand@st.com>
CC: Richard Zhu <r65037@freescale.com>
CC: Kishon Vijay Abraham I <kishon@ti.com>
CC: Marek Vasut <marex@denx.de>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Pawel Moll <pawel.moll@arm.com>
CC: Mark Rutland <mark.rutland@arm.com>
CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
CC: Kumar Gala <galak@codeaurora.org>
CC: Randy Dunlap <rdunlap@infradead.org>
CC: Grant Likely <grant.likely@linaro.org> 

Changelog:

v3
 - DW application register handling code is now part of
   Keystone PCI driver. RFC had this code part of Keystone
   PCI driver, then V1 moved this to a separate file to
   re-use on other platforms that uses this version of the
   DW h/w. Then based on comments against v2, this is moved
   back to Keystone driver.
 - Keystone SerDes phy driver is removed from this series so that
   this can be merged independent of that patch
 - added msi_set_irq()/clear_irq() API's to support Keystone

V2
 - Split the designware pcie enhancement patch to multiple
   patches based on functionality added
 - Remove the quirk code and add a patch to fix mps/mrss
   tuning for ARM. Use kernel command line parameter
   pci=pcie_bus_perf to work with Keystone PCI Controller.
   Following patch addressed this.
     [PATCH v1] ARM: pci: add call to pcie_bus_configure_settings()
 - Add documentation for device tree bindings
 - Add separate interrupt controller nodes for MSI and Legacy
   IRQs and use irq map for legacy IRQ
 - Use compatibility to identify v3.65 version of the DW hardware
   and use it to customize the designware common code.
 - Use reg property for configuration space instead of range
 - Other minor updates based on code inspection. 

V1
 - Add an interrupt controller node for Legacy irq chip and use
   interrupt map/map-mask property to map legacy IRQs A/B/C/D
 - Add a Phy driver to replace the original serdes driver
 - Move common application register handling code to a separate
   file to allow re-use across other platforms that use older
   DW PCIe h/w
 - PCI quirk for maximum read request size. Check and override only
   if the maximum is higher than what controller can handle.
 - Converted to a module platform driver.

Murali Karicheri (5):
  PCI: designware: add rd[wr]_other_conf API
  PCI: designware: refactor MSI code to work with v3.65 dw hardware
  PCI: designware: refactor host init code to re-use on keystone PCI
  PCI: designware: enhance dw core driver to support Keystone PCI host
    controller
  PCI: add PCI controller for Keystone PCIe h/w

 .../devicetree/bindings/pci/designware-pcie.txt    |    2 +
 .../devicetree/bindings/pci/pci-keystone.txt       |   69 +++
 drivers/pci/host/Kconfig                           |    5 +
 drivers/pci/host/Makefile                          |    1 +
 drivers/pci/host/pci-keystone-dw.c                 |  523 ++++++++++++++++++++
 drivers/pci/host/pci-keystone.c                    |  381 ++++++++++++++
 drivers/pci/host/pci-keystone.h                    |   56 +++
 drivers/pci/host/pcie-designware.c                 |  206 ++++++--
 drivers/pci/host/pcie-designware.h                 |   17 +-
 9 files changed, 1207 insertions(+), 53 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pci/pci-keystone.txt
 create mode 100644 drivers/pci/host/pci-keystone-dw.c
 create mode 100644 drivers/pci/host/pci-keystone.c
 create mode 100644 drivers/pci/host/pci-keystone.h

-- 
1.7.9.5

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

* [PATCH v3 1/5] PCI: designware: add rd[wr]_other_conf API
  2014-06-30 21:45 ` Murali Karicheri
@ 2014-06-30 21:45   ` Murali Karicheri
  -1 siblings, 0 replies; 33+ messages in thread
From: Murali Karicheri @ 2014-06-30 21:45 UTC (permalink / raw)
  To: linux-pci, linux-kernel, devicetree
  Cc: Murali Karicheri, Santosh Shilimkar, Russell King, Grant Likely,
	Rob Herring, Mohit Kumar, Jingoo Han, Bjorn Helgaas,
	Pratyush Anand, Richard Zhu, Kishon Vijay Abraham I, Marek Vasut,
	Arnd Bergmann, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Randy Dunlap

v3.65 version of the designware h/w, requires application space
registers to be configured to access the remote EP config space.
To support this, add rd[wr]_other_conf API in the pcie_host_opts

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>

CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
CC: Russell King <linux@arm.linux.org.uk>
CC: Grant Likely <grant.likely@linaro.org>
CC: Rob Herring <robh+dt@kernel.org>
CC: Mohit Kumar <mohit.kumar@st.com>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>
CC: Pratyush Anand <pratyush.anand@st.com>
CC: Richard Zhu <r65037@freescale.com>
CC: Kishon Vijay Abraham I <kishon@ti.com>
CC: Marek Vasut <marex@denx.de>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Pawel Moll <pawel.moll@arm.com>
CC: Mark Rutland <mark.rutland@arm.com>
CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
CC: Kumar Gala <galak@codeaurora.org>
CC: Randy Dunlap <rdunlap@infradead.org>
CC: Grant Likely <grant.likely@linaro.org> 
---
 drivers/pci/host/pcie-designware.c |   12 ++++++++++--
 drivers/pci/host/pcie-designware.h |    4 ++++
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index 1eaf4df..d8f3af7 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -656,7 +656,11 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
 	}
 
 	if (bus->number != pp->root_bus_nr)
-		ret = dw_pcie_rd_other_conf(pp, bus, devfn,
+		if (pp->ops->rd_other_conf)
+			ret = pp->ops->rd_other_conf(pp, bus, devfn,
+						where, size, val);
+		else
+			ret = dw_pcie_rd_other_conf(pp, bus, devfn,
 						where, size, val);
 	else
 		ret = dw_pcie_rd_own_conf(pp, where, size, val);
@@ -679,7 +683,11 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
 	if (bus->number != pp->root_bus_nr)
-		ret = dw_pcie_wr_other_conf(pp, bus, devfn,
+		if (pp->ops->wr_other_conf)
+			ret = pp->ops->wr_other_conf(pp, bus, devfn,
+						where, size, val);
+		else
+			ret = dw_pcie_wr_other_conf(pp, bus, devfn,
 						where, size, val);
 	else
 		ret = dw_pcie_wr_own_conf(pp, where, size, val);
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
index 77f592f..8121901 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -61,6 +61,10 @@ struct pcie_host_ops {
 			u32 val, void __iomem *dbi_base);
 	int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
 	int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val);
+	int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
+			unsigned int devfn, int where, int size, u32 *val);
+	int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
+			unsigned int devfn, int where, int size, u32 val);
 	int (*link_up)(struct pcie_port *pp);
 	void (*host_init)(struct pcie_port *pp);
 };
-- 
1.7.9.5


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

* [PATCH v3 1/5] PCI: designware: add rd[wr]_other_conf API
@ 2014-06-30 21:45   ` Murali Karicheri
  0 siblings, 0 replies; 33+ messages in thread
From: Murali Karicheri @ 2014-06-30 21:45 UTC (permalink / raw)
  To: linux-pci, linux-kernel, devicetree
  Cc: Murali Karicheri, Santosh Shilimkar, Russell King, Grant Likely,
	Rob Herring, Mohit Kumar, Jingoo Han, Bjorn Helgaas,
	Pratyush Anand, Richard Zhu, Kishon Vijay Abraham I, Marek Vasut,
	Arnd Bergmann, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Randy Dunlap

v3.65 version of the designware h/w, requires application space
registers to be configured to access the remote EP config space.
To support this, add rd[wr]_other_conf API in the pcie_host_opts

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>

CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
CC: Russell King <linux@arm.linux.org.uk>
CC: Grant Likely <grant.likely@linaro.org>
CC: Rob Herring <robh+dt@kernel.org>
CC: Mohit Kumar <mohit.kumar@st.com>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>
CC: Pratyush Anand <pratyush.anand@st.com>
CC: Richard Zhu <r65037@freescale.com>
CC: Kishon Vijay Abraham I <kishon@ti.com>
CC: Marek Vasut <marex@denx.de>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Pawel Moll <pawel.moll@arm.com>
CC: Mark Rutland <mark.rutland@arm.com>
CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
CC: Kumar Gala <galak@codeaurora.org>
CC: Randy Dunlap <rdunlap@infradead.org>
CC: Grant Likely <grant.likely@linaro.org> 
---
 drivers/pci/host/pcie-designware.c |   12 ++++++++++--
 drivers/pci/host/pcie-designware.h |    4 ++++
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index 1eaf4df..d8f3af7 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -656,7 +656,11 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
 	}
 
 	if (bus->number != pp->root_bus_nr)
-		ret = dw_pcie_rd_other_conf(pp, bus, devfn,
+		if (pp->ops->rd_other_conf)
+			ret = pp->ops->rd_other_conf(pp, bus, devfn,
+						where, size, val);
+		else
+			ret = dw_pcie_rd_other_conf(pp, bus, devfn,
 						where, size, val);
 	else
 		ret = dw_pcie_rd_own_conf(pp, where, size, val);
@@ -679,7 +683,11 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
 	if (bus->number != pp->root_bus_nr)
-		ret = dw_pcie_wr_other_conf(pp, bus, devfn,
+		if (pp->ops->wr_other_conf)
+			ret = pp->ops->wr_other_conf(pp, bus, devfn,
+						where, size, val);
+		else
+			ret = dw_pcie_wr_other_conf(pp, bus, devfn,
 						where, size, val);
 	else
 		ret = dw_pcie_wr_own_conf(pp, where, size, val);
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
index 77f592f..8121901 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -61,6 +61,10 @@ struct pcie_host_ops {
 			u32 val, void __iomem *dbi_base);
 	int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
 	int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val);
+	int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
+			unsigned int devfn, int where, int size, u32 *val);
+	int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
+			unsigned int devfn, int where, int size, u32 val);
 	int (*link_up)(struct pcie_port *pp);
 	void (*host_init)(struct pcie_port *pp);
 };
-- 
1.7.9.5

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

* [PATCH v3 2/5] PCI: designware: refactor MSI code to work with v3.65 dw hardware
  2014-06-30 21:45 ` Murali Karicheri
@ 2014-06-30 21:45   ` Murali Karicheri
  -1 siblings, 0 replies; 33+ messages in thread
From: Murali Karicheri @ 2014-06-30 21:45 UTC (permalink / raw)
  To: linux-pci, linux-kernel, devicetree
  Cc: Murali Karicheri, Santosh Shilimkar, Russell King, Grant Likely,
	Rob Herring, Mohit Kumar, Jingoo Han, Bjorn Helgaas,
	Pratyush Anand, Richard Zhu, Kishon Vijay Abraham I, Marek Vasut,
	Arnd Bergmann, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Randy Dunlap

Keystone PCI controller is based on v3.65 version of the DW
PCI h/w that implements MSI controller registers in application
space compared to the newer version. This requires updates to
the DW core API to support the PCI controller driver based on
this old DW hardware. Add msi_irq_set()/clear() API functions to
allow Set/Clear MSI IRQ enable bit in the application register.
Also the old h/w uses MSI_IRQ register in application register
space to raise MSI IRQ to the RC from EP. Current code uses the
standard mechanism as per PCI spec. So add another API get_msi_data()
to get the address of this register so that common code can be
re-used on old h/w.

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>

CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
CC: Russell King <linux@arm.linux.org.uk>
CC: Grant Likely <grant.likely@linaro.org>
CC: Rob Herring <robh+dt@kernel.org>
CC: Mohit Kumar <mohit.kumar@st.com>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>
CC: Pratyush Anand <pratyush.anand@st.com>
CC: Richard Zhu <r65037@freescale.com>
CC: Kishon Vijay Abraham I <kishon@ti.com>
CC: Marek Vasut <marex@denx.de>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Pawel Moll <pawel.moll@arm.com>
CC: Mark Rutland <mark.rutland@arm.com>
CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
CC: Kumar Gala <galak@codeaurora.org>
CC: Randy Dunlap <rdunlap@infradead.org>
CC: Grant Likely <grant.likely@linaro.org> 
---
 drivers/pci/host/pcie-designware.c |   50 ++++++++++++++++++++++++++----------
 drivers/pci/host/pcie-designware.h |    3 +++
 2 files changed, 39 insertions(+), 14 deletions(-)

diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index d8f3af7..905941c 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -217,27 +217,47 @@ static int find_valid_pos0(struct pcie_port *pp, int msgvec, int pos, int *pos0)
 	return 0;
 }
 
+static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
+{
+	unsigned int res, bit, val;
+
+	res = (irq / 32) * 12;
+	bit = irq % 32;
+	dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
+	val &= ~(1 << bit);
+	dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+}
+
 static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
 			    unsigned int nvec, unsigned int pos)
 {
-	unsigned int i, res, bit, val;
+	unsigned int i;
 
 	for (i = 0; i < nvec; i++) {
 		irq_set_msi_desc_off(irq_base, i, NULL);
 		clear_bit(pos + i, pp->msi_irq_in_use);
 		/* Disable corresponding interrupt on MSI controller */
-		res = ((pos + i) / 32) * 12;
-		bit = (pos + i) % 32;
-		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
-		val &= ~(1 << bit);
-		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+		if (pp->ops->msi_clear_irq)
+			pp->ops->msi_clear_irq(pp, pos + i);
+		else
+			dw_pcie_msi_clear_irq(pp, pos + i);
 	}
 }
 
+static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq)
+{
+	unsigned int res, bit, val;
+
+	res = (irq / 32) * 12;
+	bit = irq % 32;
+	dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
+	val |= 1 << bit;
+	dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+}
+
 static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
 {
-	int res, bit, irq, pos0, pos1, i;
-	u32 val;
+	int irq, pos0, pos1, i;
 	struct pcie_port *pp = sys_to_pcie(desc->dev->bus->sysdata);
 
 	if (!pp) {
@@ -281,11 +301,10 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
 		}
 		set_bit(pos0 + i, pp->msi_irq_in_use);
 		/*Enable corresponding interrupt in MSI interrupt controller */
-		res = ((pos0 + i) / 32) * 12;
-		bit = (pos0 + i) % 32;
-		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
-		val |= 1 << bit;
-		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+		if (pp->ops->msi_set_irq)
+			pp->ops->msi_set_irq(pp, pos0 + i);
+		else
+			dw_pcie_msi_set_irq(pp, pos0 + i);
 	}
 
 	*pos = pos0;
@@ -353,7 +372,10 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
 	 */
 	desc->msi_attrib.multiple = msgvec;
 
-	msg.address_lo = virt_to_phys((void *)pp->msi_data);
+	if (pp->ops->get_msi_data)
+		msg.address_lo = pp->ops->get_msi_data(pp);
+	else
+		msg.address_lo = virt_to_phys((void *)pp->msi_data);
 	msg.address_hi = 0x0;
 	msg.data = pos;
 	write_msi_msg(irq, &msg);
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
index 8121901..387f69e 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -67,6 +67,9 @@ struct pcie_host_ops {
 			unsigned int devfn, int where, int size, u32 val);
 	int (*link_up)(struct pcie_port *pp);
 	void (*host_init)(struct pcie_port *pp);
+	void (*msi_set_irq)(struct pcie_port *pp, int irq);
+	void (*msi_clear_irq)(struct pcie_port *pp, int irq);
+	u32 (*get_msi_data)(struct pcie_port *pp);
 };
 
 int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val);
-- 
1.7.9.5


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

* [PATCH v3 2/5] PCI: designware: refactor MSI code to work with v3.65 dw hardware
@ 2014-06-30 21:45   ` Murali Karicheri
  0 siblings, 0 replies; 33+ messages in thread
From: Murali Karicheri @ 2014-06-30 21:45 UTC (permalink / raw)
  To: linux-pci, linux-kernel, devicetree
  Cc: Murali Karicheri, Santosh Shilimkar, Russell King, Grant Likely,
	Rob Herring, Mohit Kumar, Jingoo Han, Bjorn Helgaas,
	Pratyush Anand, Richard Zhu, Kishon Vijay Abraham I, Marek Vasut,
	Arnd Bergmann, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Randy Dunlap

Keystone PCI controller is based on v3.65 version of the DW
PCI h/w that implements MSI controller registers in application
space compared to the newer version. This requires updates to
the DW core API to support the PCI controller driver based on
this old DW hardware. Add msi_irq_set()/clear() API functions to
allow Set/Clear MSI IRQ enable bit in the application register.
Also the old h/w uses MSI_IRQ register in application register
space to raise MSI IRQ to the RC from EP. Current code uses the
standard mechanism as per PCI spec. So add another API get_msi_data()
to get the address of this register so that common code can be
re-used on old h/w.

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>

CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
CC: Russell King <linux@arm.linux.org.uk>
CC: Grant Likely <grant.likely@linaro.org>
CC: Rob Herring <robh+dt@kernel.org>
CC: Mohit Kumar <mohit.kumar@st.com>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>
CC: Pratyush Anand <pratyush.anand@st.com>
CC: Richard Zhu <r65037@freescale.com>
CC: Kishon Vijay Abraham I <kishon@ti.com>
CC: Marek Vasut <marex@denx.de>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Pawel Moll <pawel.moll@arm.com>
CC: Mark Rutland <mark.rutland@arm.com>
CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
CC: Kumar Gala <galak@codeaurora.org>
CC: Randy Dunlap <rdunlap@infradead.org>
CC: Grant Likely <grant.likely@linaro.org> 
---
 drivers/pci/host/pcie-designware.c |   50 ++++++++++++++++++++++++++----------
 drivers/pci/host/pcie-designware.h |    3 +++
 2 files changed, 39 insertions(+), 14 deletions(-)

diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index d8f3af7..905941c 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -217,27 +217,47 @@ static int find_valid_pos0(struct pcie_port *pp, int msgvec, int pos, int *pos0)
 	return 0;
 }
 
+static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
+{
+	unsigned int res, bit, val;
+
+	res = (irq / 32) * 12;
+	bit = irq % 32;
+	dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
+	val &= ~(1 << bit);
+	dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+}
+
 static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
 			    unsigned int nvec, unsigned int pos)
 {
-	unsigned int i, res, bit, val;
+	unsigned int i;
 
 	for (i = 0; i < nvec; i++) {
 		irq_set_msi_desc_off(irq_base, i, NULL);
 		clear_bit(pos + i, pp->msi_irq_in_use);
 		/* Disable corresponding interrupt on MSI controller */
-		res = ((pos + i) / 32) * 12;
-		bit = (pos + i) % 32;
-		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
-		val &= ~(1 << bit);
-		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+		if (pp->ops->msi_clear_irq)
+			pp->ops->msi_clear_irq(pp, pos + i);
+		else
+			dw_pcie_msi_clear_irq(pp, pos + i);
 	}
 }
 
+static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq)
+{
+	unsigned int res, bit, val;
+
+	res = (irq / 32) * 12;
+	bit = irq % 32;
+	dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
+	val |= 1 << bit;
+	dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+}
+
 static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
 {
-	int res, bit, irq, pos0, pos1, i;
-	u32 val;
+	int irq, pos0, pos1, i;
 	struct pcie_port *pp = sys_to_pcie(desc->dev->bus->sysdata);
 
 	if (!pp) {
@@ -281,11 +301,10 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
 		}
 		set_bit(pos0 + i, pp->msi_irq_in_use);
 		/*Enable corresponding interrupt in MSI interrupt controller */
-		res = ((pos0 + i) / 32) * 12;
-		bit = (pos0 + i) % 32;
-		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
-		val |= 1 << bit;
-		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+		if (pp->ops->msi_set_irq)
+			pp->ops->msi_set_irq(pp, pos0 + i);
+		else
+			dw_pcie_msi_set_irq(pp, pos0 + i);
 	}
 
 	*pos = pos0;
@@ -353,7 +372,10 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
 	 */
 	desc->msi_attrib.multiple = msgvec;
 
-	msg.address_lo = virt_to_phys((void *)pp->msi_data);
+	if (pp->ops->get_msi_data)
+		msg.address_lo = pp->ops->get_msi_data(pp);
+	else
+		msg.address_lo = virt_to_phys((void *)pp->msi_data);
 	msg.address_hi = 0x0;
 	msg.data = pos;
 	write_msi_msg(irq, &msg);
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
index 8121901..387f69e 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -67,6 +67,9 @@ struct pcie_host_ops {
 			unsigned int devfn, int where, int size, u32 val);
 	int (*link_up)(struct pcie_port *pp);
 	void (*host_init)(struct pcie_port *pp);
+	void (*msi_set_irq)(struct pcie_port *pp, int irq);
+	void (*msi_clear_irq)(struct pcie_port *pp, int irq);
+	u32 (*get_msi_data)(struct pcie_port *pp);
 };
 
 int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val);
-- 
1.7.9.5

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

* [PATCH v3 3/5] PCI: designware: refactor host init code to re-use on keystone PCI
  2014-06-30 21:45 ` Murali Karicheri
@ 2014-06-30 21:45   ` Murali Karicheri
  -1 siblings, 0 replies; 33+ messages in thread
From: Murali Karicheri @ 2014-06-30 21:45 UTC (permalink / raw)
  To: linux-pci, linux-kernel, devicetree
  Cc: Murali Karicheri, Santosh Shilimkar, Russell King, Grant Likely,
	Rob Herring, Mohit Kumar, Jingoo Han, Bjorn Helgaas,
	Pratyush Anand, Richard Zhu, Kishon Vijay Abraham I, Marek Vasut,
	Arnd Bergmann, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Randy Dunlap

This patch refactor the host controller init code to support Keystone
PCI controller.

Current DW PCI host controller init code has code specific to newer
DW hw such as ATU port resource parse and ioremap. Conditionally
execute this code if DW h/w is not v3.65. Keystone PCI controller
is based on v3.65 DW PCI h/w and it has MSI controller implemented
in application space and requires different controller initialization
code. So factor out the MSI host init code to a separate function.

Rename dw_pcie_host_init() to dw_pcie_common_host_init() that takes an
additional arg, ptr to hw_pci structure. This allows to re-use the code
for Keystone PCI that can now provide it's own pci hw ops and msi irq
ops.  dw_pcie_host_init() is now a wrapper function that calls
dw_pcie_common_host_init() for pci common initialization.

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>

CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
CC: Russell King <linux@arm.linux.org.uk>
CC: Grant Likely <grant.likely@linaro.org>
CC: Rob Herring <robh+dt@kernel.org>
CC: Mohit Kumar <mohit.kumar@st.com>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>
CC: Pratyush Anand <pratyush.anand@st.com>
CC: Richard Zhu <r65037@freescale.com>
CC: Kishon Vijay Abraham I <kishon@ti.com>
CC: Marek Vasut <marex@denx.de>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Pawel Moll <pawel.moll@arm.com>
CC: Mark Rutland <mark.rutland@arm.com>
CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
CC: Kumar Gala <galak@codeaurora.org>
CC: Randy Dunlap <rdunlap@infradead.org>
CC: Grant Likely <grant.likely@linaro.org> 
---
 drivers/pci/host/pcie-designware.c |  105 +++++++++++++++++++++++++-----------
 drivers/pci/host/pcie-designware.h |    3 +-
 2 files changed, 75 insertions(+), 33 deletions(-)

diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index 905941c..c11e4de 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -415,19 +415,24 @@ static const struct irq_domain_ops msi_domain_ops = {
 	.map = dw_pcie_msi_map,
 };
 
-int __init dw_pcie_host_init(struct pcie_port *pp)
+static int __init dw_pcie_common_host_init(struct pcie_port *pp,
+					   struct hw_pci *hw)
 {
 	struct device_node *np = pp->dev->of_node;
 	struct of_pci_range range;
 	struct of_pci_range_parser parser;
+	struct hw_pci *pci_hw = hw;
 	u32 val;
-	int i;
 
 	if (of_pci_range_parser_init(&parser, np)) {
 		dev_err(pp->dev, "missing ranges property\n");
 		return -EINVAL;
 	}
 
+	/* Default to dw_pci if no hw ops provided */
+	if (!pci_hw)
+		pci_hw = &dw_pci;
+
 	/* Get the I/O and memory ranges from DT */
 	for_each_of_pci_range(&parser, &range) {
 		unsigned long restype = range.flags & IORESOURCE_TYPE_BITS;
@@ -467,21 +472,24 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
 		}
 	}
 
-	pp->cfg0_base = pp->cfg.start;
-	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
 	pp->mem_base = pp->mem.start;
-
-	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
-					pp->config.cfg0_size);
-	if (!pp->va_cfg0_base) {
-		dev_err(pp->dev, "error with ioremap in function\n");
-		return -ENOMEM;
-	}
-	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
-					pp->config.cfg1_size);
-	if (!pp->va_cfg1_base) {
-		dev_err(pp->dev, "error with ioremap\n");
-		return -ENOMEM;
+	if (!pp->version & DW_HW_V3_65) {
+		/* Default is with ATU port. */
+		pp->cfg0_base = pp->cfg.start;
+		pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
+
+		pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
+						pp->config.cfg0_size);
+		if (!pp->va_cfg0_base) {
+			dev_err(pp->dev, "error with ioremap in function\n");
+			return -ENOMEM;
+		}
+		pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
+						pp->config.cfg1_size);
+		if (!pp->va_cfg1_base) {
+			dev_err(pp->dev, "error with ioremap\n");
+			return -ENOMEM;
+		}
 	}
 
 	if (of_property_read_u32(np, "num-lanes", &pp->lanes)) {
@@ -489,19 +497,6 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
 		return -EINVAL;
 	}
 
-	if (IS_ENABLED(CONFIG_PCI_MSI)) {
-		pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
-					MAX_MSI_IRQS, &msi_domain_ops,
-					&dw_pcie_msi_chip);
-		if (!pp->irq_domain) {
-			dev_err(pp->dev, "irq domain init failed\n");
-			return -ENXIO;
-		}
-
-		for (i = 0; i < MAX_MSI_IRQS; i++)
-			irq_create_mapping(pp->irq_domain, i);
-	}
-
 	if (pp->ops->host_init)
 		pp->ops->host_init(pp);
 
@@ -514,10 +509,10 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
 	val |= PORT_LOGIC_SPEED_CHANGE;
 	dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
 
-	dw_pci.nr_controllers = 1;
-	dw_pci.private_data = (void **)&pp;
+	pci_hw->nr_controllers = 1;
+	pci_hw->private_data = (void **)&pp;
 
-	pci_common_init_dev(pp->dev, &dw_pci);
+	pci_common_init_dev(pp->dev, pci_hw);
 	pci_assign_unassigned_resources();
 #ifdef CONFIG_PCI_DOMAINS
 	dw_pci.domain++;
@@ -526,6 +521,52 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
 	return 0;
 }
 
+/*
+ * dw_pcie_msi_host_init() - Function to initialize msi host controller
+ * @pp: ptr to pcie port
+ * @msi_irqc_np: device node ptr to msi irq controller
+ * @irq_msi_ops: ptr to MSI irq_domain_ops struct
+ *
+ * Function register irq domain for msi irq controller and create mappings
+ * for MSI irqs.
+ */
+static int dw_pcie_msi_host_init(struct pcie_port *pp,
+				 struct device_node *msi_irqc_np,
+				 const struct irq_domain_ops *msi_irq_ops)
+{
+	const struct irq_domain_ops *msi_irq_domain_ops = msi_irq_ops;
+	int i;
+
+	/* Default to  msi_domain_ops if no msi irq domain ops provided */
+	if (!msi_irq_domain_ops)
+		msi_irq_domain_ops = &msi_domain_ops;
+
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		pp->irq_domain = irq_domain_add_linear(msi_irqc_np,
+					MAX_MSI_IRQS, msi_irq_domain_ops,
+					&dw_pcie_msi_chip);
+		if (!pp->irq_domain) {
+			dev_err(pp->dev, "irq domain init failed\n");
+			return -ENXIO;
+		}
+
+		for (i = 0; i < MAX_MSI_IRQS; i++)
+			irq_create_mapping(pp->irq_domain, i);
+	}
+	return 0;
+}
+
+int __init dw_pcie_host_init(struct pcie_port *pp)
+{
+	int ret;
+
+	ret = dw_pcie_msi_host_init(pp, pp->dev->of_node, NULL);
+	if (ret)
+		return ret;
+
+	return dw_pcie_common_host_init(pp, NULL);
+}
+
 static void dw_pcie_prog_viewport_cfg0(struct pcie_port *pp, u32 busdev)
 {
 	/* Program viewport 0 : OUTBOUND : CFG0 */
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
index 387f69e..db0260f 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -51,6 +51,8 @@ struct pcie_port {
 	int			msi_irq;
 	struct irq_domain	*irq_domain;
 	unsigned long		msi_data;
+#define DW_HW_V3_65		BIT(0)
+	u32			version;
 	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
 };
 
@@ -79,5 +81,4 @@ void dw_pcie_msi_init(struct pcie_port *pp);
 int dw_pcie_link_up(struct pcie_port *pp);
 void dw_pcie_setup_rc(struct pcie_port *pp);
 int dw_pcie_host_init(struct pcie_port *pp);
-
 #endif /* _PCIE_DESIGNWARE_H */
-- 
1.7.9.5


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

* [PATCH v3 3/5] PCI: designware: refactor host init code to re-use on keystone PCI
@ 2014-06-30 21:45   ` Murali Karicheri
  0 siblings, 0 replies; 33+ messages in thread
From: Murali Karicheri @ 2014-06-30 21:45 UTC (permalink / raw)
  To: linux-pci, linux-kernel, devicetree
  Cc: Murali Karicheri, Santosh Shilimkar, Russell King, Grant Likely,
	Rob Herring, Mohit Kumar, Jingoo Han, Bjorn Helgaas,
	Pratyush Anand, Richard Zhu, Kishon Vijay Abraham I, Marek Vasut,
	Arnd Bergmann, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Randy Dunlap

This patch refactor the host controller init code to support Keystone
PCI controller.

Current DW PCI host controller init code has code specific to newer
DW hw such as ATU port resource parse and ioremap. Conditionally
execute this code if DW h/w is not v3.65. Keystone PCI controller
is based on v3.65 DW PCI h/w and it has MSI controller implemented
in application space and requires different controller initialization
code. So factor out the MSI host init code to a separate function.

Rename dw_pcie_host_init() to dw_pcie_common_host_init() that takes an
additional arg, ptr to hw_pci structure. This allows to re-use the code
for Keystone PCI that can now provide it's own pci hw ops and msi irq
ops.  dw_pcie_host_init() is now a wrapper function that calls
dw_pcie_common_host_init() for pci common initialization.

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>

CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
CC: Russell King <linux@arm.linux.org.uk>
CC: Grant Likely <grant.likely@linaro.org>
CC: Rob Herring <robh+dt@kernel.org>
CC: Mohit Kumar <mohit.kumar@st.com>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>
CC: Pratyush Anand <pratyush.anand@st.com>
CC: Richard Zhu <r65037@freescale.com>
CC: Kishon Vijay Abraham I <kishon@ti.com>
CC: Marek Vasut <marex@denx.de>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Pawel Moll <pawel.moll@arm.com>
CC: Mark Rutland <mark.rutland@arm.com>
CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
CC: Kumar Gala <galak@codeaurora.org>
CC: Randy Dunlap <rdunlap@infradead.org>
CC: Grant Likely <grant.likely@linaro.org> 
---
 drivers/pci/host/pcie-designware.c |  105 +++++++++++++++++++++++++-----------
 drivers/pci/host/pcie-designware.h |    3 +-
 2 files changed, 75 insertions(+), 33 deletions(-)

diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index 905941c..c11e4de 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -415,19 +415,24 @@ static const struct irq_domain_ops msi_domain_ops = {
 	.map = dw_pcie_msi_map,
 };
 
-int __init dw_pcie_host_init(struct pcie_port *pp)
+static int __init dw_pcie_common_host_init(struct pcie_port *pp,
+					   struct hw_pci *hw)
 {
 	struct device_node *np = pp->dev->of_node;
 	struct of_pci_range range;
 	struct of_pci_range_parser parser;
+	struct hw_pci *pci_hw = hw;
 	u32 val;
-	int i;
 
 	if (of_pci_range_parser_init(&parser, np)) {
 		dev_err(pp->dev, "missing ranges property\n");
 		return -EINVAL;
 	}
 
+	/* Default to dw_pci if no hw ops provided */
+	if (!pci_hw)
+		pci_hw = &dw_pci;
+
 	/* Get the I/O and memory ranges from DT */
 	for_each_of_pci_range(&parser, &range) {
 		unsigned long restype = range.flags & IORESOURCE_TYPE_BITS;
@@ -467,21 +472,24 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
 		}
 	}
 
-	pp->cfg0_base = pp->cfg.start;
-	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
 	pp->mem_base = pp->mem.start;
-
-	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
-					pp->config.cfg0_size);
-	if (!pp->va_cfg0_base) {
-		dev_err(pp->dev, "error with ioremap in function\n");
-		return -ENOMEM;
-	}
-	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
-					pp->config.cfg1_size);
-	if (!pp->va_cfg1_base) {
-		dev_err(pp->dev, "error with ioremap\n");
-		return -ENOMEM;
+	if (!pp->version & DW_HW_V3_65) {
+		/* Default is with ATU port. */
+		pp->cfg0_base = pp->cfg.start;
+		pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
+
+		pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
+						pp->config.cfg0_size);
+		if (!pp->va_cfg0_base) {
+			dev_err(pp->dev, "error with ioremap in function\n");
+			return -ENOMEM;
+		}
+		pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
+						pp->config.cfg1_size);
+		if (!pp->va_cfg1_base) {
+			dev_err(pp->dev, "error with ioremap\n");
+			return -ENOMEM;
+		}
 	}
 
 	if (of_property_read_u32(np, "num-lanes", &pp->lanes)) {
@@ -489,19 +497,6 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
 		return -EINVAL;
 	}
 
-	if (IS_ENABLED(CONFIG_PCI_MSI)) {
-		pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
-					MAX_MSI_IRQS, &msi_domain_ops,
-					&dw_pcie_msi_chip);
-		if (!pp->irq_domain) {
-			dev_err(pp->dev, "irq domain init failed\n");
-			return -ENXIO;
-		}
-
-		for (i = 0; i < MAX_MSI_IRQS; i++)
-			irq_create_mapping(pp->irq_domain, i);
-	}
-
 	if (pp->ops->host_init)
 		pp->ops->host_init(pp);
 
@@ -514,10 +509,10 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
 	val |= PORT_LOGIC_SPEED_CHANGE;
 	dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
 
-	dw_pci.nr_controllers = 1;
-	dw_pci.private_data = (void **)&pp;
+	pci_hw->nr_controllers = 1;
+	pci_hw->private_data = (void **)&pp;
 
-	pci_common_init_dev(pp->dev, &dw_pci);
+	pci_common_init_dev(pp->dev, pci_hw);
 	pci_assign_unassigned_resources();
 #ifdef CONFIG_PCI_DOMAINS
 	dw_pci.domain++;
@@ -526,6 +521,52 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
 	return 0;
 }
 
+/*
+ * dw_pcie_msi_host_init() - Function to initialize msi host controller
+ * @pp: ptr to pcie port
+ * @msi_irqc_np: device node ptr to msi irq controller
+ * @irq_msi_ops: ptr to MSI irq_domain_ops struct
+ *
+ * Function register irq domain for msi irq controller and create mappings
+ * for MSI irqs.
+ */
+static int dw_pcie_msi_host_init(struct pcie_port *pp,
+				 struct device_node *msi_irqc_np,
+				 const struct irq_domain_ops *msi_irq_ops)
+{
+	const struct irq_domain_ops *msi_irq_domain_ops = msi_irq_ops;
+	int i;
+
+	/* Default to  msi_domain_ops if no msi irq domain ops provided */
+	if (!msi_irq_domain_ops)
+		msi_irq_domain_ops = &msi_domain_ops;
+
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		pp->irq_domain = irq_domain_add_linear(msi_irqc_np,
+					MAX_MSI_IRQS, msi_irq_domain_ops,
+					&dw_pcie_msi_chip);
+		if (!pp->irq_domain) {
+			dev_err(pp->dev, "irq domain init failed\n");
+			return -ENXIO;
+		}
+
+		for (i = 0; i < MAX_MSI_IRQS; i++)
+			irq_create_mapping(pp->irq_domain, i);
+	}
+	return 0;
+}
+
+int __init dw_pcie_host_init(struct pcie_port *pp)
+{
+	int ret;
+
+	ret = dw_pcie_msi_host_init(pp, pp->dev->of_node, NULL);
+	if (ret)
+		return ret;
+
+	return dw_pcie_common_host_init(pp, NULL);
+}
+
 static void dw_pcie_prog_viewport_cfg0(struct pcie_port *pp, u32 busdev)
 {
 	/* Program viewport 0 : OUTBOUND : CFG0 */
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
index 387f69e..db0260f 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -51,6 +51,8 @@ struct pcie_port {
 	int			msi_irq;
 	struct irq_domain	*irq_domain;
 	unsigned long		msi_data;
+#define DW_HW_V3_65		BIT(0)
+	u32			version;
 	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
 };
 
@@ -79,5 +81,4 @@ void dw_pcie_msi_init(struct pcie_port *pp);
 int dw_pcie_link_up(struct pcie_port *pp);
 void dw_pcie_setup_rc(struct pcie_port *pp);
 int dw_pcie_host_init(struct pcie_port *pp);
-
 #endif /* _PCIE_DESIGNWARE_H */
-- 
1.7.9.5

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

* [PATCH v3 4/5] PCI: designware: enhance dw core driver to support Keystone PCI host controller
  2014-06-30 21:45 ` Murali Karicheri
@ 2014-06-30 21:45   ` Murali Karicheri
  -1 siblings, 0 replies; 33+ messages in thread
From: Murali Karicheri @ 2014-06-30 21:45 UTC (permalink / raw)
  To: linux-pci, linux-kernel, devicetree
  Cc: Murali Karicheri, Santosh Shilimkar, Russell King, Grant Likely,
	Rob Herring, Mohit Kumar, Jingoo Han, Bjorn Helgaas,
	Pratyush Anand, Richard Zhu, Kishon Vijay Abraham I, Marek Vasut,
	Arnd Bergmann, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Randy Dunlap

Add API dw_pcie_v3_65_host_init() to support host controller initialization
for Keystone PCI driver. The Keystone PCI uses v3.65 version of the DW hardware
identified by compatibility string "dw,snps-pcie-v3.65". This allow for
different treatment for this version of the h/w during host initialization.
Key differences in v3.65 DW h/w are
	1. No ATU support
	2. Legacy and MSI irq functions are implemented in application
	   register space
	3. MSI interrupts are multiplexed over 8 IRQ lines to the Host side.
So a msi irq chip is needed and the irq domain ops ptr is passed in
dw_pcie_v3_65_host_init() to allow re-use of common MSI code in dw core.  The
Keystone PCI host controller requires a modified pci scan function to allow
setup BAR0 for EP's access to MSI_IRQ register in application register to
raise MSI irq.  So a ptr to pci hw ops struct is passed to the host init code.

Keystone PCI controller re-uses the DW Core driver code wherever there is
common functionality. So this patch makes these functions global and added
their prototypes in pcie-designware.h to allow re-use on Keystone.

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>

CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
CC: Russell King <linux@arm.linux.org.uk>
CC: Grant Likely <grant.likely@linaro.org>
CC: Rob Herring <robh+dt@kernel.org>
CC: Mohit Kumar <mohit.kumar@st.com>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>
CC: Pratyush Anand <pratyush.anand@st.com>
CC: Richard Zhu <r65037@freescale.com>
CC: Kishon Vijay Abraham I <kishon@ti.com>
CC: Marek Vasut <marex@denx.de>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Pawel Moll <pawel.moll@arm.com>
CC: Mark Rutland <mark.rutland@arm.com>
CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
CC: Kumar Gala <galak@codeaurora.org>
CC: Randy Dunlap <rdunlap@infradead.org>
CC: Grant Likely <grant.likely@linaro.org>
---
 .../devicetree/bindings/pci/designware-pcie.txt    |    2 +
 drivers/pci/host/pcie-designware.c                 |   39 ++++++++++++++++++--
 drivers/pci/host/pcie-designware.h                 |    7 ++++
 3 files changed, 44 insertions(+), 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/pci/designware-pcie.txt b/Documentation/devicetree/bindings/pci/designware-pcie.txt
index d0d15ee..0cb10c0 100644
--- a/Documentation/devicetree/bindings/pci/designware-pcie.txt
+++ b/Documentation/devicetree/bindings/pci/designware-pcie.txt
@@ -2,6 +2,8 @@
 
 Required properties:
 - compatible: should contain "snps,dw-pcie" to identify the core.
+  Additionally contains "dw,snps-pcie-v3.65" to identify v3.65 version of the DW
+  hardware.
 - #address-cells: set to <3>
 - #size-cells: set to <2>
 - device_type: set to "pci"
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index c11e4de..4dcbebe 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -556,6 +556,37 @@ static int dw_pcie_msi_host_init(struct pcie_port *pp,
 	return 0;
 }
 
+int __init dw_pcie_v3_65_host_init(struct pcie_port *pp, struct hw_pci *hw,
+				   struct device_node *msi_irqc_np,
+				   const struct irq_domain_ops *msi_irq_ops)
+{
+	int ret = -EINVAL;
+
+	/* check if compatible with v3.65 DW h/w */
+	if (!of_device_is_compatible(pp->dev->of_node, "dw,snps-pcie-v3.65")) {
+		dev_err(pp->dev,
+			"PCI Controller not compatible with v3.65 DW h/w\n");
+		goto out;
+	}
+	pp->version = DW_HW_V3_65;
+
+	/* v3.65 PCI controller is expected to provide its own PCI h/w ops */
+	if (!hw || !msi_irq_ops) {
+		dev_err(pp->dev,
+			"v3.65 PCI Controllers doesn't provide %s\n",
+			(hw == NULL) ? "PCI hw ops" : "PCI MSI irq domain ops");
+		goto out;
+	}
+
+	ret = dw_pcie_msi_host_init(pp, msi_irqc_np,  msi_irq_ops);
+	if (ret)
+		goto out;
+
+	ret = dw_pcie_common_host_init(pp, hw);
+out:
+	return ret;
+}
+
 int __init dw_pcie_host_init(struct pcie_port *pp)
 {
 	int ret;
@@ -763,7 +794,7 @@ static struct pci_ops dw_pcie_ops = {
 	.write = dw_pcie_wr_conf,
 };
 
-static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
+int dw_pcie_setup(int nr, struct pci_sys_data *sys)
 {
 	struct pcie_port *pp;
 
@@ -786,7 +817,7 @@ static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
 	return 1;
 }
 
-static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
+struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
 {
 	struct pci_bus *bus;
 	struct pcie_port *pp = sys_to_pcie(sys);
@@ -803,7 +834,7 @@ static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
 	return bus;
 }
 
-static int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
 	struct pcie_port *pp = sys_to_pcie(dev->bus->sysdata);
 	int irq;
@@ -815,7 +846,7 @@ static int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 	return irq;
 }
 
-static void dw_pcie_add_bus(struct pci_bus *bus)
+void dw_pcie_add_bus(struct pci_bus *bus)
 {
 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
 		struct pcie_port *pp = sys_to_pcie(bus->sysdata);
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
index db0260f..2681826 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -81,4 +81,11 @@ void dw_pcie_msi_init(struct pcie_port *pp);
 int dw_pcie_link_up(struct pcie_port *pp);
 void dw_pcie_setup_rc(struct pcie_port *pp);
 int dw_pcie_host_init(struct pcie_port *pp);
+int dw_pcie_v3_65_host_init(struct pcie_port *pp, struct hw_pci *hw,
+			   struct device_node *msi_irqc_np,
+			   const struct irq_domain_ops *msi_irq_ops);
+int dw_pcie_setup(int nr, struct pci_sys_data *sys);
+struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys);
+void dw_pcie_add_bus(struct pci_bus *bus);
+int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin);
 #endif /* _PCIE_DESIGNWARE_H */
-- 
1.7.9.5


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

* [PATCH v3 4/5] PCI: designware: enhance dw core driver to support Keystone PCI host controller
@ 2014-06-30 21:45   ` Murali Karicheri
  0 siblings, 0 replies; 33+ messages in thread
From: Murali Karicheri @ 2014-06-30 21:45 UTC (permalink / raw)
  To: linux-pci, linux-kernel, devicetree
  Cc: Murali Karicheri, Santosh Shilimkar, Russell King, Grant Likely,
	Rob Herring, Mohit Kumar, Jingoo Han, Bjorn Helgaas,
	Pratyush Anand, Richard Zhu, Kishon Vijay Abraham I, Marek Vasut,
	Arnd Bergmann, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Randy Dunlap

Add API dw_pcie_v3_65_host_init() to support host controller initialization
for Keystone PCI driver. The Keystone PCI uses v3.65 version of the DW hardware
identified by compatibility string "dw,snps-pcie-v3.65". This allow for
different treatment for this version of the h/w during host initialization.
Key differences in v3.65 DW h/w are
	1. No ATU support
	2. Legacy and MSI irq functions are implemented in application
	   register space
	3. MSI interrupts are multiplexed over 8 IRQ lines to the Host side.
So a msi irq chip is needed and the irq domain ops ptr is passed in
dw_pcie_v3_65_host_init() to allow re-use of common MSI code in dw core.  The
Keystone PCI host controller requires a modified pci scan function to allow
setup BAR0 for EP's access to MSI_IRQ register in application register to
raise MSI irq.  So a ptr to pci hw ops struct is passed to the host init code.

Keystone PCI controller re-uses the DW Core driver code wherever there is
common functionality. So this patch makes these functions global and added
their prototypes in pcie-designware.h to allow re-use on Keystone.

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>

CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
CC: Russell King <linux@arm.linux.org.uk>
CC: Grant Likely <grant.likely@linaro.org>
CC: Rob Herring <robh+dt@kernel.org>
CC: Mohit Kumar <mohit.kumar@st.com>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>
CC: Pratyush Anand <pratyush.anand@st.com>
CC: Richard Zhu <r65037@freescale.com>
CC: Kishon Vijay Abraham I <kishon@ti.com>
CC: Marek Vasut <marex@denx.de>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Pawel Moll <pawel.moll@arm.com>
CC: Mark Rutland <mark.rutland@arm.com>
CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
CC: Kumar Gala <galak@codeaurora.org>
CC: Randy Dunlap <rdunlap@infradead.org>
CC: Grant Likely <grant.likely@linaro.org>
---
 .../devicetree/bindings/pci/designware-pcie.txt    |    2 +
 drivers/pci/host/pcie-designware.c                 |   39 ++++++++++++++++++--
 drivers/pci/host/pcie-designware.h                 |    7 ++++
 3 files changed, 44 insertions(+), 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/pci/designware-pcie.txt b/Documentation/devicetree/bindings/pci/designware-pcie.txt
index d0d15ee..0cb10c0 100644
--- a/Documentation/devicetree/bindings/pci/designware-pcie.txt
+++ b/Documentation/devicetree/bindings/pci/designware-pcie.txt
@@ -2,6 +2,8 @@
 
 Required properties:
 - compatible: should contain "snps,dw-pcie" to identify the core.
+  Additionally contains "dw,snps-pcie-v3.65" to identify v3.65 version of the DW
+  hardware.
 - #address-cells: set to <3>
 - #size-cells: set to <2>
 - device_type: set to "pci"
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index c11e4de..4dcbebe 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -556,6 +556,37 @@ static int dw_pcie_msi_host_init(struct pcie_port *pp,
 	return 0;
 }
 
+int __init dw_pcie_v3_65_host_init(struct pcie_port *pp, struct hw_pci *hw,
+				   struct device_node *msi_irqc_np,
+				   const struct irq_domain_ops *msi_irq_ops)
+{
+	int ret = -EINVAL;
+
+	/* check if compatible with v3.65 DW h/w */
+	if (!of_device_is_compatible(pp->dev->of_node, "dw,snps-pcie-v3.65")) {
+		dev_err(pp->dev,
+			"PCI Controller not compatible with v3.65 DW h/w\n");
+		goto out;
+	}
+	pp->version = DW_HW_V3_65;
+
+	/* v3.65 PCI controller is expected to provide its own PCI h/w ops */
+	if (!hw || !msi_irq_ops) {
+		dev_err(pp->dev,
+			"v3.65 PCI Controllers doesn't provide %s\n",
+			(hw == NULL) ? "PCI hw ops" : "PCI MSI irq domain ops");
+		goto out;
+	}
+
+	ret = dw_pcie_msi_host_init(pp, msi_irqc_np,  msi_irq_ops);
+	if (ret)
+		goto out;
+
+	ret = dw_pcie_common_host_init(pp, hw);
+out:
+	return ret;
+}
+
 int __init dw_pcie_host_init(struct pcie_port *pp)
 {
 	int ret;
@@ -763,7 +794,7 @@ static struct pci_ops dw_pcie_ops = {
 	.write = dw_pcie_wr_conf,
 };
 
-static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
+int dw_pcie_setup(int nr, struct pci_sys_data *sys)
 {
 	struct pcie_port *pp;
 
@@ -786,7 +817,7 @@ static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
 	return 1;
 }
 
-static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
+struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
 {
 	struct pci_bus *bus;
 	struct pcie_port *pp = sys_to_pcie(sys);
@@ -803,7 +834,7 @@ static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
 	return bus;
 }
 
-static int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
 	struct pcie_port *pp = sys_to_pcie(dev->bus->sysdata);
 	int irq;
@@ -815,7 +846,7 @@ static int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 	return irq;
 }
 
-static void dw_pcie_add_bus(struct pci_bus *bus)
+void dw_pcie_add_bus(struct pci_bus *bus)
 {
 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
 		struct pcie_port *pp = sys_to_pcie(bus->sysdata);
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
index db0260f..2681826 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -81,4 +81,11 @@ void dw_pcie_msi_init(struct pcie_port *pp);
 int dw_pcie_link_up(struct pcie_port *pp);
 void dw_pcie_setup_rc(struct pcie_port *pp);
 int dw_pcie_host_init(struct pcie_port *pp);
+int dw_pcie_v3_65_host_init(struct pcie_port *pp, struct hw_pci *hw,
+			   struct device_node *msi_irqc_np,
+			   const struct irq_domain_ops *msi_irq_ops);
+int dw_pcie_setup(int nr, struct pci_sys_data *sys);
+struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys);
+void dw_pcie_add_bus(struct pci_bus *bus);
+int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin);
 #endif /* _PCIE_DESIGNWARE_H */
-- 
1.7.9.5

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

* [PATCH v3 5/5] PCI: add PCI controller for Keystone PCIe h/w
  2014-06-30 21:45 ` Murali Karicheri
@ 2014-06-30 21:45   ` Murali Karicheri
  -1 siblings, 0 replies; 33+ messages in thread
From: Murali Karicheri @ 2014-06-30 21:45 UTC (permalink / raw)
  To: linux-pci, linux-kernel, devicetree
  Cc: Murali Karicheri, Santosh Shilimkar, Russell King, Grant Likely,
	Rob Herring, Mohit Kumar, Jingoo Han, Bjorn Helgaas,
	Pratyush Anand, Richard Zhu, Kishon Vijay Abraham I, Marek Vasut,
	Arnd Bergmann, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Randy Dunlap

Keystone PCIe controller is based on v3.65 version of the
designware h/w. Main differences are
	1. No ATU support
	2. Legacy and MSI irq functions are implemented in
	   application register space
	3. MSI interrupts are multiplexed over 8 IRQ lines to the Host
	   side.
All of the Application register space handing code are organized into
pci-keystone-dw.c and the functions are called from pci-keystone.c
to implement PCI controller driver. Also add necessary DT documentation
for the driver.

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>

CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
CC: Russell King <linux@arm.linux.org.uk>
CC: Grant Likely <grant.likely@linaro.org>
CC: Rob Herring <robh+dt@kernel.org>
CC: Mohit Kumar <mohit.kumar@st.com>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>
CC: Pratyush Anand <pratyush.anand@st.com>
CC: Richard Zhu <r65037@freescale.com>
CC: Kishon Vijay Abraham I <kishon@ti.com>
CC: Marek Vasut <marex@denx.de>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Pawel Moll <pawel.moll@arm.com>
CC: Mark Rutland <mark.rutland@arm.com>
CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
CC: Kumar Gala <galak@codeaurora.org>
CC: Randy Dunlap <rdunlap@infradead.org>
CC: Grant Likely <grant.likely@linaro.org>
---
 .../devicetree/bindings/pci/pci-keystone.txt       |   69 +++
 drivers/pci/host/Kconfig                           |    5 +
 drivers/pci/host/Makefile                          |    1 +
 drivers/pci/host/pci-keystone-dw.c                 |  523 ++++++++++++++++++++
 drivers/pci/host/pci-keystone.c                    |  381 ++++++++++++++
 drivers/pci/host/pci-keystone.h                    |   56 +++
 6 files changed, 1035 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/pci-keystone.txt
 create mode 100644 drivers/pci/host/pci-keystone-dw.c
 create mode 100644 drivers/pci/host/pci-keystone.c
 create mode 100644 drivers/pci/host/pci-keystone.h

diff --git a/Documentation/devicetree/bindings/pci/pci-keystone.txt b/Documentation/devicetree/bindings/pci/pci-keystone.txt
new file mode 100644
index 0000000..bb39601
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/pci-keystone.txt
@@ -0,0 +1,69 @@
+TI Keystone PCIe interface
+
+Keystone PCI host Controller is based on Designware PCI h/w version 3.65.
+It shares common functions with PCIE Designware core driver and inherit
+common properties defined in
+Documentation/devicetree/bindings/pci/designware-pci.txt
+Compatibility string "dw,snps-pcie-v3.65" is used to identify the verison
+of the DW h/w used on Keystone.
+
+Please refer to Documentation/devicetree/bindings/pci/designware-pci.txt
+for the details of designware DT bindings. Additional properties are
+described here as well propeties that are not applicable.
+
+Required Properties:-
+
+compatibility: "ti,keystone-pcie"
+reg:	index 1 is the base address and length of DW application registers.
+	index 2 is the base address and length of PCI mode configuration
+	register.
+	index 3 is the base address and length of PCI device ID register.
+
+pcie_msi_intc : Interrupt controller device node for MSI irq chip
+	interrupt-cells: should be set to 1
+	interrupt-parent: Parent interrupt controller phandle
+	interrupts: GIC interrupt lines connected to PCI MSI interrupt lines
+
+ Example:
+	pcie_msi_intc: msi-interrupt-controller {
+			interrupt-controller;
+			#interrupt-cells = <1>;
+			interrupt-parent = <&gic>;
+			interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 32 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 33 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 34 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 35 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 37 IRQ_TYPE_EDGE_RISING>;
+	};
+
+pcie_intc: Interrupt controller device node for Legacy irq chip
+	interrupt-cells: should be set to 1
+	interrupt-parent: Parent interrupt controller phandle
+	interrupts: GIC interrupt lines connected to PCI Legacy interrupt lines
+
+ Example:
+	pcie_intc: legacy-interrupt-controller {
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>,
+			<GIC_SPI 27 IRQ_TYPE_EDGE_RISING>,
+			<GIC_SPI 28 IRQ_TYPE_EDGE_RISING>,
+			<GIC_SPI 29 IRQ_TYPE_EDGE_RISING>;
+	};
+
+Optional properties:-
+	phys: phandle to Generic Keystone SerDes phy for PCI
+	phy-names: name of the Generic Keystine SerDes phy for PCI
+	  - If boot loader already does PCI link establishment, then phys and
+	    phy-names shouldn't be present.
+	ti,enable-linktrain - Enable Link training.
+	  - If boot loader already does PCI link establishment, then this
+	    shouldn't be present.
+
+Designware DT Properties not applicable for Keystone PCI
+
+1. pcie_bus clock-names not used. Instead, a phandle to phys is used.
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 21df477..f8bc475 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -46,4 +46,9 @@ config PCI_HOST_GENERIC
 	  Say Y here if you want to support a simple generic PCI host
 	  controller, such as the one emulated by kvmtool.
 
+config PCI_KEYSTONE
+	bool "TI Keystone PCIe controller"
+	depends on ARCH_KEYSTONE
+	select PCIE_DW
+	select PCIEPORTBUS
 endmenu
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 611ba4b..d1b6ce1 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
 obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
 obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o
 obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o
+obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o
diff --git a/drivers/pci/host/pci-keystone-dw.c b/drivers/pci/host/pci-keystone-dw.c
new file mode 100644
index 0000000..3b5b075
--- /dev/null
+++ b/drivers/pci/host/pci-keystone-dw.c
@@ -0,0 +1,523 @@
+/*
+ * Designware application register space functions for Keystone PCI controller
+ *
+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
+ *		http://www.ti.com
+ *
+ * Author: Murali Karicheri <m-karicheri2@ti.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_pci.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+
+#include "pcie-designware.h"
+#include "pci-keystone.h"
+
+/* Application register defines */
+#define LTSSM_EN_VAL		        BIT(0)
+#define LTSSM_STATE_MASK	        0x1f
+#define LTSSM_STATE_L0		        0x11
+#define DIR_SPD				(1 << 17)
+#define DBI_CS2_EN_VAL		        BIT(5)
+#define OB_XLAT_EN_VAL		        BIT(1)
+
+/* Application registers */
+#define CMD_STATUS			0x004
+#define CFG_SETUP			0x008
+#define OB_SIZE				0x030
+#define CFG_PCIM_WIN_SZ_IDX	        3
+#define CFG_PCIM_WIN_CNT	        32
+#define SPACE0_REMOTE_CFG_OFFSET	0x1000
+#define OB_OFFSET_INDEX(n)		(0x200 + (8 * n))
+#define OB_OFFSET_HI(n)			(0x204 + (8 * n))
+
+/* IRQ register defines */
+#define IRQ_EOI                         0x050
+#define IRQ_STATUS			0x184
+#define IRQ_ENABLE_SET			0x188
+#define IRQ_ENABLE_CLR			0x18c
+
+#define MSI_IRQ				0x054
+#define MSI0_IRQ_STATUS			0x104
+#define MSI0_IRQ_ENABLE_SET		0x108
+#define MSI0_IRQ_ENABLE_CLR		0x10c
+#define IRQ_STATUS			0x184
+#define MSI_IRQ_OFFSET			4
+
+/* Config space registers */
+#define DEBUG0			        0x728
+
+#define to_keystone_pcie(x)	container_of(x, struct keystone_pcie, pp)
+
+static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
+{
+	return sys->private_data;
+}
+
+static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset,
+					u32 *bit_pos)
+{
+	*reg_offset = offset % 8;
+	*bit_pos = offset >> 3;
+}
+
+inline u32 ks_dw_pcie_get_msi_data(struct pcie_port *pp)
+{
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+
+	return ks_pcie->app.start + MSI_IRQ;
+}
+
+void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie , int offset)
+{
+	struct pcie_port *pp = &ks_pcie->pp;
+	u32 pending, vector;
+	int src, virq;
+
+	pending = readl(ks_pcie->va_app_base + MSI0_IRQ_STATUS + (offset << 4));
+	/*
+	 * MSI0, Status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit
+	 * shows 1, 9, 17, 25 and so forth
+	 */
+	for (src = 0; src < 4; src++) {
+		if (BIT(src) & pending) {
+			vector = offset + (src << 3);
+			virq = irq_linear_revmap(pp->irq_domain, vector);
+			dev_dbg(pp->dev,
+				"irq: bit %d, vector %d, virq %d\n",
+				 src, vector, virq);
+			generic_handle_irq(virq);
+		}
+	}
+}
+
+static void ks_dw_pcie_msi_irq_ack(struct irq_data *d)
+{
+	u32 offset, reg_offset, bit_pos;
+	struct keystone_pcie *ks_pcie;
+	unsigned int irq = d->irq;
+	struct msi_desc *msi;
+	struct pcie_port *pp;
+
+	msi = irq_get_msi_desc(irq);
+	pp = sys_to_pcie(msi->dev->bus->sysdata);
+	ks_pcie = to_keystone_pcie(pp);
+	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
+	update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
+
+	writel(BIT(bit_pos),
+		ks_pcie->va_app_base + MSI0_IRQ_STATUS + (reg_offset << 4));
+	writel(reg_offset + MSI_IRQ_OFFSET, ks_pcie->va_app_base + IRQ_EOI);
+}
+
+void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq)
+{
+	u32 reg_offset, bit_pos;
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+
+	update_reg_offset_bit_pos(irq, &reg_offset, &bit_pos);
+	writel(BIT(bit_pos),
+		ks_pcie->va_app_base + MSI0_IRQ_ENABLE_SET + (reg_offset << 4));
+}
+
+void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
+{
+	u32 reg_offset, bit_pos;
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+
+	update_reg_offset_bit_pos(irq, &reg_offset, &bit_pos);
+	writel(BIT(bit_pos),
+		ks_pcie->va_app_base + MSI0_IRQ_ENABLE_CLR + (reg_offset << 4));
+}
+
+static void ks_dw_pcie_msi_irq_mask(struct irq_data *d)
+{
+	struct keystone_pcie *ks_pcie;
+	unsigned int irq = d->irq;
+	struct msi_desc *msi;
+	struct pcie_port *pp;
+	u32 offset;
+
+	msi = irq_get_msi_desc(irq);
+	pp = sys_to_pcie(msi->dev->bus->sysdata);
+	ks_pcie = to_keystone_pcie(pp);
+	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
+
+	/* mask the end point if PVM implemented */
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		if (msi->msi_attrib.maskbit)
+			mask_msi_irq(d);
+	}
+
+	ks_dw_pcie_msi_clear_irq(pp, offset);
+}
+
+static void ks_dw_pcie_msi_irq_unmask(struct irq_data *d)
+{
+	struct keystone_pcie *ks_pcie;
+	unsigned int irq = d->irq;
+	struct msi_desc *msi;
+	struct pcie_port *pp;
+	u32 offset;
+
+	msi = irq_get_msi_desc(irq);
+	pp = sys_to_pcie(msi->dev->bus->sysdata);
+	ks_pcie = to_keystone_pcie(pp);
+	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
+
+	/* mask the end point if PVM implemented */
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		if (msi->msi_attrib.maskbit)
+			unmask_msi_irq(d);
+	}
+
+	ks_dw_pcie_msi_set_irq(pp, offset);
+}
+
+static struct irq_chip ks_dw_pcie_msi_irq_chip = {
+	.name = "Keystone-PCIe-MSI-IRQ",
+	.irq_ack = ks_dw_pcie_msi_irq_ack,
+	.irq_mask = ks_dw_pcie_msi_irq_mask,
+	.irq_unmask = ks_dw_pcie_msi_irq_unmask,
+};
+
+static int ks_dw_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
+			irq_hw_number_t hwirq)
+{
+	irq_set_chip_and_handler(irq, &ks_dw_pcie_msi_irq_chip,
+				 handle_level_irq);
+	irq_set_chip_data(irq, domain->host_data);
+	set_irq_flags(irq, IRQF_VALID);
+
+	return 0;
+}
+
+const struct irq_domain_ops ks_dw_pcie_msi_domain_ops = {
+	.map = ks_dw_pcie_msi_map,
+};
+
+void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie)
+{
+	int i;
+
+	for (i = 0; i < MAX_LEGACY_IRQS; i++)
+		writel(0x1, ks_pcie->va_app_base + IRQ_ENABLE_SET + (i << 4));
+}
+
+void ks_dw_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, int offset)
+{
+	struct pcie_port *pp = &ks_pcie->pp;
+	u32 pending;
+	int virq;
+
+	pending = readl(ks_pcie->va_app_base + IRQ_STATUS + (offset << 4));
+
+	if (BIT(0) & pending) {
+		virq = irq_linear_revmap(ks_pcie->legacy_irq_domain, offset);
+		dev_dbg(pp->dev,
+			": irq: irq_offset %d, virq %d\n", offset, virq);
+		generic_handle_irq(virq);
+	}
+
+	/* EOI the INTx interrupt */
+	writel(offset, ks_pcie->va_app_base + IRQ_EOI);
+}
+
+static void ks_dw_pcie_ack_legacy_irq(struct irq_data *d)
+{
+}
+
+static void ks_dw_pcie_mask_legacy_irq(struct irq_data *d)
+{
+}
+
+static void ks_dw_pcie_unmask_legacy_irq(struct irq_data *d)
+{
+}
+
+static struct irq_chip ks_dw_pcie_legacy_irq_chip = {
+	.name = "Keystone-PCI-Legacy-IRQ",
+	.irq_ack = ks_dw_pcie_ack_legacy_irq,
+	.irq_mask = ks_dw_pcie_mask_legacy_irq,
+	.irq_unmask = ks_dw_pcie_unmask_legacy_irq,
+};
+
+static int ks_dw_pcie_init_legacy_irq_map(struct irq_domain *d,
+				unsigned int irq, irq_hw_number_t hw_irq)
+{
+	irq_set_chip_and_handler(irq, &ks_dw_pcie_legacy_irq_chip,
+				handle_level_irq);
+	irq_set_chip_data(irq, d->host_data);
+	set_irq_flags(irq, IRQF_VALID);
+
+	return 0;
+}
+
+static const struct irq_domain_ops ks_dw_pcie_legacy_irq_domian_ops = {
+	.map = ks_dw_pcie_init_legacy_irq_map,
+	.xlate = irq_domain_xlate_onetwocell,
+};
+
+/**
+ * ks_dw_pcie_set_dbi_mode() - Set DBI mode to access overlaid BAR mask registers
+ *
+ * Since modification of dbi_cs2 involves different clock domain, read the
+ * status back to ensure the transition is complete.
+ */
+static inline void ks_dw_pcie_set_dbi_mode(void __iomem *reg_virt)
+{
+	u32 val;
+
+	writel(DBI_CS2_EN_VAL | readl(reg_virt + CMD_STATUS),
+		     reg_virt + CMD_STATUS);
+
+	do {
+		val = readl(reg_virt + CMD_STATUS);
+	} while (!(val & DBI_CS2_EN_VAL));
+}
+
+/**
+ * ks_dw_pcie_clear_dbi_mode() - Disable DBI mode
+ *
+ * Since modification of dbi_cs2 involves different clock domain, read the
+ * status back to ensure the transition is complete.
+ */
+static inline void ks_dw_pcie_clear_dbi_mode(void __iomem *reg_virt)
+{
+	u32 val;
+
+	writel(~DBI_CS2_EN_VAL & readl(reg_virt + CMD_STATUS),
+		     reg_virt + CMD_STATUS);
+
+	do {
+		val = readl(reg_virt + CMD_STATUS);
+	} while (val & DBI_CS2_EN_VAL);
+}
+
+void ks_dw_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie)
+{
+	struct pcie_port *pp = &ks_pcie->pp;
+	u32 start = pp->mem.start, end = pp->mem.end;
+	int i, tr_size;
+
+	/* disable BARS for inbound access */
+	ks_dw_pcie_set_dbi_mode(ks_pcie->va_app_base);
+	writel(0, pp->dbi_base + PCI_BASE_ADDRESS_0);
+	writel(0, pp->dbi_base + PCI_BASE_ADDRESS_1);
+	ks_dw_pcie_clear_dbi_mode(ks_pcie->va_app_base);
+
+	/* Set outbound translation size per window division */
+	writel(CFG_PCIM_WIN_SZ_IDX & 0x7, ks_pcie->va_app_base + OB_SIZE);
+
+	tr_size = (1 << (CFG_PCIM_WIN_SZ_IDX & 0x7)) * SZ_1M;
+
+	/* Using Direct 1:1 mapping of RC <-> PCI memory space */
+	for (i = 0; (i < CFG_PCIM_WIN_CNT) && (start < end); i++) {
+		writel(start | 1, ks_pcie->va_app_base + OB_OFFSET_INDEX(i));
+		writel(0, ks_pcie->va_app_base + OB_OFFSET_HI(i));
+		start += tr_size;
+	}
+
+	/* Enable OB translation */
+	writel(OB_XLAT_EN_VAL | readl(ks_pcie->va_app_base + CMD_STATUS),
+		ks_pcie->va_app_base + CMD_STATUS);
+}
+
+/**
+ * ks_pcie_setup_config_addr() - Set up configuration space address for a
+ * device
+ *
+ * @ks_pcie: ptr to keystone_pcie structure
+ * @bus: Bus number the device is residing on
+ * @device: Device number
+ * @function: Function number in device
+ *
+ * Forms and returns the address of configuration space mapped in PCIESS
+ * address space 0. Also configures CFG_SETUP for remote configuration space
+ * access.
+ *
+ * The address space has two regions to access configuration - local and remote.
+ * We access local region for bus 0 (as RC is attached on bus 0) and remote
+ * region for others with TYPE 1 access when bus > 1. As for device on bus = 1,
+ * we will do TYPE 0 access as it will be on our secondary bus (logical).
+ * CFG_SETUP is needed only for remote configuration access.
+ */
+static inline void __iomem *
+ks_pcie_setup_config_addr(struct keystone_pcie *ks_pcie, u8 bus, u8 device,
+			  u8 function)
+{
+	struct pcie_port *pp = &ks_pcie->pp;
+	u32 regval;
+
+	if (bus == 0)
+		return pp->dbi_base;
+
+	regval = (bus << 16) | (device << 8) | function;
+	/*
+	 * Since Bus#1 will be a virtual bus, we need to have TYPE0
+	 * access only.
+	 * TYPE 1
+	 */
+	if (bus != 1)
+		regval |= BIT(24);
+
+	writel(regval, ks_pcie->va_app_base + CFG_SETUP);
+
+	return pp->dbi_base + SPACE0_REMOTE_CFG_OFFSET;
+}
+
+int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
+		unsigned int devfn, int where, int size, u32 *val)
+{
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+	u8 bus_num = bus->number;
+	void __iomem *addr;
+	int ret;
+
+	addr = ks_pcie_setup_config_addr(ks_pcie, bus_num, PCI_SLOT(devfn),
+					 PCI_FUNC(devfn));
+
+	ret = dw_pcie_cfg_read(addr + (where & ~0x3), where, size, val);
+
+	return ret;
+}
+
+int ks_dw_pcie_wr_other_conf(struct pcie_port *pp,
+		struct pci_bus *bus, unsigned int devfn, int where,
+		int size, u32 val)
+{
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+	u8 bus_num = bus->number;
+	void __iomem *addr;
+
+	addr = ks_pcie_setup_config_addr(ks_pcie, bus_num, PCI_SLOT(devfn),
+					 PCI_FUNC(devfn));
+	return dw_pcie_cfg_write(addr + (where & ~0x3), where, size, val);
+}
+
+/**
+ * ks_dw_pcie_set_ib_access() - Setup inbound access
+ *
+ * Configure BAR0 for inbound access. BAR0 is set up in h/w to have
+ * access to PCIESS application register space and just needs to set up
+ * inbound address (mainly used for MSI).
+ */
+static void ks_dw_pcie_set_ib_access(struct keystone_pcie *ks_pcie)
+{
+	struct pcie_port *pp = &ks_pcie->pp;
+
+	/* Configure and set up BAR0 */
+	ks_dw_pcie_set_dbi_mode(ks_pcie->va_app_base);
+
+	/* Enable BAR0 */
+	writel(1, pp->dbi_base + PCI_BASE_ADDRESS_0);
+	writel(SZ_4K - 1, pp->dbi_base + PCI_BASE_ADDRESS_0);
+
+	ks_dw_pcie_clear_dbi_mode(ks_pcie->va_app_base);
+	 /*
+	  * For BAR0, just setting bus address for inbound writes (MSI) should
+	  * be sufficient. Use physical address to avoid any conflicts.
+	  */
+	writel(ks_pcie->app.start, pp->dbi_base + PCI_BASE_ADDRESS_0);
+}
+
+/**
+ * ks_dw_pcie_v3_65_scan_bus() - common function to scan bus
+ *
+ * common functin to scan v3_65 dw based pci bus. This also sets inbound access
+ * after scan.
+ */
+static struct pci_bus *ks_dw_pcie_v3_65_scan_bus(int nr,
+						 struct pci_sys_data *sys)
+{
+	struct pcie_port *pp = sys_to_pcie(sys);
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+	struct pci_bus *bus;
+
+	bus = dw_pcie_scan_bus(nr, sys);
+	if (bus)
+		ks_dw_pcie_set_ib_access(ks_pcie);
+
+	return bus;
+}
+
+/**
+ * ks_dw_pcie_link_up() - Check if link up
+ *
+ */
+int ks_dw_pcie_link_up(struct pcie_port *pp)
+{
+	u32 val = readl(pp->dbi_base + DEBUG0);
+
+	return (val & LTSSM_STATE_MASK) == LTSSM_STATE_L0;
+}
+
+void ks_dw_pcie_initiate_link_train(struct keystone_pcie *ks_pcie)
+{
+	u32 val;
+
+	/* Initiate Link Training.  */
+	val = readl(ks_pcie->va_app_base + CMD_STATUS);
+	writel(LTSSM_EN_VAL | val,  ks_pcie->va_app_base + CMD_STATUS);
+}
+
+static struct hw_pci ks_dw_pcie_v3_65_hw = {
+	.nr_controllers	= 1,
+	.setup		= dw_pcie_setup,
+	.scan		= ks_dw_pcie_v3_65_scan_bus,
+	.add_bus	= dw_pcie_add_bus,
+	.map_irq	= dw_pcie_map_irq,
+};
+
+/**
+ * ks_dw_pcie_host_init() - initialize host for v3_65 dw hardware
+ *
+ * It ioremap the register resources, initialize legacy irq domain
+ * and then call dw_pcie_v3_65_host_init() API to intialize the Keystone
+ * PCI host controller.
+ *
+ */
+int __init ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie,
+				struct device_node *msi_intc_np)
+{
+	struct pcie_port *pp = &ks_pcie->pp;
+	struct platform_device *pdev = to_platform_device(pp->dev);
+	struct resource *res;
+
+	/* index 0 is the config reg. space address */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	pp->dbi_base = devm_ioremap_resource(pp->dev, res);
+	if (IS_ERR(pp->dbi_base))
+		return PTR_ERR(pp->dbi_base);
+
+	/* index 1 is the application reg. space address */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	ks_pcie->app = *res;
+	ks_pcie->va_app_base = devm_ioremap_resource(pp->dev, res);
+	if (IS_ERR(ks_pcie->va_app_base))
+		return PTR_ERR(ks_pcie->va_app_base);
+
+	/* create legacy irq domain */
+	ks_pcie->legacy_irq_domain =
+			irq_domain_add_linear(ks_pcie->legacy_intc_np,
+					MAX_LEGACY_IRQS,
+					&ks_dw_pcie_legacy_irq_domian_ops,
+					NULL);
+	if (!ks_pcie->legacy_irq_domain) {
+		dev_err(pp->dev, "Failed to add irq domain for legacy irqs\n");
+		return -EINVAL;
+	}
+
+	return dw_pcie_v3_65_host_init(pp, &ks_dw_pcie_v3_65_hw, msi_intc_np,
+					&ks_dw_pcie_msi_domain_ops);
+}
diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c
new file mode 100644
index 0000000..e1cf671
--- /dev/null
+++ b/drivers/pci/host/pci-keystone.c
@@ -0,0 +1,381 @@
+/*
+ * PCIe host controller driver for Texas Instruments Keystone SoCs
+ *
+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
+ *		http://www.ti.com
+ *
+ * Author: Murali Karicheri <m-karicheri2@ti.com>
+ * Implementation based on pci-exynos.c and pcie-designware.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/irqchip/chained_irq.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/of_irq.h>
+#include <linux/of.h>
+#include <linux/of_pci.h>
+#include <linux/platform_device.h>
+#include <linux/phy/phy.h>
+#include <linux/resource.h>
+#include <linux/signal.h>
+
+#include "pcie-designware.h"
+#include "pci-keystone.h"
+
+#define DRIVER_NAME	"keystone-pcie"
+
+/* driver specific constants */
+#define MAX_MSI_HOST_IRQS		8
+#define MAX_LEGACY_HOST_IRQS		4
+
+/* RC mode settings */
+#define PCIE_RC_MODE		(BIT(2))
+#define PCIE_MODE_MASK		(BIT(1) | BIT(2))
+
+/* DEV_STAT_CTRL */
+#define PCIE_CAP_BASE       0x70
+
+#define to_keystone_pcie(x)	container_of(x, struct keystone_pcie, pp)
+
+static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie)
+{
+	struct pcie_port *pp = &ks_pcie->pp;
+	int count = 200;
+
+	dw_pcie_setup_rc(pp);
+	if (ks_pcie->link_train)
+		ks_dw_pcie_initiate_link_train(ks_pcie);
+
+	/* check if the link is up or not */
+	while (!dw_pcie_link_up(pp)) {
+		usleep_range(100, 1000);
+		if (--count)
+			continue;
+		dev_err(pp->dev, "phy link never came up\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void ks_pcie_msi_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
+	u32 offset = irq - ks_pcie->msi_host_irqs[0];
+	struct pcie_port *pp = &ks_pcie->pp;
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+
+	dev_dbg(pp->dev, "ks_pci_msi_irq_handler, irq %d\n", irq);
+
+	/*
+	 * The chained irq handler installation would have replaced normal
+	 * interrupt driver handler so we need to take care of mask/unmask and
+	 * ack operation.
+	 */
+	chained_irq_enter(chip, desc);
+	ks_dw_pcie_handle_msi_irq(ks_pcie, offset);
+	chained_irq_exit(chip, desc);
+}
+
+/**
+ * ks_pcie_legacy_irq_handler() - Handle legacy interrupt
+ * @irq: IRQ line for legacy interrupts
+ * @desc: Pointer to irq descriptor
+ *
+ * Traverse through pending legacy interrupts and invoke handler for each. Also
+ * takes care of interrupt controller level mask/ack operation.
+ */
+static void ks_pcie_legacy_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
+	struct pcie_port *pp = &ks_pcie->pp;
+	u32 irq_offset = irq - ks_pcie->legacy_host_irqs[0];
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+
+	dev_dbg(pp->dev, ": Handling legacy irq %d\n", irq);
+
+	/*
+	 * The chained irq handler installation would have replaced normal
+	 * interrupt driver handler so we need to take care of mask/unmask and
+	 * ack operation.
+	 */
+	chained_irq_enter(chip, desc);
+	ks_dw_pcie_handle_legacy_irq(ks_pcie, irq_offset);
+	chained_irq_exit(chip, desc);
+}
+
+static int ks_pcie_get_irq_controller_info(struct keystone_pcie *ks_pcie,
+					   char *controller, int *num_irqs)
+{
+	int temp, max_host_irqs, legacy = 1, *host_irqs, ret = -EINVAL;
+	struct device *dev = ks_pcie->pp.dev;
+	struct device_node *np_pcie = dev->of_node, **np_temp;
+
+	if (!strcmp(controller, "msi-interrupt-controller"))
+		legacy = 0;
+
+	if (legacy) {
+		np_temp = &ks_pcie->legacy_intc_np;
+		max_host_irqs = MAX_LEGACY_HOST_IRQS;
+		host_irqs = &ks_pcie->legacy_host_irqs[0];
+	} else {
+		np_temp = &ks_pcie->msi_intc_np;
+		max_host_irqs = MAX_MSI_HOST_IRQS;
+		host_irqs =  &ks_pcie->msi_host_irqs[0];
+	}
+
+	/* interrupt controller is in a child node */
+	*np_temp = of_find_node_by_name(np_pcie, controller);
+	if (!(*np_temp)) {
+		dev_err(dev, "Node for %s is absent\n", controller);
+		goto out;
+	}
+	temp = of_irq_count(*np_temp);
+	if (!temp)
+		goto out;
+	if (temp > max_host_irqs)
+		dev_warn(dev, "Too many %s interrupts defined %u\n",
+			(legacy ? "legacy" : "MSI"), temp);
+
+	/*
+	 * support upto max_host_irqs. In dt from index 0 to 3 (legacy) or 0 to
+	 * 7 (MSI)
+	 */
+	for (temp = 0; temp < max_host_irqs; temp++) {
+		host_irqs[temp] = irq_of_parse_and_map(*np_temp, temp);
+		if (host_irqs[temp] < 0)
+			break;
+	}
+	if (temp) {
+		*num_irqs = temp;
+		ret = 0;
+	}
+out:
+	return ret;
+}
+
+static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie)
+{
+	int i;
+
+	/* Legacy IRQ */
+	for (i = 0; i < ks_pcie->num_legacy_host_irqs; i++) {
+		irq_set_handler_data(ks_pcie->legacy_host_irqs[i], ks_pcie);
+		irq_set_chained_handler(ks_pcie->legacy_host_irqs[i],
+					ks_pcie_legacy_irq_handler);
+	}
+	ks_dw_pcie_enable_legacy_irqs(ks_pcie);
+
+	/* MSI IRQ */
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		for (i = 0; i < ks_pcie->num_msi_host_irqs; i++) {
+			irq_set_chained_handler(ks_pcie->msi_host_irqs[i],
+						ks_pcie_msi_irq_handler);
+			irq_set_handler_data(ks_pcie->msi_host_irqs[i],
+					     ks_pcie);
+		}
+	}
+}
+
+/*
+ * When a PCI device does not exist during config cycles, keystone host gets a
+ * bus error instead of returning 0xffffffff. This handler always returns 0
+ * for this kind of faults.
+ */
+static int
+keystone_pcie_fault(unsigned long addr, unsigned int fsr,
+		struct pt_regs *regs)
+{
+	unsigned long instr = *(unsigned long *) instruction_pointer(regs);
+
+	if ((instr & 0x0e100090) == 0x00100090) {
+		int reg = (instr >> 12) & 15;
+
+		regs->uregs[reg] = -1;
+		regs->ARM_pc += 4;
+	}
+
+	return 0;
+}
+
+static void __init ks_pcie_host_init(struct pcie_port *pp)
+{
+	u32 vendor_device_id, val;
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+
+	ks_pcie_establish_link(ks_pcie);
+	ks_dw_pcie_setup_rc_app_regs(ks_pcie);
+	ks_pcie_setup_interrupts(ks_pcie);
+	writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8),
+			pp->dbi_base + PCI_IO_BASE);
+
+	/* update the Vendor ID */
+	vendor_device_id = readl(ks_pcie->va_reg_pciid);
+	writew((vendor_device_id >> 16), pp->dbi_base + PCI_DEVICE_ID);
+
+	/* update the DEV_STAT_CTRL to publish right mrrs */
+	val = readl(pp->dbi_base + PCIE_CAP_BASE + PCI_EXP_DEVCTL);
+	val &= ~PCI_EXP_DEVCTL_READRQ;
+	/* set the mrrs to 256 bytes */
+	val |= BIT(12);
+	writel(val, pp->dbi_base + PCIE_CAP_BASE + PCI_EXP_DEVCTL);
+
+	/*
+	 * PCIe access errors that result into OCP errors are caught by ARM as
+	 * "External aborts"
+	 */
+	hook_fault_code(17, keystone_pcie_fault, SIGBUS, 0,
+			"Asynchronous external abort");
+}
+
+static struct pcie_host_ops keystone_pcie_host_ops = {
+	.rd_other_conf = ks_dw_pcie_rd_other_conf,
+	.wr_other_conf = ks_dw_pcie_wr_other_conf,
+	.link_up = ks_dw_pcie_link_up,
+	.host_init = ks_pcie_host_init,
+	.msi_set_irq = ks_dw_pcie_msi_set_irq,
+	.msi_clear_irq = ks_dw_pcie_msi_clear_irq,
+	.get_msi_data = ks_dw_pcie_get_msi_data,
+};
+
+static int add_pcie_port(struct keystone_pcie *ks_pcie,
+			 struct platform_device *pdev)
+{
+	struct pcie_port *pp = &ks_pcie->pp;
+	int ret;
+
+	ret = ks_pcie_get_irq_controller_info(ks_pcie,
+					"legacy-interrupt-controller",
+					&ks_pcie->num_legacy_host_irqs);
+	if (ret)
+		return ret;
+
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		ret = ks_pcie_get_irq_controller_info(ks_pcie,
+						"msi-interrupt-controller",
+						&ks_pcie->num_msi_host_irqs);
+		if (ret)
+			return ret;
+	}
+
+	pp->root_bus_nr = -1;
+	pp->ops = &keystone_pcie_host_ops;
+	ret = ks_dw_pcie_host_init(ks_pcie, ks_pcie->msi_intc_np);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to initialize host\n");
+		return ret;
+	}
+
+	return ret;
+}
+
+static const struct of_device_id ks_pcie_of_match[] = {
+	{
+		.type = "pci",
+		.compatible = "ti,keystone-pcie",
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, ks_pcie_of_match);
+
+static int __exit ks_pcie_remove(struct platform_device *pdev)
+{
+	struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(ks_pcie->clk);
+
+	return 0;
+}
+
+static int __init ks_pcie_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device *dev = &pdev->dev;
+	struct keystone_pcie *ks_pcie;
+	struct pcie_port *pp;
+	struct resource *res;
+	void __iomem *reg_p;
+	struct phy *phy;
+	int ret = 0;
+	u32 val;
+
+	ks_pcie = devm_kzalloc(&pdev->dev, sizeof(*ks_pcie),
+				GFP_KERNEL);
+	if (!ks_pcie) {
+		dev_err(dev, "no memory for keystone pcie\n");
+		return -ENOMEM;
+	}
+	pp = &ks_pcie->pp;
+
+	/* initialize SerDes Phy if present */
+	phy = devm_phy_get(dev, "pcie-phy");
+	if (phy)
+		ret = phy_init(phy);
+
+	/* index 2 is the devcfg register for RC mode settings */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	reg_p = devm_ioremap_resource(dev, res);
+	if (IS_ERR(reg_p))
+		return PTR_ERR(reg_p);
+
+	/* enable RC mode in devcfg */
+	val = readl(reg_p);
+	val &= ~PCIE_MODE_MASK;
+	val |= PCIE_RC_MODE;
+	writel(val, reg_p);
+
+	/* index 3 is to read PCI DEVICE_ID */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+	reg_p = devm_ioremap_resource(dev, res);
+	if (IS_ERR(reg_p))
+		return PTR_ERR(reg_p);
+	ks_pcie->va_reg_pciid = reg_p;
+
+	/* check if we need to enable link training */
+	ks_pcie->link_train =
+		(of_get_property(np, "ti,enable-linktrain", NULL) != NULL);
+
+	pp->dev = dev;
+	platform_set_drvdata(pdev, ks_pcie);
+	ks_pcie->clk = devm_clk_get(dev, "pcie");
+	if (IS_ERR(ks_pcie->clk)) {
+		dev_err(dev, "Failed to get pcie rc clock\n");
+		return PTR_ERR(ks_pcie->clk);
+	}
+	ret = clk_prepare_enable(ks_pcie->clk);
+	if (ret)
+		return ret;
+
+	ret = add_pcie_port(ks_pcie, pdev);
+	if (ret < 0)
+		goto fail_clk;
+
+	return 0;
+fail_clk:
+	clk_disable_unprepare(ks_pcie->clk);
+
+	return ret;
+}
+
+static struct platform_driver ks_pcie_driver __refdata = {
+	.probe  = ks_pcie_probe,
+	.remove = __exit_p(ks_pcie_remove),
+	.driver = {
+		.name	= "keystone-pcie",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(ks_pcie_of_match),
+	},
+};
+
+module_platform_driver(ks_pcie_driver);
+
+MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
+MODULE_DESCRIPTION("Keystone PCIe host controller driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/host/pci-keystone.h b/drivers/pci/host/pci-keystone.h
new file mode 100644
index 0000000..b133f5c
--- /dev/null
+++ b/drivers/pci/host/pci-keystone.h
@@ -0,0 +1,56 @@
+/*
+ * Keystone PCI Controller's common includes
+ *
+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
+ *		http://www.ti.com
+ *
+ * Author: Murali Karicheri <m-karicheri2@ti.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define MAX_LEGACY_IRQS			4
+#define MAX_MSI_HOST_IRQS		8
+#define MAX_LEGACY_HOST_IRQS		4
+
+struct keystone_pcie {
+	struct	clk		*clk;
+	int			link_train;
+	struct	pcie_port	pp;
+	void __iomem		*va_reg_pciid;
+
+	int			num_legacy_host_irqs;
+	int			legacy_host_irqs[MAX_LEGACY_HOST_IRQS];
+	struct			device_node *legacy_intc_np;
+
+	int			num_msi_host_irqs;
+	int			msi_host_irqs[MAX_MSI_HOST_IRQS];
+	struct			device_node *msi_intc_np;
+	struct irq_domain	*legacy_irq_domain;
+
+	/* Application register space */
+	void __iomem		*va_app_base;
+	struct resource		app;
+};
+
+/* Keystone DW specific MSI controller APIs/definitions */
+void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset);
+u32 ks_dw_pcie_get_msi_data(struct pcie_port *pp);
+
+/* Keystone specific PCI controller APIs */
+void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie);
+void ks_dw_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, int offset);
+int  ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie,
+			struct device_node *msi_intc_np);
+int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
+		unsigned int devfn, int where, int size, u32 val);
+int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
+		unsigned int devfn, int where, int size, u32 *val);
+void ks_dw_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie);
+int ks_dw_pcie_link_up(struct pcie_port *pp);
+void ks_dw_pcie_initiate_link_train(struct keystone_pcie *ks_pcie);
+void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq);
+void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq);
-- 
1.7.9.5


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

* [PATCH v3 5/5] PCI: add PCI controller for Keystone PCIe h/w
@ 2014-06-30 21:45   ` Murali Karicheri
  0 siblings, 0 replies; 33+ messages in thread
From: Murali Karicheri @ 2014-06-30 21:45 UTC (permalink / raw)
  To: linux-pci, linux-kernel, devicetree
  Cc: Murali Karicheri, Santosh Shilimkar, Russell King, Grant Likely,
	Rob Herring, Mohit Kumar, Jingoo Han, Bjorn Helgaas,
	Pratyush Anand, Richard Zhu, Kishon Vijay Abraham I, Marek Vasut,
	Arnd Bergmann, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Randy Dunlap

Keystone PCIe controller is based on v3.65 version of the
designware h/w. Main differences are
	1. No ATU support
	2. Legacy and MSI irq functions are implemented in
	   application register space
	3. MSI interrupts are multiplexed over 8 IRQ lines to the Host
	   side.
All of the Application register space handing code are organized into
pci-keystone-dw.c and the functions are called from pci-keystone.c
to implement PCI controller driver. Also add necessary DT documentation
for the driver.

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>

CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
CC: Russell King <linux@arm.linux.org.uk>
CC: Grant Likely <grant.likely@linaro.org>
CC: Rob Herring <robh+dt@kernel.org>
CC: Mohit Kumar <mohit.kumar@st.com>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>
CC: Pratyush Anand <pratyush.anand@st.com>
CC: Richard Zhu <r65037@freescale.com>
CC: Kishon Vijay Abraham I <kishon@ti.com>
CC: Marek Vasut <marex@denx.de>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Pawel Moll <pawel.moll@arm.com>
CC: Mark Rutland <mark.rutland@arm.com>
CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
CC: Kumar Gala <galak@codeaurora.org>
CC: Randy Dunlap <rdunlap@infradead.org>
CC: Grant Likely <grant.likely@linaro.org>
---
 .../devicetree/bindings/pci/pci-keystone.txt       |   69 +++
 drivers/pci/host/Kconfig                           |    5 +
 drivers/pci/host/Makefile                          |    1 +
 drivers/pci/host/pci-keystone-dw.c                 |  523 ++++++++++++++++++++
 drivers/pci/host/pci-keystone.c                    |  381 ++++++++++++++
 drivers/pci/host/pci-keystone.h                    |   56 +++
 6 files changed, 1035 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/pci-keystone.txt
 create mode 100644 drivers/pci/host/pci-keystone-dw.c
 create mode 100644 drivers/pci/host/pci-keystone.c
 create mode 100644 drivers/pci/host/pci-keystone.h

diff --git a/Documentation/devicetree/bindings/pci/pci-keystone.txt b/Documentation/devicetree/bindings/pci/pci-keystone.txt
new file mode 100644
index 0000000..bb39601
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/pci-keystone.txt
@@ -0,0 +1,69 @@
+TI Keystone PCIe interface
+
+Keystone PCI host Controller is based on Designware PCI h/w version 3.65.
+It shares common functions with PCIE Designware core driver and inherit
+common properties defined in
+Documentation/devicetree/bindings/pci/designware-pci.txt
+Compatibility string "dw,snps-pcie-v3.65" is used to identify the verison
+of the DW h/w used on Keystone.
+
+Please refer to Documentation/devicetree/bindings/pci/designware-pci.txt
+for the details of designware DT bindings. Additional properties are
+described here as well propeties that are not applicable.
+
+Required Properties:-
+
+compatibility: "ti,keystone-pcie"
+reg:	index 1 is the base address and length of DW application registers.
+	index 2 is the base address and length of PCI mode configuration
+	register.
+	index 3 is the base address and length of PCI device ID register.
+
+pcie_msi_intc : Interrupt controller device node for MSI irq chip
+	interrupt-cells: should be set to 1
+	interrupt-parent: Parent interrupt controller phandle
+	interrupts: GIC interrupt lines connected to PCI MSI interrupt lines
+
+ Example:
+	pcie_msi_intc: msi-interrupt-controller {
+			interrupt-controller;
+			#interrupt-cells = <1>;
+			interrupt-parent = <&gic>;
+			interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 32 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 33 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 34 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 35 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 37 IRQ_TYPE_EDGE_RISING>;
+	};
+
+pcie_intc: Interrupt controller device node for Legacy irq chip
+	interrupt-cells: should be set to 1
+	interrupt-parent: Parent interrupt controller phandle
+	interrupts: GIC interrupt lines connected to PCI Legacy interrupt lines
+
+ Example:
+	pcie_intc: legacy-interrupt-controller {
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>,
+			<GIC_SPI 27 IRQ_TYPE_EDGE_RISING>,
+			<GIC_SPI 28 IRQ_TYPE_EDGE_RISING>,
+			<GIC_SPI 29 IRQ_TYPE_EDGE_RISING>;
+	};
+
+Optional properties:-
+	phys: phandle to Generic Keystone SerDes phy for PCI
+	phy-names: name of the Generic Keystine SerDes phy for PCI
+	  - If boot loader already does PCI link establishment, then phys and
+	    phy-names shouldn't be present.
+	ti,enable-linktrain - Enable Link training.
+	  - If boot loader already does PCI link establishment, then this
+	    shouldn't be present.
+
+Designware DT Properties not applicable for Keystone PCI
+
+1. pcie_bus clock-names not used. Instead, a phandle to phys is used.
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 21df477..f8bc475 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -46,4 +46,9 @@ config PCI_HOST_GENERIC
 	  Say Y here if you want to support a simple generic PCI host
 	  controller, such as the one emulated by kvmtool.
 
+config PCI_KEYSTONE
+	bool "TI Keystone PCIe controller"
+	depends on ARCH_KEYSTONE
+	select PCIE_DW
+	select PCIEPORTBUS
 endmenu
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 611ba4b..d1b6ce1 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
 obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
 obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o
 obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o
+obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o
diff --git a/drivers/pci/host/pci-keystone-dw.c b/drivers/pci/host/pci-keystone-dw.c
new file mode 100644
index 0000000..3b5b075
--- /dev/null
+++ b/drivers/pci/host/pci-keystone-dw.c
@@ -0,0 +1,523 @@
+/*
+ * Designware application register space functions for Keystone PCI controller
+ *
+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
+ *		http://www.ti.com
+ *
+ * Author: Murali Karicheri <m-karicheri2@ti.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_pci.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+
+#include "pcie-designware.h"
+#include "pci-keystone.h"
+
+/* Application register defines */
+#define LTSSM_EN_VAL		        BIT(0)
+#define LTSSM_STATE_MASK	        0x1f
+#define LTSSM_STATE_L0		        0x11
+#define DIR_SPD				(1 << 17)
+#define DBI_CS2_EN_VAL		        BIT(5)
+#define OB_XLAT_EN_VAL		        BIT(1)
+
+/* Application registers */
+#define CMD_STATUS			0x004
+#define CFG_SETUP			0x008
+#define OB_SIZE				0x030
+#define CFG_PCIM_WIN_SZ_IDX	        3
+#define CFG_PCIM_WIN_CNT	        32
+#define SPACE0_REMOTE_CFG_OFFSET	0x1000
+#define OB_OFFSET_INDEX(n)		(0x200 + (8 * n))
+#define OB_OFFSET_HI(n)			(0x204 + (8 * n))
+
+/* IRQ register defines */
+#define IRQ_EOI                         0x050
+#define IRQ_STATUS			0x184
+#define IRQ_ENABLE_SET			0x188
+#define IRQ_ENABLE_CLR			0x18c
+
+#define MSI_IRQ				0x054
+#define MSI0_IRQ_STATUS			0x104
+#define MSI0_IRQ_ENABLE_SET		0x108
+#define MSI0_IRQ_ENABLE_CLR		0x10c
+#define IRQ_STATUS			0x184
+#define MSI_IRQ_OFFSET			4
+
+/* Config space registers */
+#define DEBUG0			        0x728
+
+#define to_keystone_pcie(x)	container_of(x, struct keystone_pcie, pp)
+
+static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
+{
+	return sys->private_data;
+}
+
+static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset,
+					u32 *bit_pos)
+{
+	*reg_offset = offset % 8;
+	*bit_pos = offset >> 3;
+}
+
+inline u32 ks_dw_pcie_get_msi_data(struct pcie_port *pp)
+{
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+
+	return ks_pcie->app.start + MSI_IRQ;
+}
+
+void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie , int offset)
+{
+	struct pcie_port *pp = &ks_pcie->pp;
+	u32 pending, vector;
+	int src, virq;
+
+	pending = readl(ks_pcie->va_app_base + MSI0_IRQ_STATUS + (offset << 4));
+	/*
+	 * MSI0, Status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit
+	 * shows 1, 9, 17, 25 and so forth
+	 */
+	for (src = 0; src < 4; src++) {
+		if (BIT(src) & pending) {
+			vector = offset + (src << 3);
+			virq = irq_linear_revmap(pp->irq_domain, vector);
+			dev_dbg(pp->dev,
+				"irq: bit %d, vector %d, virq %d\n",
+				 src, vector, virq);
+			generic_handle_irq(virq);
+		}
+	}
+}
+
+static void ks_dw_pcie_msi_irq_ack(struct irq_data *d)
+{
+	u32 offset, reg_offset, bit_pos;
+	struct keystone_pcie *ks_pcie;
+	unsigned int irq = d->irq;
+	struct msi_desc *msi;
+	struct pcie_port *pp;
+
+	msi = irq_get_msi_desc(irq);
+	pp = sys_to_pcie(msi->dev->bus->sysdata);
+	ks_pcie = to_keystone_pcie(pp);
+	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
+	update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
+
+	writel(BIT(bit_pos),
+		ks_pcie->va_app_base + MSI0_IRQ_STATUS + (reg_offset << 4));
+	writel(reg_offset + MSI_IRQ_OFFSET, ks_pcie->va_app_base + IRQ_EOI);
+}
+
+void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq)
+{
+	u32 reg_offset, bit_pos;
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+
+	update_reg_offset_bit_pos(irq, &reg_offset, &bit_pos);
+	writel(BIT(bit_pos),
+		ks_pcie->va_app_base + MSI0_IRQ_ENABLE_SET + (reg_offset << 4));
+}
+
+void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
+{
+	u32 reg_offset, bit_pos;
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+
+	update_reg_offset_bit_pos(irq, &reg_offset, &bit_pos);
+	writel(BIT(bit_pos),
+		ks_pcie->va_app_base + MSI0_IRQ_ENABLE_CLR + (reg_offset << 4));
+}
+
+static void ks_dw_pcie_msi_irq_mask(struct irq_data *d)
+{
+	struct keystone_pcie *ks_pcie;
+	unsigned int irq = d->irq;
+	struct msi_desc *msi;
+	struct pcie_port *pp;
+	u32 offset;
+
+	msi = irq_get_msi_desc(irq);
+	pp = sys_to_pcie(msi->dev->bus->sysdata);
+	ks_pcie = to_keystone_pcie(pp);
+	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
+
+	/* mask the end point if PVM implemented */
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		if (msi->msi_attrib.maskbit)
+			mask_msi_irq(d);
+	}
+
+	ks_dw_pcie_msi_clear_irq(pp, offset);
+}
+
+static void ks_dw_pcie_msi_irq_unmask(struct irq_data *d)
+{
+	struct keystone_pcie *ks_pcie;
+	unsigned int irq = d->irq;
+	struct msi_desc *msi;
+	struct pcie_port *pp;
+	u32 offset;
+
+	msi = irq_get_msi_desc(irq);
+	pp = sys_to_pcie(msi->dev->bus->sysdata);
+	ks_pcie = to_keystone_pcie(pp);
+	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
+
+	/* mask the end point if PVM implemented */
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		if (msi->msi_attrib.maskbit)
+			unmask_msi_irq(d);
+	}
+
+	ks_dw_pcie_msi_set_irq(pp, offset);
+}
+
+static struct irq_chip ks_dw_pcie_msi_irq_chip = {
+	.name = "Keystone-PCIe-MSI-IRQ",
+	.irq_ack = ks_dw_pcie_msi_irq_ack,
+	.irq_mask = ks_dw_pcie_msi_irq_mask,
+	.irq_unmask = ks_dw_pcie_msi_irq_unmask,
+};
+
+static int ks_dw_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
+			irq_hw_number_t hwirq)
+{
+	irq_set_chip_and_handler(irq, &ks_dw_pcie_msi_irq_chip,
+				 handle_level_irq);
+	irq_set_chip_data(irq, domain->host_data);
+	set_irq_flags(irq, IRQF_VALID);
+
+	return 0;
+}
+
+const struct irq_domain_ops ks_dw_pcie_msi_domain_ops = {
+	.map = ks_dw_pcie_msi_map,
+};
+
+void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie)
+{
+	int i;
+
+	for (i = 0; i < MAX_LEGACY_IRQS; i++)
+		writel(0x1, ks_pcie->va_app_base + IRQ_ENABLE_SET + (i << 4));
+}
+
+void ks_dw_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, int offset)
+{
+	struct pcie_port *pp = &ks_pcie->pp;
+	u32 pending;
+	int virq;
+
+	pending = readl(ks_pcie->va_app_base + IRQ_STATUS + (offset << 4));
+
+	if (BIT(0) & pending) {
+		virq = irq_linear_revmap(ks_pcie->legacy_irq_domain, offset);
+		dev_dbg(pp->dev,
+			": irq: irq_offset %d, virq %d\n", offset, virq);
+		generic_handle_irq(virq);
+	}
+
+	/* EOI the INTx interrupt */
+	writel(offset, ks_pcie->va_app_base + IRQ_EOI);
+}
+
+static void ks_dw_pcie_ack_legacy_irq(struct irq_data *d)
+{
+}
+
+static void ks_dw_pcie_mask_legacy_irq(struct irq_data *d)
+{
+}
+
+static void ks_dw_pcie_unmask_legacy_irq(struct irq_data *d)
+{
+}
+
+static struct irq_chip ks_dw_pcie_legacy_irq_chip = {
+	.name = "Keystone-PCI-Legacy-IRQ",
+	.irq_ack = ks_dw_pcie_ack_legacy_irq,
+	.irq_mask = ks_dw_pcie_mask_legacy_irq,
+	.irq_unmask = ks_dw_pcie_unmask_legacy_irq,
+};
+
+static int ks_dw_pcie_init_legacy_irq_map(struct irq_domain *d,
+				unsigned int irq, irq_hw_number_t hw_irq)
+{
+	irq_set_chip_and_handler(irq, &ks_dw_pcie_legacy_irq_chip,
+				handle_level_irq);
+	irq_set_chip_data(irq, d->host_data);
+	set_irq_flags(irq, IRQF_VALID);
+
+	return 0;
+}
+
+static const struct irq_domain_ops ks_dw_pcie_legacy_irq_domian_ops = {
+	.map = ks_dw_pcie_init_legacy_irq_map,
+	.xlate = irq_domain_xlate_onetwocell,
+};
+
+/**
+ * ks_dw_pcie_set_dbi_mode() - Set DBI mode to access overlaid BAR mask registers
+ *
+ * Since modification of dbi_cs2 involves different clock domain, read the
+ * status back to ensure the transition is complete.
+ */
+static inline void ks_dw_pcie_set_dbi_mode(void __iomem *reg_virt)
+{
+	u32 val;
+
+	writel(DBI_CS2_EN_VAL | readl(reg_virt + CMD_STATUS),
+		     reg_virt + CMD_STATUS);
+
+	do {
+		val = readl(reg_virt + CMD_STATUS);
+	} while (!(val & DBI_CS2_EN_VAL));
+}
+
+/**
+ * ks_dw_pcie_clear_dbi_mode() - Disable DBI mode
+ *
+ * Since modification of dbi_cs2 involves different clock domain, read the
+ * status back to ensure the transition is complete.
+ */
+static inline void ks_dw_pcie_clear_dbi_mode(void __iomem *reg_virt)
+{
+	u32 val;
+
+	writel(~DBI_CS2_EN_VAL & readl(reg_virt + CMD_STATUS),
+		     reg_virt + CMD_STATUS);
+
+	do {
+		val = readl(reg_virt + CMD_STATUS);
+	} while (val & DBI_CS2_EN_VAL);
+}
+
+void ks_dw_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie)
+{
+	struct pcie_port *pp = &ks_pcie->pp;
+	u32 start = pp->mem.start, end = pp->mem.end;
+	int i, tr_size;
+
+	/* disable BARS for inbound access */
+	ks_dw_pcie_set_dbi_mode(ks_pcie->va_app_base);
+	writel(0, pp->dbi_base + PCI_BASE_ADDRESS_0);
+	writel(0, pp->dbi_base + PCI_BASE_ADDRESS_1);
+	ks_dw_pcie_clear_dbi_mode(ks_pcie->va_app_base);
+
+	/* Set outbound translation size per window division */
+	writel(CFG_PCIM_WIN_SZ_IDX & 0x7, ks_pcie->va_app_base + OB_SIZE);
+
+	tr_size = (1 << (CFG_PCIM_WIN_SZ_IDX & 0x7)) * SZ_1M;
+
+	/* Using Direct 1:1 mapping of RC <-> PCI memory space */
+	for (i = 0; (i < CFG_PCIM_WIN_CNT) && (start < end); i++) {
+		writel(start | 1, ks_pcie->va_app_base + OB_OFFSET_INDEX(i));
+		writel(0, ks_pcie->va_app_base + OB_OFFSET_HI(i));
+		start += tr_size;
+	}
+
+	/* Enable OB translation */
+	writel(OB_XLAT_EN_VAL | readl(ks_pcie->va_app_base + CMD_STATUS),
+		ks_pcie->va_app_base + CMD_STATUS);
+}
+
+/**
+ * ks_pcie_setup_config_addr() - Set up configuration space address for a
+ * device
+ *
+ * @ks_pcie: ptr to keystone_pcie structure
+ * @bus: Bus number the device is residing on
+ * @device: Device number
+ * @function: Function number in device
+ *
+ * Forms and returns the address of configuration space mapped in PCIESS
+ * address space 0. Also configures CFG_SETUP for remote configuration space
+ * access.
+ *
+ * The address space has two regions to access configuration - local and remote.
+ * We access local region for bus 0 (as RC is attached on bus 0) and remote
+ * region for others with TYPE 1 access when bus > 1. As for device on bus = 1,
+ * we will do TYPE 0 access as it will be on our secondary bus (logical).
+ * CFG_SETUP is needed only for remote configuration access.
+ */
+static inline void __iomem *
+ks_pcie_setup_config_addr(struct keystone_pcie *ks_pcie, u8 bus, u8 device,
+			  u8 function)
+{
+	struct pcie_port *pp = &ks_pcie->pp;
+	u32 regval;
+
+	if (bus == 0)
+		return pp->dbi_base;
+
+	regval = (bus << 16) | (device << 8) | function;
+	/*
+	 * Since Bus#1 will be a virtual bus, we need to have TYPE0
+	 * access only.
+	 * TYPE 1
+	 */
+	if (bus != 1)
+		regval |= BIT(24);
+
+	writel(regval, ks_pcie->va_app_base + CFG_SETUP);
+
+	return pp->dbi_base + SPACE0_REMOTE_CFG_OFFSET;
+}
+
+int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
+		unsigned int devfn, int where, int size, u32 *val)
+{
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+	u8 bus_num = bus->number;
+	void __iomem *addr;
+	int ret;
+
+	addr = ks_pcie_setup_config_addr(ks_pcie, bus_num, PCI_SLOT(devfn),
+					 PCI_FUNC(devfn));
+
+	ret = dw_pcie_cfg_read(addr + (where & ~0x3), where, size, val);
+
+	return ret;
+}
+
+int ks_dw_pcie_wr_other_conf(struct pcie_port *pp,
+		struct pci_bus *bus, unsigned int devfn, int where,
+		int size, u32 val)
+{
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+	u8 bus_num = bus->number;
+	void __iomem *addr;
+
+	addr = ks_pcie_setup_config_addr(ks_pcie, bus_num, PCI_SLOT(devfn),
+					 PCI_FUNC(devfn));
+	return dw_pcie_cfg_write(addr + (where & ~0x3), where, size, val);
+}
+
+/**
+ * ks_dw_pcie_set_ib_access() - Setup inbound access
+ *
+ * Configure BAR0 for inbound access. BAR0 is set up in h/w to have
+ * access to PCIESS application register space and just needs to set up
+ * inbound address (mainly used for MSI).
+ */
+static void ks_dw_pcie_set_ib_access(struct keystone_pcie *ks_pcie)
+{
+	struct pcie_port *pp = &ks_pcie->pp;
+
+	/* Configure and set up BAR0 */
+	ks_dw_pcie_set_dbi_mode(ks_pcie->va_app_base);
+
+	/* Enable BAR0 */
+	writel(1, pp->dbi_base + PCI_BASE_ADDRESS_0);
+	writel(SZ_4K - 1, pp->dbi_base + PCI_BASE_ADDRESS_0);
+
+	ks_dw_pcie_clear_dbi_mode(ks_pcie->va_app_base);
+	 /*
+	  * For BAR0, just setting bus address for inbound writes (MSI) should
+	  * be sufficient. Use physical address to avoid any conflicts.
+	  */
+	writel(ks_pcie->app.start, pp->dbi_base + PCI_BASE_ADDRESS_0);
+}
+
+/**
+ * ks_dw_pcie_v3_65_scan_bus() - common function to scan bus
+ *
+ * common functin to scan v3_65 dw based pci bus. This also sets inbound access
+ * after scan.
+ */
+static struct pci_bus *ks_dw_pcie_v3_65_scan_bus(int nr,
+						 struct pci_sys_data *sys)
+{
+	struct pcie_port *pp = sys_to_pcie(sys);
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+	struct pci_bus *bus;
+
+	bus = dw_pcie_scan_bus(nr, sys);
+	if (bus)
+		ks_dw_pcie_set_ib_access(ks_pcie);
+
+	return bus;
+}
+
+/**
+ * ks_dw_pcie_link_up() - Check if link up
+ *
+ */
+int ks_dw_pcie_link_up(struct pcie_port *pp)
+{
+	u32 val = readl(pp->dbi_base + DEBUG0);
+
+	return (val & LTSSM_STATE_MASK) == LTSSM_STATE_L0;
+}
+
+void ks_dw_pcie_initiate_link_train(struct keystone_pcie *ks_pcie)
+{
+	u32 val;
+
+	/* Initiate Link Training.  */
+	val = readl(ks_pcie->va_app_base + CMD_STATUS);
+	writel(LTSSM_EN_VAL | val,  ks_pcie->va_app_base + CMD_STATUS);
+}
+
+static struct hw_pci ks_dw_pcie_v3_65_hw = {
+	.nr_controllers	= 1,
+	.setup		= dw_pcie_setup,
+	.scan		= ks_dw_pcie_v3_65_scan_bus,
+	.add_bus	= dw_pcie_add_bus,
+	.map_irq	= dw_pcie_map_irq,
+};
+
+/**
+ * ks_dw_pcie_host_init() - initialize host for v3_65 dw hardware
+ *
+ * It ioremap the register resources, initialize legacy irq domain
+ * and then call dw_pcie_v3_65_host_init() API to intialize the Keystone
+ * PCI host controller.
+ *
+ */
+int __init ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie,
+				struct device_node *msi_intc_np)
+{
+	struct pcie_port *pp = &ks_pcie->pp;
+	struct platform_device *pdev = to_platform_device(pp->dev);
+	struct resource *res;
+
+	/* index 0 is the config reg. space address */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	pp->dbi_base = devm_ioremap_resource(pp->dev, res);
+	if (IS_ERR(pp->dbi_base))
+		return PTR_ERR(pp->dbi_base);
+
+	/* index 1 is the application reg. space address */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	ks_pcie->app = *res;
+	ks_pcie->va_app_base = devm_ioremap_resource(pp->dev, res);
+	if (IS_ERR(ks_pcie->va_app_base))
+		return PTR_ERR(ks_pcie->va_app_base);
+
+	/* create legacy irq domain */
+	ks_pcie->legacy_irq_domain =
+			irq_domain_add_linear(ks_pcie->legacy_intc_np,
+					MAX_LEGACY_IRQS,
+					&ks_dw_pcie_legacy_irq_domian_ops,
+					NULL);
+	if (!ks_pcie->legacy_irq_domain) {
+		dev_err(pp->dev, "Failed to add irq domain for legacy irqs\n");
+		return -EINVAL;
+	}
+
+	return dw_pcie_v3_65_host_init(pp, &ks_dw_pcie_v3_65_hw, msi_intc_np,
+					&ks_dw_pcie_msi_domain_ops);
+}
diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c
new file mode 100644
index 0000000..e1cf671
--- /dev/null
+++ b/drivers/pci/host/pci-keystone.c
@@ -0,0 +1,381 @@
+/*
+ * PCIe host controller driver for Texas Instruments Keystone SoCs
+ *
+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
+ *		http://www.ti.com
+ *
+ * Author: Murali Karicheri <m-karicheri2@ti.com>
+ * Implementation based on pci-exynos.c and pcie-designware.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/irqchip/chained_irq.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/of_irq.h>
+#include <linux/of.h>
+#include <linux/of_pci.h>
+#include <linux/platform_device.h>
+#include <linux/phy/phy.h>
+#include <linux/resource.h>
+#include <linux/signal.h>
+
+#include "pcie-designware.h"
+#include "pci-keystone.h"
+
+#define DRIVER_NAME	"keystone-pcie"
+
+/* driver specific constants */
+#define MAX_MSI_HOST_IRQS		8
+#define MAX_LEGACY_HOST_IRQS		4
+
+/* RC mode settings */
+#define PCIE_RC_MODE		(BIT(2))
+#define PCIE_MODE_MASK		(BIT(1) | BIT(2))
+
+/* DEV_STAT_CTRL */
+#define PCIE_CAP_BASE       0x70
+
+#define to_keystone_pcie(x)	container_of(x, struct keystone_pcie, pp)
+
+static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie)
+{
+	struct pcie_port *pp = &ks_pcie->pp;
+	int count = 200;
+
+	dw_pcie_setup_rc(pp);
+	if (ks_pcie->link_train)
+		ks_dw_pcie_initiate_link_train(ks_pcie);
+
+	/* check if the link is up or not */
+	while (!dw_pcie_link_up(pp)) {
+		usleep_range(100, 1000);
+		if (--count)
+			continue;
+		dev_err(pp->dev, "phy link never came up\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void ks_pcie_msi_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
+	u32 offset = irq - ks_pcie->msi_host_irqs[0];
+	struct pcie_port *pp = &ks_pcie->pp;
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+
+	dev_dbg(pp->dev, "ks_pci_msi_irq_handler, irq %d\n", irq);
+
+	/*
+	 * The chained irq handler installation would have replaced normal
+	 * interrupt driver handler so we need to take care of mask/unmask and
+	 * ack operation.
+	 */
+	chained_irq_enter(chip, desc);
+	ks_dw_pcie_handle_msi_irq(ks_pcie, offset);
+	chained_irq_exit(chip, desc);
+}
+
+/**
+ * ks_pcie_legacy_irq_handler() - Handle legacy interrupt
+ * @irq: IRQ line for legacy interrupts
+ * @desc: Pointer to irq descriptor
+ *
+ * Traverse through pending legacy interrupts and invoke handler for each. Also
+ * takes care of interrupt controller level mask/ack operation.
+ */
+static void ks_pcie_legacy_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
+	struct pcie_port *pp = &ks_pcie->pp;
+	u32 irq_offset = irq - ks_pcie->legacy_host_irqs[0];
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+
+	dev_dbg(pp->dev, ": Handling legacy irq %d\n", irq);
+
+	/*
+	 * The chained irq handler installation would have replaced normal
+	 * interrupt driver handler so we need to take care of mask/unmask and
+	 * ack operation.
+	 */
+	chained_irq_enter(chip, desc);
+	ks_dw_pcie_handle_legacy_irq(ks_pcie, irq_offset);
+	chained_irq_exit(chip, desc);
+}
+
+static int ks_pcie_get_irq_controller_info(struct keystone_pcie *ks_pcie,
+					   char *controller, int *num_irqs)
+{
+	int temp, max_host_irqs, legacy = 1, *host_irqs, ret = -EINVAL;
+	struct device *dev = ks_pcie->pp.dev;
+	struct device_node *np_pcie = dev->of_node, **np_temp;
+
+	if (!strcmp(controller, "msi-interrupt-controller"))
+		legacy = 0;
+
+	if (legacy) {
+		np_temp = &ks_pcie->legacy_intc_np;
+		max_host_irqs = MAX_LEGACY_HOST_IRQS;
+		host_irqs = &ks_pcie->legacy_host_irqs[0];
+	} else {
+		np_temp = &ks_pcie->msi_intc_np;
+		max_host_irqs = MAX_MSI_HOST_IRQS;
+		host_irqs =  &ks_pcie->msi_host_irqs[0];
+	}
+
+	/* interrupt controller is in a child node */
+	*np_temp = of_find_node_by_name(np_pcie, controller);
+	if (!(*np_temp)) {
+		dev_err(dev, "Node for %s is absent\n", controller);
+		goto out;
+	}
+	temp = of_irq_count(*np_temp);
+	if (!temp)
+		goto out;
+	if (temp > max_host_irqs)
+		dev_warn(dev, "Too many %s interrupts defined %u\n",
+			(legacy ? "legacy" : "MSI"), temp);
+
+	/*
+	 * support upto max_host_irqs. In dt from index 0 to 3 (legacy) or 0 to
+	 * 7 (MSI)
+	 */
+	for (temp = 0; temp < max_host_irqs; temp++) {
+		host_irqs[temp] = irq_of_parse_and_map(*np_temp, temp);
+		if (host_irqs[temp] < 0)
+			break;
+	}
+	if (temp) {
+		*num_irqs = temp;
+		ret = 0;
+	}
+out:
+	return ret;
+}
+
+static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie)
+{
+	int i;
+
+	/* Legacy IRQ */
+	for (i = 0; i < ks_pcie->num_legacy_host_irqs; i++) {
+		irq_set_handler_data(ks_pcie->legacy_host_irqs[i], ks_pcie);
+		irq_set_chained_handler(ks_pcie->legacy_host_irqs[i],
+					ks_pcie_legacy_irq_handler);
+	}
+	ks_dw_pcie_enable_legacy_irqs(ks_pcie);
+
+	/* MSI IRQ */
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		for (i = 0; i < ks_pcie->num_msi_host_irqs; i++) {
+			irq_set_chained_handler(ks_pcie->msi_host_irqs[i],
+						ks_pcie_msi_irq_handler);
+			irq_set_handler_data(ks_pcie->msi_host_irqs[i],
+					     ks_pcie);
+		}
+	}
+}
+
+/*
+ * When a PCI device does not exist during config cycles, keystone host gets a
+ * bus error instead of returning 0xffffffff. This handler always returns 0
+ * for this kind of faults.
+ */
+static int
+keystone_pcie_fault(unsigned long addr, unsigned int fsr,
+		struct pt_regs *regs)
+{
+	unsigned long instr = *(unsigned long *) instruction_pointer(regs);
+
+	if ((instr & 0x0e100090) == 0x00100090) {
+		int reg = (instr >> 12) & 15;
+
+		regs->uregs[reg] = -1;
+		regs->ARM_pc += 4;
+	}
+
+	return 0;
+}
+
+static void __init ks_pcie_host_init(struct pcie_port *pp)
+{
+	u32 vendor_device_id, val;
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+
+	ks_pcie_establish_link(ks_pcie);
+	ks_dw_pcie_setup_rc_app_regs(ks_pcie);
+	ks_pcie_setup_interrupts(ks_pcie);
+	writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8),
+			pp->dbi_base + PCI_IO_BASE);
+
+	/* update the Vendor ID */
+	vendor_device_id = readl(ks_pcie->va_reg_pciid);
+	writew((vendor_device_id >> 16), pp->dbi_base + PCI_DEVICE_ID);
+
+	/* update the DEV_STAT_CTRL to publish right mrrs */
+	val = readl(pp->dbi_base + PCIE_CAP_BASE + PCI_EXP_DEVCTL);
+	val &= ~PCI_EXP_DEVCTL_READRQ;
+	/* set the mrrs to 256 bytes */
+	val |= BIT(12);
+	writel(val, pp->dbi_base + PCIE_CAP_BASE + PCI_EXP_DEVCTL);
+
+	/*
+	 * PCIe access errors that result into OCP errors are caught by ARM as
+	 * "External aborts"
+	 */
+	hook_fault_code(17, keystone_pcie_fault, SIGBUS, 0,
+			"Asynchronous external abort");
+}
+
+static struct pcie_host_ops keystone_pcie_host_ops = {
+	.rd_other_conf = ks_dw_pcie_rd_other_conf,
+	.wr_other_conf = ks_dw_pcie_wr_other_conf,
+	.link_up = ks_dw_pcie_link_up,
+	.host_init = ks_pcie_host_init,
+	.msi_set_irq = ks_dw_pcie_msi_set_irq,
+	.msi_clear_irq = ks_dw_pcie_msi_clear_irq,
+	.get_msi_data = ks_dw_pcie_get_msi_data,
+};
+
+static int add_pcie_port(struct keystone_pcie *ks_pcie,
+			 struct platform_device *pdev)
+{
+	struct pcie_port *pp = &ks_pcie->pp;
+	int ret;
+
+	ret = ks_pcie_get_irq_controller_info(ks_pcie,
+					"legacy-interrupt-controller",
+					&ks_pcie->num_legacy_host_irqs);
+	if (ret)
+		return ret;
+
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		ret = ks_pcie_get_irq_controller_info(ks_pcie,
+						"msi-interrupt-controller",
+						&ks_pcie->num_msi_host_irqs);
+		if (ret)
+			return ret;
+	}
+
+	pp->root_bus_nr = -1;
+	pp->ops = &keystone_pcie_host_ops;
+	ret = ks_dw_pcie_host_init(ks_pcie, ks_pcie->msi_intc_np);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to initialize host\n");
+		return ret;
+	}
+
+	return ret;
+}
+
+static const struct of_device_id ks_pcie_of_match[] = {
+	{
+		.type = "pci",
+		.compatible = "ti,keystone-pcie",
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, ks_pcie_of_match);
+
+static int __exit ks_pcie_remove(struct platform_device *pdev)
+{
+	struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(ks_pcie->clk);
+
+	return 0;
+}
+
+static int __init ks_pcie_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device *dev = &pdev->dev;
+	struct keystone_pcie *ks_pcie;
+	struct pcie_port *pp;
+	struct resource *res;
+	void __iomem *reg_p;
+	struct phy *phy;
+	int ret = 0;
+	u32 val;
+
+	ks_pcie = devm_kzalloc(&pdev->dev, sizeof(*ks_pcie),
+				GFP_KERNEL);
+	if (!ks_pcie) {
+		dev_err(dev, "no memory for keystone pcie\n");
+		return -ENOMEM;
+	}
+	pp = &ks_pcie->pp;
+
+	/* initialize SerDes Phy if present */
+	phy = devm_phy_get(dev, "pcie-phy");
+	if (phy)
+		ret = phy_init(phy);
+
+	/* index 2 is the devcfg register for RC mode settings */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	reg_p = devm_ioremap_resource(dev, res);
+	if (IS_ERR(reg_p))
+		return PTR_ERR(reg_p);
+
+	/* enable RC mode in devcfg */
+	val = readl(reg_p);
+	val &= ~PCIE_MODE_MASK;
+	val |= PCIE_RC_MODE;
+	writel(val, reg_p);
+
+	/* index 3 is to read PCI DEVICE_ID */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+	reg_p = devm_ioremap_resource(dev, res);
+	if (IS_ERR(reg_p))
+		return PTR_ERR(reg_p);
+	ks_pcie->va_reg_pciid = reg_p;
+
+	/* check if we need to enable link training */
+	ks_pcie->link_train =
+		(of_get_property(np, "ti,enable-linktrain", NULL) != NULL);
+
+	pp->dev = dev;
+	platform_set_drvdata(pdev, ks_pcie);
+	ks_pcie->clk = devm_clk_get(dev, "pcie");
+	if (IS_ERR(ks_pcie->clk)) {
+		dev_err(dev, "Failed to get pcie rc clock\n");
+		return PTR_ERR(ks_pcie->clk);
+	}
+	ret = clk_prepare_enable(ks_pcie->clk);
+	if (ret)
+		return ret;
+
+	ret = add_pcie_port(ks_pcie, pdev);
+	if (ret < 0)
+		goto fail_clk;
+
+	return 0;
+fail_clk:
+	clk_disable_unprepare(ks_pcie->clk);
+
+	return ret;
+}
+
+static struct platform_driver ks_pcie_driver __refdata = {
+	.probe  = ks_pcie_probe,
+	.remove = __exit_p(ks_pcie_remove),
+	.driver = {
+		.name	= "keystone-pcie",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(ks_pcie_of_match),
+	},
+};
+
+module_platform_driver(ks_pcie_driver);
+
+MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
+MODULE_DESCRIPTION("Keystone PCIe host controller driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/host/pci-keystone.h b/drivers/pci/host/pci-keystone.h
new file mode 100644
index 0000000..b133f5c
--- /dev/null
+++ b/drivers/pci/host/pci-keystone.h
@@ -0,0 +1,56 @@
+/*
+ * Keystone PCI Controller's common includes
+ *
+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
+ *		http://www.ti.com
+ *
+ * Author: Murali Karicheri <m-karicheri2@ti.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define MAX_LEGACY_IRQS			4
+#define MAX_MSI_HOST_IRQS		8
+#define MAX_LEGACY_HOST_IRQS		4
+
+struct keystone_pcie {
+	struct	clk		*clk;
+	int			link_train;
+	struct	pcie_port	pp;
+	void __iomem		*va_reg_pciid;
+
+	int			num_legacy_host_irqs;
+	int			legacy_host_irqs[MAX_LEGACY_HOST_IRQS];
+	struct			device_node *legacy_intc_np;
+
+	int			num_msi_host_irqs;
+	int			msi_host_irqs[MAX_MSI_HOST_IRQS];
+	struct			device_node *msi_intc_np;
+	struct irq_domain	*legacy_irq_domain;
+
+	/* Application register space */
+	void __iomem		*va_app_base;
+	struct resource		app;
+};
+
+/* Keystone DW specific MSI controller APIs/definitions */
+void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset);
+u32 ks_dw_pcie_get_msi_data(struct pcie_port *pp);
+
+/* Keystone specific PCI controller APIs */
+void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie);
+void ks_dw_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, int offset);
+int  ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie,
+			struct device_node *msi_intc_np);
+int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
+		unsigned int devfn, int where, int size, u32 val);
+int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
+		unsigned int devfn, int where, int size, u32 *val);
+void ks_dw_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie);
+int ks_dw_pcie_link_up(struct pcie_port *pp);
+void ks_dw_pcie_initiate_link_train(struct keystone_pcie *ks_pcie);
+void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq);
+void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq);
-- 
1.7.9.5

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

* Re: [PATCH v3 0/5] Add Keystone PCIe controller driver
  2014-06-30 21:45 ` Murali Karicheri
                   ` (5 preceding siblings ...)
  (?)
@ 2014-07-05 18:23 ` Bjorn Helgaas
  2014-07-08 12:49     ` Murali Karicheri
  -1 siblings, 1 reply; 33+ messages in thread
From: Bjorn Helgaas @ 2014-07-05 18:23 UTC (permalink / raw)
  To: Murali Karicheri
  Cc: linux-pci, linux-kernel, devicetree, Santosh Shilimkar,
	Russell King, Grant Likely, Rob Herring, Mohit Kumar, Jingoo Han,
	Pratyush Anand, Richard Zhu, Kishon Vijay Abraham I, Marek Vasut,
	Arnd Bergmann, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Randy Dunlap

On Mon, Jun 30, 2014 at 05:45:15PM -0400, Murali Karicheri wrote:
> This patch add PCIe controller driver for Keystone SoCs. This
> is based on v2 of the series posted to the mailing list.
> Keystone PCI controller is based on version 3.65 of the DW
> hardware. This driver re-uses some of the DW core driver
> functions and required modification in some to support
> the old DW h/w based Keystone driver.
> 
> Please review and let me know if you have any comments.

I'm waiting for acks from Mohit or Jingoo for the designware changes.

I'd also like an ack from the devicetree folks for the Keystone binding.

And I think we need a MAINTAINERS update for drivers/pci/host/\*keystone\*

> CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
> CC: Russell King <linux@arm.linux.org.uk>
> CC: Grant Likely <grant.likely@linaro.org>
> CC: Rob Herring <robh+dt@kernel.org>
> CC: Mohit Kumar <mohit.kumar@st.com>
> CC: Jingoo Han <jg1.han@samsung.com>
> CC: Bjorn Helgaas <bhelgaas@google.com>
> CC: Pratyush Anand <pratyush.anand@st.com>
> CC: Richard Zhu <r65037@freescale.com>
> CC: Kishon Vijay Abraham I <kishon@ti.com>
> CC: Marek Vasut <marex@denx.de>
> CC: Arnd Bergmann <arnd@arndb.de>
> CC: Pawel Moll <pawel.moll@arm.com>
> CC: Mark Rutland <mark.rutland@arm.com>
> CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
> CC: Kumar Gala <galak@codeaurora.org>
> CC: Randy Dunlap <rdunlap@infradead.org>
> CC: Grant Likely <grant.likely@linaro.org> 
> 
> Changelog:
> 
> v3
>  - DW application register handling code is now part of
>    Keystone PCI driver. RFC had this code part of Keystone
>    PCI driver, then V1 moved this to a separate file to
>    re-use on other platforms that uses this version of the
>    DW h/w. Then based on comments against v2, this is moved
>    back to Keystone driver.
>  - Keystone SerDes phy driver is removed from this series so that
>    this can be merged independent of that patch
>  - added msi_set_irq()/clear_irq() API's to support Keystone
> 
> V2
>  - Split the designware pcie enhancement patch to multiple
>    patches based on functionality added
>  - Remove the quirk code and add a patch to fix mps/mrss
>    tuning for ARM. Use kernel command line parameter
>    pci=pcie_bus_perf to work with Keystone PCI Controller.
>    Following patch addressed this.
>      [PATCH v1] ARM: pci: add call to pcie_bus_configure_settings()
>  - Add documentation for device tree bindings
>  - Add separate interrupt controller nodes for MSI and Legacy
>    IRQs and use irq map for legacy IRQ
>  - Use compatibility to identify v3.65 version of the DW hardware
>    and use it to customize the designware common code.
>  - Use reg property for configuration space instead of range
>  - Other minor updates based on code inspection. 
> 
> V1
>  - Add an interrupt controller node for Legacy irq chip and use
>    interrupt map/map-mask property to map legacy IRQs A/B/C/D
>  - Add a Phy driver to replace the original serdes driver
>  - Move common application register handling code to a separate
>    file to allow re-use across other platforms that use older
>    DW PCIe h/w
>  - PCI quirk for maximum read request size. Check and override only
>    if the maximum is higher than what controller can handle.
>  - Converted to a module platform driver.
> 
> Murali Karicheri (5):
>   PCI: designware: add rd[wr]_other_conf API
>   PCI: designware: refactor MSI code to work with v3.65 dw hardware
>   PCI: designware: refactor host init code to re-use on keystone PCI
>   PCI: designware: enhance dw core driver to support Keystone PCI host
>     controller
>   PCI: add PCI controller for Keystone PCIe h/w
> 
>  .../devicetree/bindings/pci/designware-pcie.txt    |    2 +
>  .../devicetree/bindings/pci/pci-keystone.txt       |   69 +++
>  drivers/pci/host/Kconfig                           |    5 +
>  drivers/pci/host/Makefile                          |    1 +
>  drivers/pci/host/pci-keystone-dw.c                 |  523 ++++++++++++++++++++
>  drivers/pci/host/pci-keystone.c                    |  381 ++++++++++++++
>  drivers/pci/host/pci-keystone.h                    |   56 +++
>  drivers/pci/host/pcie-designware.c                 |  206 ++++++--
>  drivers/pci/host/pcie-designware.h                 |   17 +-
>  9 files changed, 1207 insertions(+), 53 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/pci/pci-keystone.txt
>  create mode 100644 drivers/pci/host/pci-keystone-dw.c
>  create mode 100644 drivers/pci/host/pci-keystone.c
>  create mode 100644 drivers/pci/host/pci-keystone.h
> 
> -- 
> 1.7.9.5
> 

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

* Re: [PATCH v3 5/5] PCI: add PCI controller for Keystone PCIe h/w
  2014-06-30 21:45   ` Murali Karicheri
  (?)
@ 2014-07-05 18:45   ` Bjorn Helgaas
  -1 siblings, 0 replies; 33+ messages in thread
From: Bjorn Helgaas @ 2014-07-05 18:45 UTC (permalink / raw)
  To: Murali Karicheri
  Cc: linux-pci, linux-kernel, devicetree, Santosh Shilimkar,
	Russell King, Grant Likely, Rob Herring, Mohit Kumar, Jingoo Han,
	Pratyush Anand, Richard Zhu, Kishon Vijay Abraham I, Marek Vasut,
	Arnd Bergmann, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Randy Dunlap

On Mon, Jun 30, 2014 at 05:45:20PM -0400, Murali Karicheri wrote:
> Keystone PCIe controller is based on v3.65 version of the
> designware h/w. Main differences are
> 	1. No ATU support
> 	2. Legacy and MSI irq functions are implemented in
> 	   application register space
> 	3. MSI interrupts are multiplexed over 8 IRQ lines to the Host
> 	   side.
> All of the Application register space handing code are organized into
> pci-keystone-dw.c and the functions are called from pci-keystone.c
> to implement PCI controller driver. Also add necessary DT documentation
> for the driver.

I didn't review this code, but have a few minor comments below.

> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
> 
> CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
> CC: Russell King <linux@arm.linux.org.uk>
> CC: Grant Likely <grant.likely@linaro.org>
> CC: Rob Herring <robh+dt@kernel.org>
> CC: Mohit Kumar <mohit.kumar@st.com>
> CC: Jingoo Han <jg1.han@samsung.com>
> CC: Bjorn Helgaas <bhelgaas@google.com>
> CC: Pratyush Anand <pratyush.anand@st.com>
> CC: Richard Zhu <r65037@freescale.com>
> CC: Kishon Vijay Abraham I <kishon@ti.com>
> CC: Marek Vasut <marex@denx.de>
> CC: Arnd Bergmann <arnd@arndb.de>
> CC: Pawel Moll <pawel.moll@arm.com>
> CC: Mark Rutland <mark.rutland@arm.com>
> CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
> CC: Kumar Gala <galak@codeaurora.org>
> CC: Randy Dunlap <rdunlap@infradead.org>
> CC: Grant Likely <grant.likely@linaro.org>
> ---
>  .../devicetree/bindings/pci/pci-keystone.txt       |   69 +++
>  drivers/pci/host/Kconfig                           |    5 +
>  drivers/pci/host/Makefile                          |    1 +
>  drivers/pci/host/pci-keystone-dw.c                 |  523 ++++++++++++++++++++
>  drivers/pci/host/pci-keystone.c                    |  381 ++++++++++++++
>  drivers/pci/host/pci-keystone.h                    |   56 +++
>  6 files changed, 1035 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/pci/pci-keystone.txt
>  create mode 100644 drivers/pci/host/pci-keystone-dw.c
>  create mode 100644 drivers/pci/host/pci-keystone.c
>  create mode 100644 drivers/pci/host/pci-keystone.h
> 
> diff --git a/Documentation/devicetree/bindings/pci/pci-keystone.txt b/Documentation/devicetree/bindings/pci/pci-keystone.txt
> new file mode 100644
> index 0000000..bb39601
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/pci-keystone.txt
> @@ -0,0 +1,69 @@
> +TI Keystone PCIe interface
> +
> +Keystone PCI host Controller is based on Designware PCI h/w version 3.65.
> +It shares common functions with PCIE Designware core driver and inherit
> +common properties defined in
> +Documentation/devicetree/bindings/pci/designware-pci.txt
> +Compatibility string "dw,snps-pcie-v3.65" is used to identify the verison
> +of the DW h/w used on Keystone.
> +
> +Please refer to Documentation/devicetree/bindings/pci/designware-pci.txt
> +for the details of designware DT bindings. Additional properties are
> +described here as well propeties that are not applicable.
> +
> +Required Properties:-
> +
> +compatibility: "ti,keystone-pcie"
> +reg:	index 1 is the base address and length of DW application registers.
> +	index 2 is the base address and length of PCI mode configuration
> +	register.
> +	index 3 is the base address and length of PCI device ID register.
> +
> +pcie_msi_intc : Interrupt controller device node for MSI irq chip
> +	interrupt-cells: should be set to 1
> +	interrupt-parent: Parent interrupt controller phandle
> +	interrupts: GIC interrupt lines connected to PCI MSI interrupt lines
> +
> + Example:
> +	pcie_msi_intc: msi-interrupt-controller {
> +			interrupt-controller;
> +			#interrupt-cells = <1>;
> +			interrupt-parent = <&gic>;
> +			interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
> +					<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>,
> +					<GIC_SPI 32 IRQ_TYPE_EDGE_RISING>,
> +					<GIC_SPI 33 IRQ_TYPE_EDGE_RISING>,
> +					<GIC_SPI 34 IRQ_TYPE_EDGE_RISING>,
> +					<GIC_SPI 35 IRQ_TYPE_EDGE_RISING>,
> +					<GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
> +					<GIC_SPI 37 IRQ_TYPE_EDGE_RISING>;
> +	};
> +
> +pcie_intc: Interrupt controller device node for Legacy irq chip
> +	interrupt-cells: should be set to 1
> +	interrupt-parent: Parent interrupt controller phandle
> +	interrupts: GIC interrupt lines connected to PCI Legacy interrupt lines
> +
> + Example:
> +	pcie_intc: legacy-interrupt-controller {
> +		interrupt-controller;
> +		#interrupt-cells = <1>;
> +		interrupt-parent = <&gic>;
> +		interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>,
> +			<GIC_SPI 27 IRQ_TYPE_EDGE_RISING>,
> +			<GIC_SPI 28 IRQ_TYPE_EDGE_RISING>,
> +			<GIC_SPI 29 IRQ_TYPE_EDGE_RISING>;
> +	};
> +
> +Optional properties:-
> +	phys: phandle to Generic Keystone SerDes phy for PCI
> +	phy-names: name of the Generic Keystine SerDes phy for PCI
> +	  - If boot loader already does PCI link establishment, then phys and
> +	    phy-names shouldn't be present.
> +	ti,enable-linktrain - Enable Link training.
> +	  - If boot loader already does PCI link establishment, then this
> +	    shouldn't be present.
> +
> +Designware DT Properties not applicable for Keystone PCI
> +
> +1. pcie_bus clock-names not used. Instead, a phandle to phys is used.
> diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
> index 21df477..f8bc475 100644
> --- a/drivers/pci/host/Kconfig
> +++ b/drivers/pci/host/Kconfig
> @@ -46,4 +46,9 @@ config PCI_HOST_GENERIC
>  	  Say Y here if you want to support a simple generic PCI host
>  	  controller, such as the one emulated by kvmtool.
>  
> +config PCI_KEYSTONE
> +	bool "TI Keystone PCIe controller"
> +	depends on ARCH_KEYSTONE
> +	select PCIE_DW
> +	select PCIEPORTBUS
>  endmenu
> diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
> index 611ba4b..d1b6ce1 100644
> --- a/drivers/pci/host/Makefile
> +++ b/drivers/pci/host/Makefile
> @@ -6,3 +6,4 @@ obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
>  obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
>  obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o
>  obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o
> +obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o
> diff --git a/drivers/pci/host/pci-keystone-dw.c b/drivers/pci/host/pci-keystone-dw.c
> new file mode 100644
> index 0000000..3b5b075
> --- /dev/null
> +++ b/drivers/pci/host/pci-keystone-dw.c
> @@ -0,0 +1,523 @@
> +/*
> + * Designware application register space functions for Keystone PCI controller
> + *
> + * Copyright (C) 2013-2014 Texas Instruments., Ltd.
> + *		http://www.ti.com
> + *
> + * Author: Murali Karicheri <m-karicheri2@ti.com>
> + *
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/irq.h>
> +#include <linux/irqdomain.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_pci.h>
> +#include <linux/pci.h>
> +#include <linux/platform_device.h>
> +
> +#include "pcie-designware.h"
> +#include "pci-keystone.h"
> +
> +/* Application register defines */
> +#define LTSSM_EN_VAL		        BIT(0)
> +#define LTSSM_STATE_MASK	        0x1f
> +#define LTSSM_STATE_L0		        0x11
> +#define DIR_SPD				(1 << 17)
> +#define DBI_CS2_EN_VAL		        BIT(5)
> +#define OB_XLAT_EN_VAL		        BIT(1)

It's sort of confusing to mix "BIT(x)" with the hex masks.  Personally I
think it's easier to read the plain hex masks.

> +/* Application registers */
> +#define CMD_STATUS			0x004
> +#define CFG_SETUP			0x008
> +#define OB_SIZE				0x030
> +#define CFG_PCIM_WIN_SZ_IDX	        3
> +#define CFG_PCIM_WIN_CNT	        32
> +#define SPACE0_REMOTE_CFG_OFFSET	0x1000
> +#define OB_OFFSET_INDEX(n)		(0x200 + (8 * n))
> +#define OB_OFFSET_HI(n)			(0x204 + (8 * n))
> +
> +/* IRQ register defines */
> +#define IRQ_EOI                         0x050
> +#define IRQ_STATUS			0x184
> +#define IRQ_ENABLE_SET			0x188
> +#define IRQ_ENABLE_CLR			0x18c
> +
> +#define MSI_IRQ				0x054
> +#define MSI0_IRQ_STATUS			0x104
> +#define MSI0_IRQ_ENABLE_SET		0x108
> +#define MSI0_IRQ_ENABLE_CLR		0x10c
> +#define IRQ_STATUS			0x184
> +#define MSI_IRQ_OFFSET			4
> +
> +/* Config space registers */
> +#define DEBUG0			        0x728
> +
> +#define to_keystone_pcie(x)	container_of(x, struct keystone_pcie, pp)
> +
> +static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
> +{
> +	return sys->private_data;
> +}
> +
> +static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset,
> +					u32 *bit_pos)
> +{
> +	*reg_offset = offset % 8;
> +	*bit_pos = offset >> 3;
> +}
> +
> +inline u32 ks_dw_pcie_get_msi_data(struct pcie_port *pp)

I don't think this should be marked "inline".

> +{
> +	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
> +
> +	return ks_pcie->app.start + MSI_IRQ;
> +}
> +
> +void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie , int offset)
> +{
> +	struct pcie_port *pp = &ks_pcie->pp;
> +	u32 pending, vector;
> +	int src, virq;
> +
> +	pending = readl(ks_pcie->va_app_base + MSI0_IRQ_STATUS + (offset << 4));
> +	/*
> +	 * MSI0, Status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit
> +	 * shows 1, 9, 17, 25 and so forth
> +	 */
> +	for (src = 0; src < 4; src++) {
> +		if (BIT(src) & pending) {
> +			vector = offset + (src << 3);
> +			virq = irq_linear_revmap(pp->irq_domain, vector);
> +			dev_dbg(pp->dev,
> +				"irq: bit %d, vector %d, virq %d\n",
> +				 src, vector, virq);
> +			generic_handle_irq(virq);
> +		}
> +	}
> +}
> +
> +static void ks_dw_pcie_msi_irq_ack(struct irq_data *d)
> +{
> +	u32 offset, reg_offset, bit_pos;
> +	struct keystone_pcie *ks_pcie;
> +	unsigned int irq = d->irq;
> +	struct msi_desc *msi;
> +	struct pcie_port *pp;
> +
> +	msi = irq_get_msi_desc(irq);
> +	pp = sys_to_pcie(msi->dev->bus->sysdata);
> +	ks_pcie = to_keystone_pcie(pp);
> +	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
> +	update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
> +
> +	writel(BIT(bit_pos),
> +		ks_pcie->va_app_base + MSI0_IRQ_STATUS + (reg_offset << 4));
> +	writel(reg_offset + MSI_IRQ_OFFSET, ks_pcie->va_app_base + IRQ_EOI);
> +}
> +
> +void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq)
> +{
> +	u32 reg_offset, bit_pos;
> +	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
> +
> +	update_reg_offset_bit_pos(irq, &reg_offset, &bit_pos);
> +	writel(BIT(bit_pos),
> +		ks_pcie->va_app_base + MSI0_IRQ_ENABLE_SET + (reg_offset << 4));
> +}
> +
> +void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
> +{
> +	u32 reg_offset, bit_pos;
> +	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
> +
> +	update_reg_offset_bit_pos(irq, &reg_offset, &bit_pos);
> +	writel(BIT(bit_pos),
> +		ks_pcie->va_app_base + MSI0_IRQ_ENABLE_CLR + (reg_offset << 4));
> +}
> +
> +static void ks_dw_pcie_msi_irq_mask(struct irq_data *d)
> +{
> +	struct keystone_pcie *ks_pcie;
> +	unsigned int irq = d->irq;
> +	struct msi_desc *msi;
> +	struct pcie_port *pp;
> +	u32 offset;
> +
> +	msi = irq_get_msi_desc(irq);
> +	pp = sys_to_pcie(msi->dev->bus->sysdata);
> +	ks_pcie = to_keystone_pcie(pp);
> +	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
> +
> +	/* mask the end point if PVM implemented */
> +	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> +		if (msi->msi_attrib.maskbit)
> +			mask_msi_irq(d);
> +	}
> +
> +	ks_dw_pcie_msi_clear_irq(pp, offset);
> +}
> +
> +static void ks_dw_pcie_msi_irq_unmask(struct irq_data *d)
> +{
> +	struct keystone_pcie *ks_pcie;
> +	unsigned int irq = d->irq;
> +	struct msi_desc *msi;
> +	struct pcie_port *pp;
> +	u32 offset;
> +
> +	msi = irq_get_msi_desc(irq);
> +	pp = sys_to_pcie(msi->dev->bus->sysdata);
> +	ks_pcie = to_keystone_pcie(pp);
> +	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
> +
> +	/* mask the end point if PVM implemented */
> +	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> +		if (msi->msi_attrib.maskbit)
> +			unmask_msi_irq(d);
> +	}
> +
> +	ks_dw_pcie_msi_set_irq(pp, offset);
> +}
> +
> +static struct irq_chip ks_dw_pcie_msi_irq_chip = {
> +	.name = "Keystone-PCIe-MSI-IRQ",
> +	.irq_ack = ks_dw_pcie_msi_irq_ack,
> +	.irq_mask = ks_dw_pcie_msi_irq_mask,
> +	.irq_unmask = ks_dw_pcie_msi_irq_unmask,
> +};
> +
> +static int ks_dw_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
> +			irq_hw_number_t hwirq)
> +{
> +	irq_set_chip_and_handler(irq, &ks_dw_pcie_msi_irq_chip,
> +				 handle_level_irq);
> +	irq_set_chip_data(irq, domain->host_data);
> +	set_irq_flags(irq, IRQF_VALID);
> +
> +	return 0;
> +}
> +
> +const struct irq_domain_ops ks_dw_pcie_msi_domain_ops = {
> +	.map = ks_dw_pcie_msi_map,
> +};
> +
> +void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie)
> +{
> +	int i;
> +
> +	for (i = 0; i < MAX_LEGACY_IRQS; i++)
> +		writel(0x1, ks_pcie->va_app_base + IRQ_ENABLE_SET + (i << 4));
> +}
> +
> +void ks_dw_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, int offset)
> +{
> +	struct pcie_port *pp = &ks_pcie->pp;
> +	u32 pending;
> +	int virq;
> +
> +	pending = readl(ks_pcie->va_app_base + IRQ_STATUS + (offset << 4));
> +
> +	if (BIT(0) & pending) {
> +		virq = irq_linear_revmap(ks_pcie->legacy_irq_domain, offset);
> +		dev_dbg(pp->dev,
> +			": irq: irq_offset %d, virq %d\n", offset, virq);
> +		generic_handle_irq(virq);
> +	}
> +
> +	/* EOI the INTx interrupt */
> +	writel(offset, ks_pcie->va_app_base + IRQ_EOI);
> +}
> +
> +static void ks_dw_pcie_ack_legacy_irq(struct irq_data *d)
> +{
> +}
> +
> +static void ks_dw_pcie_mask_legacy_irq(struct irq_data *d)
> +{
> +}
> +
> +static void ks_dw_pcie_unmask_legacy_irq(struct irq_data *d)
> +{
> +}
> +
> +static struct irq_chip ks_dw_pcie_legacy_irq_chip = {
> +	.name = "Keystone-PCI-Legacy-IRQ",
> +	.irq_ack = ks_dw_pcie_ack_legacy_irq,
> +	.irq_mask = ks_dw_pcie_mask_legacy_irq,
> +	.irq_unmask = ks_dw_pcie_unmask_legacy_irq,
> +};
> +
> +static int ks_dw_pcie_init_legacy_irq_map(struct irq_domain *d,
> +				unsigned int irq, irq_hw_number_t hw_irq)
> +{
> +	irq_set_chip_and_handler(irq, &ks_dw_pcie_legacy_irq_chip,
> +				handle_level_irq);
> +	irq_set_chip_data(irq, d->host_data);
> +	set_irq_flags(irq, IRQF_VALID);
> +
> +	return 0;
> +}
> +
> +static const struct irq_domain_ops ks_dw_pcie_legacy_irq_domian_ops = {
> +	.map = ks_dw_pcie_init_legacy_irq_map,
> +	.xlate = irq_domain_xlate_onetwocell,
> +};
> +
> +/**
> + * ks_dw_pcie_set_dbi_mode() - Set DBI mode to access overlaid BAR mask registers
> + *
> + * Since modification of dbi_cs2 involves different clock domain, read the
> + * status back to ensure the transition is complete.
> + */
> +static inline void ks_dw_pcie_set_dbi_mode(void __iomem *reg_virt)

Seems dubious to mark a function that accesses CSRs as "inline".

> +{
> +	u32 val;
> +
> +	writel(DBI_CS2_EN_VAL | readl(reg_virt + CMD_STATUS),
> +		     reg_virt + CMD_STATUS);
> +
> +	do {
> +		val = readl(reg_virt + CMD_STATUS);
> +	} while (!(val & DBI_CS2_EN_VAL));
> +}
> +
> +/**
> + * ks_dw_pcie_clear_dbi_mode() - Disable DBI mode
> + *
> + * Since modification of dbi_cs2 involves different clock domain, read the
> + * status back to ensure the transition is complete.
> + */
> +static inline void ks_dw_pcie_clear_dbi_mode(void __iomem *reg_virt)

Ditto.

> +{
> +	u32 val;
> +
> +	writel(~DBI_CS2_EN_VAL & readl(reg_virt + CMD_STATUS),
> +		     reg_virt + CMD_STATUS);
> +
> +	do {
> +		val = readl(reg_virt + CMD_STATUS);
> +	} while (val & DBI_CS2_EN_VAL);
> +}
> +
> +void ks_dw_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie)
> +{
> +	struct pcie_port *pp = &ks_pcie->pp;
> +	u32 start = pp->mem.start, end = pp->mem.end;
> +	int i, tr_size;
> +
> +	/* disable BARS for inbound access */
> +	ks_dw_pcie_set_dbi_mode(ks_pcie->va_app_base);
> +	writel(0, pp->dbi_base + PCI_BASE_ADDRESS_0);
> +	writel(0, pp->dbi_base + PCI_BASE_ADDRESS_1);
> +	ks_dw_pcie_clear_dbi_mode(ks_pcie->va_app_base);
> +
> +	/* Set outbound translation size per window division */
> +	writel(CFG_PCIM_WIN_SZ_IDX & 0x7, ks_pcie->va_app_base + OB_SIZE);
> +
> +	tr_size = (1 << (CFG_PCIM_WIN_SZ_IDX & 0x7)) * SZ_1M;
> +
> +	/* Using Direct 1:1 mapping of RC <-> PCI memory space */
> +	for (i = 0; (i < CFG_PCIM_WIN_CNT) && (start < end); i++) {
> +		writel(start | 1, ks_pcie->va_app_base + OB_OFFSET_INDEX(i));
> +		writel(0, ks_pcie->va_app_base + OB_OFFSET_HI(i));
> +		start += tr_size;
> +	}
> +
> +	/* Enable OB translation */
> +	writel(OB_XLAT_EN_VAL | readl(ks_pcie->va_app_base + CMD_STATUS),
> +		ks_pcie->va_app_base + CMD_STATUS);
> +}
> +
> +/**
> + * ks_pcie_setup_config_addr() - Set up configuration space address for a
> + * device
> + *
> + * @ks_pcie: ptr to keystone_pcie structure
> + * @bus: Bus number the device is residing on
> + * @device: Device number
> + * @function: Function number in device
> + *
> + * Forms and returns the address of configuration space mapped in PCIESS
> + * address space 0. Also configures CFG_SETUP for remote configuration space
> + * access.
> + *
> + * The address space has two regions to access configuration - local and remote.
> + * We access local region for bus 0 (as RC is attached on bus 0) and remote
> + * region for others with TYPE 1 access when bus > 1. As for device on bus = 1,
> + * we will do TYPE 0 access as it will be on our secondary bus (logical).
> + * CFG_SETUP is needed only for remote configuration access.
> + */
> +static inline void __iomem *
> +ks_pcie_setup_config_addr(struct keystone_pcie *ks_pcie, u8 bus, u8 device,
> +			  u8 function)

Inconsistent formatting (function name is normally on the same line as
its type).  "inline" probably pointless, maybe the name could be shortened,
too, e.g., "ks_pcie_cfg_addr".

Consider passing devfn in, and using PCI_SLOT() and PCI_FUNC() here instead
of in both callers.

> +{
> +	struct pcie_port *pp = &ks_pcie->pp;
> +	u32 regval;
> +
> +	if (bus == 0)
> +		return pp->dbi_base;
> +
> +	regval = (bus << 16) | (device << 8) | function;
> +	/*
> +	 * Since Bus#1 will be a virtual bus, we need to have TYPE0
> +	 * access only.
> +	 * TYPE 1
> +	 */
> +	if (bus != 1)
> +		regval |= BIT(24);
> +
> +	writel(regval, ks_pcie->va_app_base + CFG_SETUP);
> +
> +	return pp->dbi_base + SPACE0_REMOTE_CFG_OFFSET;
> +}
> +
> +int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
> +		unsigned int devfn, int where, int size, u32 *val)
> +{
> +	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
> +	u8 bus_num = bus->number;
> +	void __iomem *addr;
> +	int ret;
> +
> +	addr = ks_pcie_setup_config_addr(ks_pcie, bus_num, PCI_SLOT(devfn),
> +					 PCI_FUNC(devfn));
> +
> +	ret = dw_pcie_cfg_read(addr + (where & ~0x3), where, size, val);
> +
> +	return ret;
> +}
> +
> +int ks_dw_pcie_wr_other_conf(struct pcie_port *pp,
> +		struct pci_bus *bus, unsigned int devfn, int where,
> +		int size, u32 val)
> +{
> +	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
> +	u8 bus_num = bus->number;
> +	void __iomem *addr;
> +
> +	addr = ks_pcie_setup_config_addr(ks_pcie, bus_num, PCI_SLOT(devfn),
> +					 PCI_FUNC(devfn));
> +	return dw_pcie_cfg_write(addr + (where & ~0x3), where, size, val);
> +}
> +
> +/**
> + * ks_dw_pcie_set_ib_access() - Setup inbound access
> + *
> + * Configure BAR0 for inbound access. BAR0 is set up in h/w to have
> + * access to PCIESS application register space and just needs to set up
> + * inbound address (mainly used for MSI).
> + */
> +static void ks_dw_pcie_set_ib_access(struct keystone_pcie *ks_pcie)
> +{
> +	struct pcie_port *pp = &ks_pcie->pp;
> +
> +	/* Configure and set up BAR0 */
> +	ks_dw_pcie_set_dbi_mode(ks_pcie->va_app_base);
> +
> +	/* Enable BAR0 */
> +	writel(1, pp->dbi_base + PCI_BASE_ADDRESS_0);
> +	writel(SZ_4K - 1, pp->dbi_base + PCI_BASE_ADDRESS_0);
> +
> +	ks_dw_pcie_clear_dbi_mode(ks_pcie->va_app_base);

Add a blank line here.

> +	 /*
> +	  * For BAR0, just setting bus address for inbound writes (MSI) should
> +	  * be sufficient. Use physical address to avoid any conflicts.
> +	  */
> +	writel(ks_pcie->app.start, pp->dbi_base + PCI_BASE_ADDRESS_0);
> +}
> +
> +/**
> + * ks_dw_pcie_v3_65_scan_bus() - common function to scan bus
> + *
> + * common functin to scan v3_65 dw based pci bus. This also sets inbound access

s/functin/function/

> + * after scan.
> + */
> +static struct pci_bus *ks_dw_pcie_v3_65_scan_bus(int nr,
> +						 struct pci_sys_data *sys)
> +{
> +	struct pcie_port *pp = sys_to_pcie(sys);
> +	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
> +	struct pci_bus *bus;
> +
> +	bus = dw_pcie_scan_bus(nr, sys);
> +	if (bus)
> +		ks_dw_pcie_set_ib_access(ks_pcie);
> +
> +	return bus;
> +}
> +
> +/**
> + * ks_dw_pcie_link_up() - Check if link up
> + *
> + */
> +int ks_dw_pcie_link_up(struct pcie_port *pp)
> +{
> +	u32 val = readl(pp->dbi_base + DEBUG0);
> +
> +	return (val & LTSSM_STATE_MASK) == LTSSM_STATE_L0;
> +}
> +
> +void ks_dw_pcie_initiate_link_train(struct keystone_pcie *ks_pcie)
> +{
> +	u32 val;
> +
> +	/* Initiate Link Training.  */
> +	val = readl(ks_pcie->va_app_base + CMD_STATUS);
> +	writel(LTSSM_EN_VAL | val,  ks_pcie->va_app_base + CMD_STATUS);
> +}
> +
> +static struct hw_pci ks_dw_pcie_v3_65_hw = {
> +	.nr_controllers	= 1,
> +	.setup		= dw_pcie_setup,
> +	.scan		= ks_dw_pcie_v3_65_scan_bus,
> +	.add_bus	= dw_pcie_add_bus,
> +	.map_irq	= dw_pcie_map_irq,
> +};
> +
> +/**
> + * ks_dw_pcie_host_init() - initialize host for v3_65 dw hardware
> + *
> + * It ioremap the register resources, initialize legacy irq domain
> + * and then call dw_pcie_v3_65_host_init() API to intialize the Keystone
> + * PCI host controller.
> + *
> + */
> +int __init ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie,
> +				struct device_node *msi_intc_np)

Called from add_pcie_port(), which is not __init.  But add_pcie_port() is
only called from ks_pcie_probe(), which *is* __init.  Looks like maybe
add_pcie_port() should be __init as well?

> +{
> +	struct pcie_port *pp = &ks_pcie->pp;
> +	struct platform_device *pdev = to_platform_device(pp->dev);
> +	struct resource *res;
> +
> +	/* index 0 is the config reg. space address */
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	pp->dbi_base = devm_ioremap_resource(pp->dev, res);
> +	if (IS_ERR(pp->dbi_base))
> +		return PTR_ERR(pp->dbi_base);
> +
> +	/* index 1 is the application reg. space address */
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> +	ks_pcie->app = *res;
> +	ks_pcie->va_app_base = devm_ioremap_resource(pp->dev, res);
> +	if (IS_ERR(ks_pcie->va_app_base))
> +		return PTR_ERR(ks_pcie->va_app_base);
> +
> +	/* create legacy irq domain */
> +	ks_pcie->legacy_irq_domain =
> +			irq_domain_add_linear(ks_pcie->legacy_intc_np,
> +					MAX_LEGACY_IRQS,
> +					&ks_dw_pcie_legacy_irq_domian_ops,
> +					NULL);
> +	if (!ks_pcie->legacy_irq_domain) {
> +		dev_err(pp->dev, "Failed to add irq domain for legacy irqs\n");
> +		return -EINVAL;
> +	}
> +
> +	return dw_pcie_v3_65_host_init(pp, &ks_dw_pcie_v3_65_hw, msi_intc_np,
> +					&ks_dw_pcie_msi_domain_ops);
> +}
> diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c
> new file mode 100644
> index 0000000..e1cf671
> --- /dev/null
> +++ b/drivers/pci/host/pci-keystone.c
> @@ -0,0 +1,381 @@
> +/*
> + * PCIe host controller driver for Texas Instruments Keystone SoCs
> + *
> + * Copyright (C) 2013-2014 Texas Instruments., Ltd.
> + *		http://www.ti.com
> + *
> + * Author: Murali Karicheri <m-karicheri2@ti.com>
> + * Implementation based on pci-exynos.c and pcie-designware.c
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/irqchip/chained_irq.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/irqdomain.h>
> +#include <linux/module.h>
> +#include <linux/msi.h>
> +#include <linux/of_irq.h>
> +#include <linux/of.h>
> +#include <linux/of_pci.h>
> +#include <linux/platform_device.h>
> +#include <linux/phy/phy.h>
> +#include <linux/resource.h>
> +#include <linux/signal.h>
> +
> +#include "pcie-designware.h"
> +#include "pci-keystone.h"
> +
> +#define DRIVER_NAME	"keystone-pcie"
> +
> +/* driver specific constants */
> +#define MAX_MSI_HOST_IRQS		8
> +#define MAX_LEGACY_HOST_IRQS		4
> +
> +/* RC mode settings */
> +#define PCIE_RC_MODE		(BIT(2))
> +#define PCIE_MODE_MASK		(BIT(1) | BIT(2))
> +
> +/* DEV_STAT_CTRL */
> +#define PCIE_CAP_BASE       0x70
> +
> +#define to_keystone_pcie(x)	container_of(x, struct keystone_pcie, pp)
> +
> +static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie)
> +{
> +	struct pcie_port *pp = &ks_pcie->pp;
> +	int count = 200;
> +
> +	dw_pcie_setup_rc(pp);
> +	if (ks_pcie->link_train)
> +		ks_dw_pcie_initiate_link_train(ks_pcie);
> +
> +	/* check if the link is up or not */
> +	while (!dw_pcie_link_up(pp)) {
> +		usleep_range(100, 1000);
> +		if (--count)
> +			continue;
> +		dev_err(pp->dev, "phy link never came up\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static void ks_pcie_msi_irq_handler(unsigned int irq, struct irq_desc *desc)
> +{
> +	struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
> +	u32 offset = irq - ks_pcie->msi_host_irqs[0];
> +	struct pcie_port *pp = &ks_pcie->pp;
> +	struct irq_chip *chip = irq_desc_get_chip(desc);
> +
> +	dev_dbg(pp->dev, "ks_pci_msi_irq_handler, irq %d\n", irq);
> +
> +	/*
> +	 * The chained irq handler installation would have replaced normal
> +	 * interrupt driver handler so we need to take care of mask/unmask and
> +	 * ack operation.
> +	 */
> +	chained_irq_enter(chip, desc);
> +	ks_dw_pcie_handle_msi_irq(ks_pcie, offset);
> +	chained_irq_exit(chip, desc);
> +}
> +
> +/**
> + * ks_pcie_legacy_irq_handler() - Handle legacy interrupt
> + * @irq: IRQ line for legacy interrupts
> + * @desc: Pointer to irq descriptor
> + *
> + * Traverse through pending legacy interrupts and invoke handler for each. Also
> + * takes care of interrupt controller level mask/ack operation.
> + */
> +static void ks_pcie_legacy_irq_handler(unsigned int irq, struct irq_desc *desc)
> +{
> +	struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
> +	struct pcie_port *pp = &ks_pcie->pp;
> +	u32 irq_offset = irq - ks_pcie->legacy_host_irqs[0];
> +	struct irq_chip *chip = irq_desc_get_chip(desc);
> +
> +	dev_dbg(pp->dev, ": Handling legacy irq %d\n", irq);
> +
> +	/*
> +	 * The chained irq handler installation would have replaced normal
> +	 * interrupt driver handler so we need to take care of mask/unmask and
> +	 * ack operation.
> +	 */
> +	chained_irq_enter(chip, desc);
> +	ks_dw_pcie_handle_legacy_irq(ks_pcie, irq_offset);
> +	chained_irq_exit(chip, desc);
> +}
> +
> +static int ks_pcie_get_irq_controller_info(struct keystone_pcie *ks_pcie,
> +					   char *controller, int *num_irqs)
> +{
> +	int temp, max_host_irqs, legacy = 1, *host_irqs, ret = -EINVAL;
> +	struct device *dev = ks_pcie->pp.dev;
> +	struct device_node *np_pcie = dev->of_node, **np_temp;
> +
> +	if (!strcmp(controller, "msi-interrupt-controller"))
> +		legacy = 0;
> +
> +	if (legacy) {
> +		np_temp = &ks_pcie->legacy_intc_np;
> +		max_host_irqs = MAX_LEGACY_HOST_IRQS;
> +		host_irqs = &ks_pcie->legacy_host_irqs[0];
> +	} else {
> +		np_temp = &ks_pcie->msi_intc_np;
> +		max_host_irqs = MAX_MSI_HOST_IRQS;
> +		host_irqs =  &ks_pcie->msi_host_irqs[0];
> +	}
> +
> +	/* interrupt controller is in a child node */
> +	*np_temp = of_find_node_by_name(np_pcie, controller);
> +	if (!(*np_temp)) {
> +		dev_err(dev, "Node for %s is absent\n", controller);
> +		goto out;
> +	}
> +	temp = of_irq_count(*np_temp);
> +	if (!temp)
> +		goto out;
> +	if (temp > max_host_irqs)
> +		dev_warn(dev, "Too many %s interrupts defined %u\n",
> +			(legacy ? "legacy" : "MSI"), temp);
> +
> +	/*
> +	 * support upto max_host_irqs. In dt from index 0 to 3 (legacy) or 0 to
> +	 * 7 (MSI)
> +	 */
> +	for (temp = 0; temp < max_host_irqs; temp++) {
> +		host_irqs[temp] = irq_of_parse_and_map(*np_temp, temp);
> +		if (host_irqs[temp] < 0)
> +			break;
> +	}
> +	if (temp) {
> +		*num_irqs = temp;
> +		ret = 0;
> +	}
> +out:
> +	return ret;
> +}
> +
> +static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie)
> +{
> +	int i;
> +
> +	/* Legacy IRQ */
> +	for (i = 0; i < ks_pcie->num_legacy_host_irqs; i++) {
> +		irq_set_handler_data(ks_pcie->legacy_host_irqs[i], ks_pcie);
> +		irq_set_chained_handler(ks_pcie->legacy_host_irqs[i],
> +					ks_pcie_legacy_irq_handler);
> +	}
> +	ks_dw_pcie_enable_legacy_irqs(ks_pcie);
> +
> +	/* MSI IRQ */
> +	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> +		for (i = 0; i < ks_pcie->num_msi_host_irqs; i++) {
> +			irq_set_chained_handler(ks_pcie->msi_host_irqs[i],
> +						ks_pcie_msi_irq_handler);
> +			irq_set_handler_data(ks_pcie->msi_host_irqs[i],
> +					     ks_pcie);
> +		}
> +	}
> +}
> +
> +/*
> + * When a PCI device does not exist during config cycles, keystone host gets a
> + * bus error instead of returning 0xffffffff. This handler always returns 0
> + * for this kind of faults.
> + */
> +static int
> +keystone_pcie_fault(unsigned long addr, unsigned int fsr,
> +		struct pt_regs *regs)

"static int keystone_pcie_fault(..." (on one line).

> +{
> +	unsigned long instr = *(unsigned long *) instruction_pointer(regs);
> +
> +	if ((instr & 0x0e100090) == 0x00100090) {
> +		int reg = (instr >> 12) & 15;
> +
> +		regs->uregs[reg] = -1;
> +		regs->ARM_pc += 4;
> +	}
> +
> +	return 0;
> +}
> +
> +static void __init ks_pcie_host_init(struct pcie_port *pp)
> +{
> +	u32 vendor_device_id, val;
> +	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
> +
> +	ks_pcie_establish_link(ks_pcie);
> +	ks_dw_pcie_setup_rc_app_regs(ks_pcie);
> +	ks_pcie_setup_interrupts(ks_pcie);
> +	writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8),
> +			pp->dbi_base + PCI_IO_BASE);
> +
> +	/* update the Vendor ID */
> +	vendor_device_id = readl(ks_pcie->va_reg_pciid);
> +	writew((vendor_device_id >> 16), pp->dbi_base + PCI_DEVICE_ID);
> +
> +	/* update the DEV_STAT_CTRL to publish right mrrs */
> +	val = readl(pp->dbi_base + PCIE_CAP_BASE + PCI_EXP_DEVCTL);
> +	val &= ~PCI_EXP_DEVCTL_READRQ;
> +	/* set the mrrs to 256 bytes */
> +	val |= BIT(12);
> +	writel(val, pp->dbi_base + PCIE_CAP_BASE + PCI_EXP_DEVCTL);
> +
> +	/*
> +	 * PCIe access errors that result into OCP errors are caught by ARM as
> +	 * "External aborts"
> +	 */
> +	hook_fault_code(17, keystone_pcie_fault, SIGBUS, 0,
> +			"Asynchronous external abort");
> +}
> +
> +static struct pcie_host_ops keystone_pcie_host_ops = {
> +	.rd_other_conf = ks_dw_pcie_rd_other_conf,
> +	.wr_other_conf = ks_dw_pcie_wr_other_conf,
> +	.link_up = ks_dw_pcie_link_up,
> +	.host_init = ks_pcie_host_init,
> +	.msi_set_irq = ks_dw_pcie_msi_set_irq,
> +	.msi_clear_irq = ks_dw_pcie_msi_clear_irq,
> +	.get_msi_data = ks_dw_pcie_get_msi_data,
> +};
> +
> +static int add_pcie_port(struct keystone_pcie *ks_pcie,
> +			 struct platform_device *pdev)
> +{
> +	struct pcie_port *pp = &ks_pcie->pp;
> +	int ret;
> +
> +	ret = ks_pcie_get_irq_controller_info(ks_pcie,
> +					"legacy-interrupt-controller",
> +					&ks_pcie->num_legacy_host_irqs);
> +	if (ret)
> +		return ret;
> +
> +	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> +		ret = ks_pcie_get_irq_controller_info(ks_pcie,
> +						"msi-interrupt-controller",
> +						&ks_pcie->num_msi_host_irqs);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	pp->root_bus_nr = -1;
> +	pp->ops = &keystone_pcie_host_ops;
> +	ret = ks_dw_pcie_host_init(ks_pcie, ks_pcie->msi_intc_np);
> +	if (ret) {
> +		dev_err(&pdev->dev, "failed to initialize host\n");
> +		return ret;
> +	}
> +
> +	return ret;
> +}
> +
> +static const struct of_device_id ks_pcie_of_match[] = {
> +	{
> +		.type = "pci",
> +		.compatible = "ti,keystone-pcie",
> +	},
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, ks_pcie_of_match);
> +
> +static int __exit ks_pcie_remove(struct platform_device *pdev)
> +{
> +	struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev);
> +
> +	clk_disable_unprepare(ks_pcie->clk);
> +
> +	return 0;
> +}
> +
> +static int __init ks_pcie_probe(struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	struct device *dev = &pdev->dev;
> +	struct keystone_pcie *ks_pcie;
> +	struct pcie_port *pp;
> +	struct resource *res;
> +	void __iomem *reg_p;
> +	struct phy *phy;
> +	int ret = 0;
> +	u32 val;
> +
> +	ks_pcie = devm_kzalloc(&pdev->dev, sizeof(*ks_pcie),
> +				GFP_KERNEL);
> +	if (!ks_pcie) {
> +		dev_err(dev, "no memory for keystone pcie\n");
> +		return -ENOMEM;
> +	}
> +	pp = &ks_pcie->pp;
> +
> +	/* initialize SerDes Phy if present */
> +	phy = devm_phy_get(dev, "pcie-phy");
> +	if (phy)
> +		ret = phy_init(phy);
> +
> +	/* index 2 is the devcfg register for RC mode settings */
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
> +	reg_p = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(reg_p))
> +		return PTR_ERR(reg_p);
> +
> +	/* enable RC mode in devcfg */
> +	val = readl(reg_p);
> +	val &= ~PCIE_MODE_MASK;
> +	val |= PCIE_RC_MODE;
> +	writel(val, reg_p);
> +
> +	/* index 3 is to read PCI DEVICE_ID */
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
> +	reg_p = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(reg_p))
> +		return PTR_ERR(reg_p);
> +	ks_pcie->va_reg_pciid = reg_p;
> +
> +	/* check if we need to enable link training */
> +	ks_pcie->link_train =
> +		(of_get_property(np, "ti,enable-linktrain", NULL) != NULL);
> +
> +	pp->dev = dev;
> +	platform_set_drvdata(pdev, ks_pcie);
> +	ks_pcie->clk = devm_clk_get(dev, "pcie");
> +	if (IS_ERR(ks_pcie->clk)) {
> +		dev_err(dev, "Failed to get pcie rc clock\n");
> +		return PTR_ERR(ks_pcie->clk);
> +	}
> +	ret = clk_prepare_enable(ks_pcie->clk);
> +	if (ret)
> +		return ret;
> +
> +	ret = add_pcie_port(ks_pcie, pdev);
> +	if (ret < 0)
> +		goto fail_clk;
> +
> +	return 0;
> +fail_clk:
> +	clk_disable_unprepare(ks_pcie->clk);
> +
> +	return ret;
> +}
> +
> +static struct platform_driver ks_pcie_driver __refdata = {
> +	.probe  = ks_pcie_probe,
> +	.remove = __exit_p(ks_pcie_remove),
> +	.driver = {
> +		.name	= "keystone-pcie",
> +		.owner	= THIS_MODULE,
> +		.of_match_table = of_match_ptr(ks_pcie_of_match),
> +	},
> +};
> +
> +module_platform_driver(ks_pcie_driver);
> +
> +MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
> +MODULE_DESCRIPTION("Keystone PCIe host controller driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/pci/host/pci-keystone.h b/drivers/pci/host/pci-keystone.h
> new file mode 100644
> index 0000000..b133f5c
> --- /dev/null
> +++ b/drivers/pci/host/pci-keystone.h
> @@ -0,0 +1,56 @@
> +/*
> + * Keystone PCI Controller's common includes
> + *
> + * Copyright (C) 2013-2014 Texas Instruments., Ltd.
> + *		http://www.ti.com
> + *
> + * Author: Murali Karicheri <m-karicheri2@ti.com>
> + *
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#define MAX_LEGACY_IRQS			4
> +#define MAX_MSI_HOST_IRQS		8
> +#define MAX_LEGACY_HOST_IRQS		4
> +
> +struct keystone_pcie {
> +	struct	clk		*clk;
> +	int			link_train;
> +	struct	pcie_port	pp;
> +	void __iomem		*va_reg_pciid;
> +
> +	int			num_legacy_host_irqs;
> +	int			legacy_host_irqs[MAX_LEGACY_HOST_IRQS];
> +	struct			device_node *legacy_intc_np;
> +
> +	int			num_msi_host_irqs;
> +	int			msi_host_irqs[MAX_MSI_HOST_IRQS];
> +	struct			device_node *msi_intc_np;
> +	struct irq_domain	*legacy_irq_domain;
> +
> +	/* Application register space */
> +	void __iomem		*va_app_base;
> +	struct resource		app;
> +};
> +
> +/* Keystone DW specific MSI controller APIs/definitions */
> +void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset);
> +u32 ks_dw_pcie_get_msi_data(struct pcie_port *pp);
> +
> +/* Keystone specific PCI controller APIs */
> +void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie);
> +void ks_dw_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, int offset);
> +int  ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie,
> +			struct device_node *msi_intc_np);
> +int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
> +		unsigned int devfn, int where, int size, u32 val);
> +int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
> +		unsigned int devfn, int where, int size, u32 *val);
> +void ks_dw_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie);
> +int ks_dw_pcie_link_up(struct pcie_port *pp);
> +void ks_dw_pcie_initiate_link_train(struct keystone_pcie *ks_pcie);
> +void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq);
> +void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq);
> -- 
> 1.7.9.5
> 

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

* RE: [PATCH v3 1/5] PCI: designware: add rd[wr]_other_conf API
  2014-06-30 21:45   ` Murali Karicheri
  (?)
@ 2014-07-07  4:11   ` Mohit KUMAR DCG
  2014-07-07 16:53     ` Murali Karicheri
  -1 siblings, 1 reply; 33+ messages in thread
From: Mohit KUMAR DCG @ 2014-07-07  4:11 UTC (permalink / raw)
  To: Murali Karicheri, linux-pci, linux-kernel, devicetree
  Cc: Santosh Shilimkar, Russell King, Grant Likely, Rob Herring,
	Jingoo Han, Bjorn Helgaas, Pratyush ANAND, Richard Zhu,
	Kishon Vijay Abraham I, Marek Vasut, Arnd Bergmann, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap

Hello Murali,

> -----Original Message-----
> From: Murali Karicheri [mailto:m-karicheri2@ti.com]
> Sent: Tuesday, July 01, 2014 3:15 AM
> To: linux-pci@vger.kernel.org; linux-kernel@vger.kernel.org;
> devicetree@vger.kernel.org
> Cc: Murali Karicheri; Santosh Shilimkar; Russell King; Grant Likely; Rob Herring;
> Mohit KUMAR DCG; Jingoo Han; Bjorn Helgaas; Pratyush ANAND; Richard
> Zhu; Kishon Vijay Abraham I; Marek Vasut; Arnd Bergmann; Pawel Moll;
> Mark Rutland; Ian Campbell; Kumar Gala; Randy Dunlap
> Subject: [PATCH v3 1/5] PCI: designware: add rd[wr]_other_conf API
> 
> v3.65 version of the designware h/w, requires application space registers to
> be configured to access the remote EP config space.
> To support this, add rd[wr]_other_conf API in the pcie_host_opts
> 
> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
> 
> CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
> CC: Russell King <linux@arm.linux.org.uk>
> CC: Grant Likely <grant.likely@linaro.org>
> CC: Rob Herring <robh+dt@kernel.org>
> CC: Mohit Kumar <mohit.kumar@st.com>
> CC: Jingoo Han <jg1.han@samsung.com>
> CC: Bjorn Helgaas <bhelgaas@google.com>
> CC: Pratyush Anand <pratyush.anand@st.com>
> CC: Richard Zhu <r65037@freescale.com>
> CC: Kishon Vijay Abraham I <kishon@ti.com>
> CC: Marek Vasut <marex@denx.de>
> CC: Arnd Bergmann <arnd@arndb.de>
> CC: Pawel Moll <pawel.moll@arm.com>
> CC: Mark Rutland <mark.rutland@arm.com>
> CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
> CC: Kumar Gala <galak@codeaurora.org>
> CC: Randy Dunlap <rdunlap@infradead.org>
> CC: Grant Likely <grant.likely@linaro.org>
> ---
>  drivers/pci/host/pcie-designware.c |   12 ++++++++++--
>  drivers/pci/host/pcie-designware.h |    4 ++++
>  2 files changed, 14 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-
> designware.c
> index 1eaf4df..d8f3af7 100644
> --- a/drivers/pci/host/pcie-designware.c
> +++ b/drivers/pci/host/pcie-designware.c
> @@ -656,7 +656,11 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32
> devfn, int where,
>  	}
> 
>  	if (bus->number != pp->root_bus_nr)
> -		ret = dw_pcie_rd_other_conf(pp, bus, devfn,
> +		if (pp->ops->rd_other_conf)
> +			ret = pp->ops->rd_other_conf(pp, bus, devfn,
> +						where, size, val);
> +		else
> +			ret = dw_pcie_rd_other_conf(pp, bus, devfn,
>  						where, size, val);
>  	else
>  		ret = dw_pcie_rd_own_conf(pp, where, size, val); @@ -
> 679,7 +683,11 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32
> devfn,
>  		return PCIBIOS_DEVICE_NOT_FOUND;
> 
>  	if (bus->number != pp->root_bus_nr)
> -		ret = dw_pcie_wr_other_conf(pp, bus, devfn,
> +		if (pp->ops->wr_other_conf)
> +			ret = pp->ops->wr_other_conf(pp, bus, devfn,
> +						where, size, val);
> +		else
> +			ret = dw_pcie_wr_other_conf(pp, bus, devfn,
>  						where, size, val);
>  	else
>  		ret = dw_pcie_wr_own_conf(pp, where, size, val); diff --git
> a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
> index 77f592f..8121901 100644
> --- a/drivers/pci/host/pcie-designware.h
> +++ b/drivers/pci/host/pcie-designware.h
> @@ -61,6 +61,10 @@ struct pcie_host_ops {
>  			u32 val, void __iomem *dbi_base);
>  	int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32
> *val);
>  	int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32
> val);
> +	int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
> +			unsigned int devfn, int where, int size, u32 *val);
> +	int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
> +			unsigned int devfn, int where, int size, u32 val);
>  	int (*link_up)(struct pcie_port *pp);
>  	void (*host_init)(struct pcie_port *pp);  };

- Now it looks good to me.

Acked-by: Mohit Kumar <mohit.kumar@st.com>

Regards
Mohit
> --
> 1.7.9.5


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

* RE: [PATCH v3 2/5] PCI: designware: refactor MSI code to work with v3.65 dw hardware
  2014-06-30 21:45   ` Murali Karicheri
@ 2014-07-07  4:17     ` Mohit KUMAR DCG
  -1 siblings, 0 replies; 33+ messages in thread
From: Mohit KUMAR DCG @ 2014-07-07  4:17 UTC (permalink / raw)
  To: Murali Karicheri, linux-pci, linux-kernel, devicetree, Jingoo Han
  Cc: Santosh Shilimkar, Russell King, Grant Likely, Rob Herring,
	Jingoo Han, Bjorn Helgaas, Pratyush ANAND, Richard Zhu,
	Kishon Vijay Abraham I, Marek Vasut, Arnd Bergmann, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap

Hello Murali,

> -----Original Message-----
> From: Murali Karicheri [mailto:m-karicheri2@ti.com]
> Sent: Tuesday, July 01, 2014 3:15 AM
> To: linux-pci@vger.kernel.org; linux-kernel@vger.kernel.org;
> devicetree@vger.kernel.org
> Cc: Murali Karicheri; Santosh Shilimkar; Russell King; Grant Likely; Rob Herring;
> Mohit KUMAR DCG; Jingoo Han; Bjorn Helgaas; Pratyush ANAND; Richard
> Zhu; Kishon Vijay Abraham I; Marek Vasut; Arnd Bergmann; Pawel Moll;
> Mark Rutland; Ian Campbell; Kumar Gala; Randy Dunlap
> Subject: [PATCH v3 2/5] PCI: designware: refactor MSI code to work with
> v3.65 dw hardware
> 
> Keystone PCI controller is based on v3.65 version of the DW PCI h/w that
> implements MSI controller registers in application space compared to the
> newer version. This requires updates to the DW core API to support the PCI
> controller driver based on this old DW hardware. Add msi_irq_set()/clear()
> API functions to allow Set/Clear MSI IRQ enable bit in the application register.
> Also the old h/w uses MSI_IRQ register in application register space to raise
> MSI IRQ to the RC from EP. Current code uses the standard mechanism as
> per PCI spec. So add another API get_msi_data() to get the address of this
> register so that common code can be re-used on old h/w.
> 
> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
> 
> CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
> CC: Russell King <linux@arm.linux.org.uk>
> CC: Grant Likely <grant.likely@linaro.org>
> CC: Rob Herring <robh+dt@kernel.org>
> CC: Mohit Kumar <mohit.kumar@st.com>
> CC: Jingoo Han <jg1.han@samsung.com>
> CC: Bjorn Helgaas <bhelgaas@google.com>
> CC: Pratyush Anand <pratyush.anand@st.com>
> CC: Richard Zhu <r65037@freescale.com>
> CC: Kishon Vijay Abraham I <kishon@ti.com>
> CC: Marek Vasut <marex@denx.de>
> CC: Arnd Bergmann <arnd@arndb.de>
> CC: Pawel Moll <pawel.moll@arm.com>
> CC: Mark Rutland <mark.rutland@arm.com>
> CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
> CC: Kumar Gala <galak@codeaurora.org>
> CC: Randy Dunlap <rdunlap@infradead.org>
> CC: Grant Likely <grant.likely@linaro.org>
> ---
>  drivers/pci/host/pcie-designware.c |   50 ++++++++++++++++++++++++++-
> ---------
>  drivers/pci/host/pcie-designware.h |    3 +++
>  2 files changed, 39 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-
> designware.c
> index d8f3af7..905941c 100644
> --- a/drivers/pci/host/pcie-designware.c
> +++ b/drivers/pci/host/pcie-designware.c
> @@ -217,27 +217,47 @@ static int find_valid_pos0(struct pcie_port *pp, int
> msgvec, int pos, int *pos0)
>  	return 0;
>  }
> 
> +static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq) {
> +	unsigned int res, bit, val;
> +
> +	res = (irq / 32) * 12;
> +	bit = irq % 32;
> +	dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
> +	val &= ~(1 << bit);
> +	dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val); }
> +
>  static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
>  			    unsigned int nvec, unsigned int pos)  {
> -	unsigned int i, res, bit, val;
> +	unsigned int i;
> 
>  	for (i = 0; i < nvec; i++) {
>  		irq_set_msi_desc_off(irq_base, i, NULL);
>  		clear_bit(pos + i, pp->msi_irq_in_use);
>  		/* Disable corresponding interrupt on MSI controller */
> -		res = ((pos + i) / 32) * 12;
> -		bit = (pos + i) % 32;
> -		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
> 4, &val);
> -		val &= ~(1 << bit);
> -		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
> 4, val);
> +		if (pp->ops->msi_clear_irq)
> +			pp->ops->msi_clear_irq(pp, pos + i);
> +		else
> +			dw_pcie_msi_clear_irq(pp, pos + i);
>  	}
>  }
> 
> +static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq) {
> +	unsigned int res, bit, val;
> +
> +	res = (irq / 32) * 12;
> +	bit = irq % 32;
> +	dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
> +	val |= 1 << bit;
> +	dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val); }
> +
>  static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)  {
> -	int res, bit, irq, pos0, pos1, i;
> -	u32 val;
> +	int irq, pos0, pos1, i;
>  	struct pcie_port *pp = sys_to_pcie(desc->dev->bus->sysdata);
> 
>  	if (!pp) {
> @@ -281,11 +301,10 @@ static int assign_irq(int no_irqs, struct msi_desc
> *desc, int *pos)
>  		}
>  		set_bit(pos0 + i, pp->msi_irq_in_use);
>  		/*Enable corresponding interrupt in MSI interrupt controller
> */
> -		res = ((pos0 + i) / 32) * 12;
> -		bit = (pos0 + i) % 32;
> -		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
> 4, &val);
> -		val |= 1 << bit;
> -		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
> 4, val);
> +		if (pp->ops->msi_set_irq)
> +			pp->ops->msi_set_irq(pp, pos0 + i);
> +		else
> +			dw_pcie_msi_set_irq(pp, pos0 + i);
>  	}
> 
>  	*pos = pos0;
> @@ -353,7 +372,10 @@ static int dw_msi_setup_irq(struct msi_chip *chip,
> struct pci_dev *pdev,
>  	 */
>  	desc->msi_attrib.multiple = msgvec;
> 
> -	msg.address_lo = virt_to_phys((void *)pp->msi_data);
> +	if (pp->ops->get_msi_data)
> +		msg.address_lo = pp->ops->get_msi_data(pp);
> +	else
> +		msg.address_lo = virt_to_phys((void *)pp->msi_data);
>  	msg.address_hi = 0x0;
>  	msg.data = pos;
>  	write_msi_msg(irq, &msg);
> diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-
> designware.h
> index 8121901..387f69e 100644
> --- a/drivers/pci/host/pcie-designware.h
> +++ b/drivers/pci/host/pcie-designware.h
> @@ -67,6 +67,9 @@ struct pcie_host_ops {
>  			unsigned int devfn, int where, int size, u32 val);
>  	int (*link_up)(struct pcie_port *pp);
>  	void (*host_init)(struct pcie_port *pp);
> +	void (*msi_set_irq)(struct pcie_port *pp, int irq);
> +	void (*msi_clear_irq)(struct pcie_port *pp, int irq);
> +	u32 (*get_msi_data)(struct pcie_port *pp);
>  };
> 
>  int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val);

- Now MSI specific dw code can be shared b/w old Synopsys controller (ver < 3.70)
and newer controller that standardize the MSI settings inside design ware core itself.

Jingoo,

Pls let us know if you have any concern or comment over this.

Acked-by: Mohit Kumar <mohit.kumar@st.com>

Regards
Mohit

> --
> 1.7.9.5


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

* RE: [PATCH v3 2/5] PCI: designware: refactor MSI code to work with v3.65 dw hardware
@ 2014-07-07  4:17     ` Mohit KUMAR DCG
  0 siblings, 0 replies; 33+ messages in thread
From: Mohit KUMAR DCG @ 2014-07-07  4:17 UTC (permalink / raw)
  To: Murali Karicheri, linux-pci, linux-kernel, devicetree
  Cc: Santosh Shilimkar, Russell King, Grant Likely, Rob Herring,
	Jingoo Han, Bjorn Helgaas, Pratyush ANAND, Richard Zhu,
	Kishon Vijay Abraham I, Marek Vasut, Arnd Bergmann, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap

Hello Murali,

> -----Original Message-----
> From: Murali Karicheri [mailto:m-karicheri2@ti.com]
> Sent: Tuesday, July 01, 2014 3:15 AM
> To: linux-pci@vger.kernel.org; linux-kernel@vger.kernel.org;
> devicetree@vger.kernel.org
> Cc: Murali Karicheri; Santosh Shilimkar; Russell King; Grant Likely; Rob Herring;
> Mohit KUMAR DCG; Jingoo Han; Bjorn Helgaas; Pratyush ANAND; Richard
> Zhu; Kishon Vijay Abraham I; Marek Vasut; Arnd Bergmann; Pawel Moll;
> Mark Rutland; Ian Campbell; Kumar Gala; Randy Dunlap
> Subject: [PATCH v3 2/5] PCI: designware: refactor MSI code to work with
> v3.65 dw hardware
> 
> Keystone PCI controller is based on v3.65 version of the DW PCI h/w that
> implements MSI controller registers in application space compared to the
> newer version. This requires updates to the DW core API to support the PCI
> controller driver based on this old DW hardware. Add msi_irq_set()/clear()
> API functions to allow Set/Clear MSI IRQ enable bit in the application register.
> Also the old h/w uses MSI_IRQ register in application register space to raise
> MSI IRQ to the RC from EP. Current code uses the standard mechanism as
> per PCI spec. So add another API get_msi_data() to get the address of this
> register so that common code can be re-used on old h/w.
> 
> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
> 
> CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
> CC: Russell King <linux@arm.linux.org.uk>
> CC: Grant Likely <grant.likely@linaro.org>
> CC: Rob Herring <robh+dt@kernel.org>
> CC: Mohit Kumar <mohit.kumar@st.com>
> CC: Jingoo Han <jg1.han@samsung.com>
> CC: Bjorn Helgaas <bhelgaas@google.com>
> CC: Pratyush Anand <pratyush.anand@st.com>
> CC: Richard Zhu <r65037@freescale.com>
> CC: Kishon Vijay Abraham I <kishon@ti.com>
> CC: Marek Vasut <marex@denx.de>
> CC: Arnd Bergmann <arnd@arndb.de>
> CC: Pawel Moll <pawel.moll@arm.com>
> CC: Mark Rutland <mark.rutland@arm.com>
> CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
> CC: Kumar Gala <galak@codeaurora.org>
> CC: Randy Dunlap <rdunlap@infradead.org>
> CC: Grant Likely <grant.likely@linaro.org>
> ---
>  drivers/pci/host/pcie-designware.c |   50 ++++++++++++++++++++++++++-
> ---------
>  drivers/pci/host/pcie-designware.h |    3 +++
>  2 files changed, 39 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-
> designware.c
> index d8f3af7..905941c 100644
> --- a/drivers/pci/host/pcie-designware.c
> +++ b/drivers/pci/host/pcie-designware.c
> @@ -217,27 +217,47 @@ static int find_valid_pos0(struct pcie_port *pp, int
> msgvec, int pos, int *pos0)
>  	return 0;
>  }
> 
> +static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq) {
> +	unsigned int res, bit, val;
> +
> +	res = (irq / 32) * 12;
> +	bit = irq % 32;
> +	dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
> +	val &= ~(1 << bit);
> +	dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val); }
> +
>  static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
>  			    unsigned int nvec, unsigned int pos)  {
> -	unsigned int i, res, bit, val;
> +	unsigned int i;
> 
>  	for (i = 0; i < nvec; i++) {
>  		irq_set_msi_desc_off(irq_base, i, NULL);
>  		clear_bit(pos + i, pp->msi_irq_in_use);
>  		/* Disable corresponding interrupt on MSI controller */
> -		res = ((pos + i) / 32) * 12;
> -		bit = (pos + i) % 32;
> -		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
> 4, &val);
> -		val &= ~(1 << bit);
> -		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
> 4, val);
> +		if (pp->ops->msi_clear_irq)
> +			pp->ops->msi_clear_irq(pp, pos + i);
> +		else
> +			dw_pcie_msi_clear_irq(pp, pos + i);
>  	}
>  }
> 
> +static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq) {
> +	unsigned int res, bit, val;
> +
> +	res = (irq / 32) * 12;
> +	bit = irq % 32;
> +	dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
> +	val |= 1 << bit;
> +	dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val); }
> +
>  static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)  {
> -	int res, bit, irq, pos0, pos1, i;
> -	u32 val;
> +	int irq, pos0, pos1, i;
>  	struct pcie_port *pp = sys_to_pcie(desc->dev->bus->sysdata);
> 
>  	if (!pp) {
> @@ -281,11 +301,10 @@ static int assign_irq(int no_irqs, struct msi_desc
> *desc, int *pos)
>  		}
>  		set_bit(pos0 + i, pp->msi_irq_in_use);
>  		/*Enable corresponding interrupt in MSI interrupt controller
> */
> -		res = ((pos0 + i) / 32) * 12;
> -		bit = (pos0 + i) % 32;
> -		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
> 4, &val);
> -		val |= 1 << bit;
> -		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
> 4, val);
> +		if (pp->ops->msi_set_irq)
> +			pp->ops->msi_set_irq(pp, pos0 + i);
> +		else
> +			dw_pcie_msi_set_irq(pp, pos0 + i);
>  	}
> 
>  	*pos = pos0;
> @@ -353,7 +372,10 @@ static int dw_msi_setup_irq(struct msi_chip *chip,
> struct pci_dev *pdev,
>  	 */
>  	desc->msi_attrib.multiple = msgvec;
> 
> -	msg.address_lo = virt_to_phys((void *)pp->msi_data);
> +	if (pp->ops->get_msi_data)
> +		msg.address_lo = pp->ops->get_msi_data(pp);
> +	else
> +		msg.address_lo = virt_to_phys((void *)pp->msi_data);
>  	msg.address_hi = 0x0;
>  	msg.data = pos;
>  	write_msi_msg(irq, &msg);
> diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-
> designware.h
> index 8121901..387f69e 100644
> --- a/drivers/pci/host/pcie-designware.h
> +++ b/drivers/pci/host/pcie-designware.h
> @@ -67,6 +67,9 @@ struct pcie_host_ops {
>  			unsigned int devfn, int where, int size, u32 val);
>  	int (*link_up)(struct pcie_port *pp);
>  	void (*host_init)(struct pcie_port *pp);
> +	void (*msi_set_irq)(struct pcie_port *pp, int irq);
> +	void (*msi_clear_irq)(struct pcie_port *pp, int irq);
> +	u32 (*get_msi_data)(struct pcie_port *pp);
>  };
> 
>  int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val);

- Now MSI specific dw code can be shared b/w old Synopsys controller (ver < 3.70)
and newer controller that standardize the MSI settings inside design ware core itself.

Jingoo,

Pls let us know if you have any concern or comment over this.

Acked-by: Mohit Kumar <mohit.kumar@st.com>

Regards
Mohit

> --
> 1.7.9.5

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

* Re: [PATCH v3 2/5] PCI: designware: refactor MSI code to work with v3.65 dw hardware
  2014-07-07  4:17     ` Mohit KUMAR DCG
  (?)
@ 2014-07-07 16:53     ` Murali Karicheri
  2014-07-08 12:20       ` Jingoo Han
  -1 siblings, 1 reply; 33+ messages in thread
From: Murali Karicheri @ 2014-07-07 16:53 UTC (permalink / raw)
  To: Mohit KUMAR DCG
  Cc: linux-pci, linux-kernel, devicetree, Jingoo Han,
	Santosh Shilimkar, Russell King, Grant Likely, Rob Herring,
	Bjorn Helgaas, Pratyush ANAND, Richard Zhu,
	Kishon Vijay Abraham I, Marek Vasut, Arnd Bergmann, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap

On 07/07/2014 12:17 AM, Mohit KUMAR DCG wrote:
> Hello Murali,
>
>> -----Original Message-----
>> From: Murali Karicheri [mailto:m-karicheri2@ti.com]
>> Sent: Tuesday, July 01, 2014 3:15 AM
>> To: linux-pci@vger.kernel.org; linux-kernel@vger.kernel.org;
>> devicetree@vger.kernel.org
>> Cc: Murali Karicheri; Santosh Shilimkar; Russell King; Grant Likely; Rob Herring;
>> Mohit KUMAR DCG; Jingoo Han; Bjorn Helgaas; Pratyush ANAND; Richard
>> Zhu; Kishon Vijay Abraham I; Marek Vasut; Arnd Bergmann; Pawel Moll;
>> Mark Rutland; Ian Campbell; Kumar Gala; Randy Dunlap
>> Subject: [PATCH v3 2/5] PCI: designware: refactor MSI code to work with
>> v3.65 dw hardware
>>
>> Keystone PCI controller is based on v3.65 version of the DW PCI h/w that
>> implements MSI controller registers in application space compared to the
>> newer version. This requires updates to the DW core API to support the PCI
>> controller driver based on this old DW hardware. Add msi_irq_set()/clear()
>> API functions to allow Set/Clear MSI IRQ enable bit in the application register.
>> Also the old h/w uses MSI_IRQ register in application register space to raise
>> MSI IRQ to the RC from EP. Current code uses the standard mechanism as
>> per PCI spec. So add another API get_msi_data() to get the address of this
>> register so that common code can be re-used on old h/w.
>>
>> Signed-off-by: Murali Karicheri<m-karicheri2@ti.com>
>>
>> CC: Santosh Shilimkar<santosh.shilimkar@ti.com>
>> CC: Russell King<linux@arm.linux.org.uk>
>> CC: Grant Likely<grant.likely@linaro.org>
>> CC: Rob Herring<robh+dt@kernel.org>
>> CC: Mohit Kumar<mohit.kumar@st.com>
>> CC: Jingoo Han<jg1.han@samsung.com>
>> CC: Bjorn Helgaas<bhelgaas@google.com>
>> CC: Pratyush Anand<pratyush.anand@st.com>
>> CC: Richard Zhu<r65037@freescale.com>
>> CC: Kishon Vijay Abraham I<kishon@ti.com>
>> CC: Marek Vasut<marex@denx.de>
>> CC: Arnd Bergmann<arnd@arndb.de>
>> CC: Pawel Moll<pawel.moll@arm.com>
>> CC: Mark Rutland<mark.rutland@arm.com>
>> CC: Ian Campbell<ijc+devicetree@hellion.org.uk>
>> CC: Kumar Gala<galak@codeaurora.org>
>> CC: Randy Dunlap<rdunlap@infradead.org>
>> CC: Grant Likely<grant.likely@linaro.org>
>> ---
>>   drivers/pci/host/pcie-designware.c |   50 ++++++++++++++++++++++++++-
>> ---------
>>   drivers/pci/host/pcie-designware.h |    3 +++
>>   2 files changed, 39 insertions(+), 14 deletions(-)
>>
>> diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-
>> designware.c
>> index d8f3af7..905941c 100644
>> --- a/drivers/pci/host/pcie-designware.c
>> +++ b/drivers/pci/host/pcie-designware.c
>> @@ -217,27 +217,47 @@ static int find_valid_pos0(struct pcie_port *pp, int
>> msgvec, int pos, int *pos0)
>>   	return 0;
>>   }
>>
>> +static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq) {
>> +	unsigned int res, bit, val;
>> +
>> +	res = (irq / 32) * 12;
>> +	bit = irq % 32;
>> +	dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,&val);
>> +	val&= ~(1<<  bit);
>> +	dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val); }
>> +
>>   static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
>>   			    unsigned int nvec, unsigned int pos)  {
>> -	unsigned int i, res, bit, val;
>> +	unsigned int i;
>>
>>   	for (i = 0; i<  nvec; i++) {
>>   		irq_set_msi_desc_off(irq_base, i, NULL);
>>   		clear_bit(pos + i, pp->msi_irq_in_use);
>>   		/* Disable corresponding interrupt on MSI controller */
>> -		res = ((pos + i) / 32) * 12;
>> -		bit = (pos + i) % 32;
>> -		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
>> 4,&val);
>> -		val&= ~(1<<  bit);
>> -		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
>> 4, val);
>> +		if (pp->ops->msi_clear_irq)
>> +			pp->ops->msi_clear_irq(pp, pos + i);
>> +		else
>> +			dw_pcie_msi_clear_irq(pp, pos + i);
>>   	}
>>   }
>>
>> +static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq) {
>> +	unsigned int res, bit, val;
>> +
>> +	res = (irq / 32) * 12;
>> +	bit = irq % 32;
>> +	dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,&val);
>> +	val |= 1<<  bit;
>> +	dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val); }
>> +
>>   static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)  {
>> -	int res, bit, irq, pos0, pos1, i;
>> -	u32 val;
>> +	int irq, pos0, pos1, i;
>>   	struct pcie_port *pp = sys_to_pcie(desc->dev->bus->sysdata);
>>
>>   	if (!pp) {
>> @@ -281,11 +301,10 @@ static int assign_irq(int no_irqs, struct msi_desc
>> *desc, int *pos)
>>   		}
>>   		set_bit(pos0 + i, pp->msi_irq_in_use);
>>   		/*Enable corresponding interrupt in MSI interrupt controller
>> */
>> -		res = ((pos0 + i) / 32) * 12;
>> -		bit = (pos0 + i) % 32;
>> -		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
>> 4,&val);
>> -		val |= 1<<  bit;
>> -		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
>> 4, val);
>> +		if (pp->ops->msi_set_irq)
>> +			pp->ops->msi_set_irq(pp, pos0 + i);
>> +		else
>> +			dw_pcie_msi_set_irq(pp, pos0 + i);
>>   	}
>>
>>   	*pos = pos0;
>> @@ -353,7 +372,10 @@ static int dw_msi_setup_irq(struct msi_chip *chip,
>> struct pci_dev *pdev,
>>   	 */
>>   	desc->msi_attrib.multiple = msgvec;
>>
>> -	msg.address_lo = virt_to_phys((void *)pp->msi_data);
>> +	if (pp->ops->get_msi_data)
>> +		msg.address_lo = pp->ops->get_msi_data(pp);
>> +	else
>> +		msg.address_lo = virt_to_phys((void *)pp->msi_data);
>>   	msg.address_hi = 0x0;
>>   	msg.data = pos;
>>   	write_msi_msg(irq,&msg);
>> diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-
>> designware.h
>> index 8121901..387f69e 100644
>> --- a/drivers/pci/host/pcie-designware.h
>> +++ b/drivers/pci/host/pcie-designware.h
>> @@ -67,6 +67,9 @@ struct pcie_host_ops {
>>   			unsigned int devfn, int where, int size, u32 val);
>>   	int (*link_up)(struct pcie_port *pp);
>>   	void (*host_init)(struct pcie_port *pp);
>> +	void (*msi_set_irq)(struct pcie_port *pp, int irq);
>> +	void (*msi_clear_irq)(struct pcie_port *pp, int irq);
>> +	u32 (*get_msi_data)(struct pcie_port *pp);
>>   };
>>
>>   int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val);
>
> - Now MSI specific dw code can be shared b/w old Synopsys controller (ver<  3.70)
> and newer controller that standardize the MSI settings inside design ware core itself.
>
> Jingoo,
>
> Pls let us know if you have any concern or comment over this.
>
> Acked-by: Mohit Kumar<mohit.kumar@st.com>
>
> Regards
> Mohit
>
>> --
>> 1.7.9.5
>
Mohit,

Thanks.

Jingoo, could you provide your response or Ack?

Thanks

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

* Re: [PATCH v3 1/5] PCI: designware: add rd[wr]_other_conf API
  2014-07-07  4:11   ` Mohit KUMAR DCG
@ 2014-07-07 16:53     ` Murali Karicheri
  2014-07-08 12:17       ` Jingoo Han
  0 siblings, 1 reply; 33+ messages in thread
From: Murali Karicheri @ 2014-07-07 16:53 UTC (permalink / raw)
  To: Mohit KUMAR DCG
  Cc: linux-pci, linux-kernel, devicetree, Santosh Shilimkar,
	Russell King, Grant Likely, Rob Herring, Jingoo Han,
	Bjorn Helgaas, Pratyush ANAND, Richard Zhu,
	Kishon Vijay Abraham I, Marek Vasut, Arnd Bergmann, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap

On 07/07/2014 12:11 AM, Mohit KUMAR DCG wrote:
> Hello Murali,
>
>> -----Original Message-----
>> From: Murali Karicheri [mailto:m-karicheri2@ti.com]
>> Sent: Tuesday, July 01, 2014 3:15 AM
>> To: linux-pci@vger.kernel.org; linux-kernel@vger.kernel.org;
>> devicetree@vger.kernel.org
>> Cc: Murali Karicheri; Santosh Shilimkar; Russell King; Grant Likely; Rob Herring;
>> Mohit KUMAR DCG; Jingoo Han; Bjorn Helgaas; Pratyush ANAND; Richard
>> Zhu; Kishon Vijay Abraham I; Marek Vasut; Arnd Bergmann; Pawel Moll;
>> Mark Rutland; Ian Campbell; Kumar Gala; Randy Dunlap
>> Subject: [PATCH v3 1/5] PCI: designware: add rd[wr]_other_conf API
>>
>> v3.65 version of the designware h/w, requires application space registers to
>> be configured to access the remote EP config space.
>> To support this, add rd[wr]_other_conf API in the pcie_host_opts
>>
>> Signed-off-by: Murali Karicheri<m-karicheri2@ti.com>
>>
>> CC: Santosh Shilimkar<santosh.shilimkar@ti.com>
>> CC: Russell King<linux@arm.linux.org.uk>
>> CC: Grant Likely<grant.likely@linaro.org>
>> CC: Rob Herring<robh+dt@kernel.org>
>> CC: Mohit Kumar<mohit.kumar@st.com>
>> CC: Jingoo Han<jg1.han@samsung.com>
>> CC: Bjorn Helgaas<bhelgaas@google.com>
>> CC: Pratyush Anand<pratyush.anand@st.com>
>> CC: Richard Zhu<r65037@freescale.com>
>> CC: Kishon Vijay Abraham I<kishon@ti.com>
>> CC: Marek Vasut<marex@denx.de>
>> CC: Arnd Bergmann<arnd@arndb.de>
>> CC: Pawel Moll<pawel.moll@arm.com>
>> CC: Mark Rutland<mark.rutland@arm.com>
>> CC: Ian Campbell<ijc+devicetree@hellion.org.uk>
>> CC: Kumar Gala<galak@codeaurora.org>
>> CC: Randy Dunlap<rdunlap@infradead.org>
>> CC: Grant Likely<grant.likely@linaro.org>
>> ---
>>   drivers/pci/host/pcie-designware.c |   12 ++++++++++--
>>   drivers/pci/host/pcie-designware.h |    4 ++++
>>   2 files changed, 14 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-
>> designware.c
>> index 1eaf4df..d8f3af7 100644
>> --- a/drivers/pci/host/pcie-designware.c
>> +++ b/drivers/pci/host/pcie-designware.c
>> @@ -656,7 +656,11 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32
>> devfn, int where,
>>   	}
>>
>>   	if (bus->number != pp->root_bus_nr)
>> -		ret = dw_pcie_rd_other_conf(pp, bus, devfn,
>> +		if (pp->ops->rd_other_conf)
>> +			ret = pp->ops->rd_other_conf(pp, bus, devfn,
>> +						where, size, val);
>> +		else
>> +			ret = dw_pcie_rd_other_conf(pp, bus, devfn,
>>   						where, size, val);
>>   	else
>>   		ret = dw_pcie_rd_own_conf(pp, where, size, val); @@ -
>> 679,7 +683,11 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32
>> devfn,
>>   		return PCIBIOS_DEVICE_NOT_FOUND;
>>
>>   	if (bus->number != pp->root_bus_nr)
>> -		ret = dw_pcie_wr_other_conf(pp, bus, devfn,
>> +		if (pp->ops->wr_other_conf)
>> +			ret = pp->ops->wr_other_conf(pp, bus, devfn,
>> +						where, size, val);
>> +		else
>> +			ret = dw_pcie_wr_other_conf(pp, bus, devfn,
>>   						where, size, val);
>>   	else
>>   		ret = dw_pcie_wr_own_conf(pp, where, size, val); diff --git
>> a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
>> index 77f592f..8121901 100644
>> --- a/drivers/pci/host/pcie-designware.h
>> +++ b/drivers/pci/host/pcie-designware.h
>> @@ -61,6 +61,10 @@ struct pcie_host_ops {
>>   			u32 val, void __iomem *dbi_base);
>>   	int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32
>> *val);
>>   	int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32
>> val);
>> +	int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
>> +			unsigned int devfn, int where, int size, u32 *val);
>> +	int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
>> +			unsigned int devfn, int where, int size, u32 val);
>>   	int (*link_up)(struct pcie_port *pp);
>>   	void (*host_init)(struct pcie_port *pp);  };
>
> - Now it looks good to me.
>
> Acked-by: Mohit Kumar<mohit.kumar@st.com>
>
> Regards
> Mohit
>> --
>> 1.7.9.5
>
Mohit,

Thanks.

Jingoo, could you provide your response or Ack?

Thanks
Murali

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

* Re: [PATCH v3 1/5] PCI: designware: add rd[wr]_other_conf API
  2014-07-07 16:53     ` Murali Karicheri
@ 2014-07-08 12:17       ` Jingoo Han
  0 siblings, 0 replies; 33+ messages in thread
From: Jingoo Han @ 2014-07-08 12:17 UTC (permalink / raw)
  To: 'Murali Karicheri', 'Mohit KUMAR DCG'
  Cc: linux-pci, linux-kernel, devicetree, 'Santosh Shilimkar',
	'Russell King', 'Grant Likely',
	'Rob Herring', 'Bjorn Helgaas',
	'Pratyush ANAND', 'Richard Zhu',
	'Kishon Vijay Abraham I', 'Marek Vasut',
	'Arnd Bergmann', 'Pawel Moll',
	'Mark Rutland', 'Ian Campbell',
	'Kumar Gala', 'Randy Dunlap',
	'Jingoo Han'

On Tuesday, July 08, 2014 1:54 AM, Murali Karicheri wrote:
> On 07/07/2014 12:11 AM, Mohit KUMAR DCG wrote:
> > On Tuesday, July 01, 2014 3:15 AM, Murali Karicheri wrote:
> >>
> >> v3.65 version of the designware h/w, requires application space registers to
> >> be configured to access the remote EP config space.
> >> To support this, add rd[wr]_other_conf API in the pcie_host_opts
> >>
> >> Signed-off-by: Murali Karicheri<m-karicheri2@ti.com>
> >>
> >> CC: Santosh Shilimkar<santosh.shilimkar@ti.com>
> >> CC: Russell King<linux@arm.linux.org.uk>
> >> CC: Grant Likely<grant.likely@linaro.org>
> >> CC: Rob Herring<robh+dt@kernel.org>
> >> CC: Mohit Kumar<mohit.kumar@st.com>
> >> CC: Jingoo Han<jg1.han@samsung.com>
> >> CC: Bjorn Helgaas<bhelgaas@google.com>
> >> CC: Pratyush Anand<pratyush.anand@st.com>
> >> CC: Richard Zhu<r65037@freescale.com>
> >> CC: Kishon Vijay Abraham I<kishon@ti.com>
> >> CC: Marek Vasut<marex@denx.de>
> >> CC: Arnd Bergmann<arnd@arndb.de>
> >> CC: Pawel Moll<pawel.moll@arm.com>
> >> CC: Mark Rutland<mark.rutland@arm.com>
> >> CC: Ian Campbell<ijc+devicetree@hellion.org.uk>
> >> CC: Kumar Gala<galak@codeaurora.org>
> >> CC: Randy Dunlap<rdunlap@infradead.org>
> >> CC: Grant Likely<grant.likely@linaro.org>
> >> ---
> >>   drivers/pci/host/pcie-designware.c |   12 ++++++++++--
> >>   drivers/pci/host/pcie-designware.h |    4 ++++
> >>   2 files changed, 14 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-
> >> designware.c
> >> index 1eaf4df..d8f3af7 100644
> >> --- a/drivers/pci/host/pcie-designware.c
> >> +++ b/drivers/pci/host/pcie-designware.c
> >> @@ -656,7 +656,11 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32
> >> devfn, int where,
> >>   	}
> >>
> >>   	if (bus->number != pp->root_bus_nr)
> >> -		ret = dw_pcie_rd_other_conf(pp, bus, devfn,
> >> +		if (pp->ops->rd_other_conf)
> >> +			ret = pp->ops->rd_other_conf(pp, bus, devfn,
> >> +						where, size, val);
> >> +		else
> >> +			ret = dw_pcie_rd_other_conf(pp, bus, devfn,
> >>   						where, size, val);
> >>   	else
> >>   		ret = dw_pcie_rd_own_conf(pp, where, size, val); @@ -
> >> 679,7 +683,11 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32
> >> devfn,
> >>   		return PCIBIOS_DEVICE_NOT_FOUND;
> >>
> >>   	if (bus->number != pp->root_bus_nr)
> >> -		ret = dw_pcie_wr_other_conf(pp, bus, devfn,
> >> +		if (pp->ops->wr_other_conf)
> >> +			ret = pp->ops->wr_other_conf(pp, bus, devfn,
> >> +						where, size, val);
> >> +		else
> >> +			ret = dw_pcie_wr_other_conf(pp, bus, devfn,
> >>   						where, size, val);
> >>   	else
> >>   		ret = dw_pcie_wr_own_conf(pp, where, size, val); diff --git
> >> a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
> >> index 77f592f..8121901 100644
> >> --- a/drivers/pci/host/pcie-designware.h
> >> +++ b/drivers/pci/host/pcie-designware.h
> >> @@ -61,6 +61,10 @@ struct pcie_host_ops {
> >>   			u32 val, void __iomem *dbi_base);
> >>   	int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32
> >> *val);
> >>   	int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32
> >> val);
> >> +	int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
> >> +			unsigned int devfn, int where, int size, u32 *val);
> >> +	int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
> >> +			unsigned int devfn, int where, int size, u32 val);
> >>   	int (*link_up)(struct pcie_port *pp);
> >>   	void (*host_init)(struct pcie_port *pp);  };
> >
> > - Now it looks good to me.
> >
> > Acked-by: Mohit Kumar<mohit.kumar@st.com>
> >
> > Regards
> > Mohit
> >> --
> >> 1.7.9.5
> >
> Mohit,
> 
> Thanks.
> 
> Jingoo, could you provide your response or Ack?

Acked-by: Jingoo Han <jg1.han@samsung.com>

Best regards,
Jingoo Han

> 
> Thanks
> Murali
> --


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

* Re: [PATCH v3 2/5] PCI: designware: refactor MSI code to work with v3.65 dw hardware
  2014-07-07 16:53     ` Murali Karicheri
@ 2014-07-08 12:20       ` Jingoo Han
  0 siblings, 0 replies; 33+ messages in thread
From: Jingoo Han @ 2014-07-08 12:20 UTC (permalink / raw)
  To: 'Murali Karicheri', 'Mohit KUMAR DCG'
  Cc: linux-pci, linux-kernel, devicetree, 'Santosh Shilimkar',
	'Russell King', 'Grant Likely',
	'Rob Herring', 'Bjorn Helgaas',
	'Pratyush ANAND', 'Richard Zhu',
	'Kishon Vijay Abraham I', 'Marek Vasut',
	'Arnd Bergmann', 'Pawel Moll',
	'Mark Rutland', 'Ian Campbell',
	'Kumar Gala', 'Randy Dunlap',
	'Jingoo Han'

On Tuesday, July 08, 2014 1:53 AM, Murali Karicheri wrote:
> On 07/07/2014 12:17 AM, Mohit KUMAR DCG wrote:
> > On Tuesday, July 01, 2014 3:15 AM, Murali Karicheri wrote:
> >>
> >> Keystone PCI controller is based on v3.65 version of the DW PCI h/w that
> >> implements MSI controller registers in application space compared to the
> >> newer version. This requires updates to the DW core API to support the PCI
> >> controller driver based on this old DW hardware. Add msi_irq_set()/clear()
> >> API functions to allow Set/Clear MSI IRQ enable bit in the application register.
> >> Also the old h/w uses MSI_IRQ register in application register space to raise
> >> MSI IRQ to the RC from EP. Current code uses the standard mechanism as
> >> per PCI spec. So add another API get_msi_data() to get the address of this
> >> register so that common code can be re-used on old h/w.
> >>
> >> Signed-off-by: Murali Karicheri<m-karicheri2@ti.com>
> >>
> >> CC: Santosh Shilimkar<santosh.shilimkar@ti.com>
> >> CC: Russell King<linux@arm.linux.org.uk>
> >> CC: Grant Likely<grant.likely@linaro.org>
> >> CC: Rob Herring<robh+dt@kernel.org>
> >> CC: Mohit Kumar<mohit.kumar@st.com>
> >> CC: Jingoo Han<jg1.han@samsung.com>
> >> CC: Bjorn Helgaas<bhelgaas@google.com>
> >> CC: Pratyush Anand<pratyush.anand@st.com>
> >> CC: Richard Zhu<r65037@freescale.com>
> >> CC: Kishon Vijay Abraham I<kishon@ti.com>
> >> CC: Marek Vasut<marex@denx.de>
> >> CC: Arnd Bergmann<arnd@arndb.de>
> >> CC: Pawel Moll<pawel.moll@arm.com>
> >> CC: Mark Rutland<mark.rutland@arm.com>
> >> CC: Ian Campbell<ijc+devicetree@hellion.org.uk>
> >> CC: Kumar Gala<galak@codeaurora.org>
> >> CC: Randy Dunlap<rdunlap@infradead.org>
> >> CC: Grant Likely<grant.likely@linaro.org>
> >> ---
> >>   drivers/pci/host/pcie-designware.c |   50 ++++++++++++++++++++++++++-
> >> ---------
> >>   drivers/pci/host/pcie-designware.h |    3 +++
> >>   2 files changed, 39 insertions(+), 14 deletions(-)
> >>
> >> diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-
> >> designware.c
> >> index d8f3af7..905941c 100644
> >> --- a/drivers/pci/host/pcie-designware.c
> >> +++ b/drivers/pci/host/pcie-designware.c
> >> @@ -217,27 +217,47 @@ static int find_valid_pos0(struct pcie_port *pp, int
> >> msgvec, int pos, int *pos0)
> >>   	return 0;
> >>   }
> >>
> >> +static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq) {
> >> +	unsigned int res, bit, val;
> >> +
> >> +	res = (irq / 32) * 12;
> >> +	bit = irq % 32;
> >> +	dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,&val);
> >> +	val&= ~(1<<  bit);
> >> +	dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val); }
> >> +
> >>   static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
> >>   			    unsigned int nvec, unsigned int pos)  {
> >> -	unsigned int i, res, bit, val;
> >> +	unsigned int i;
> >>
> >>   	for (i = 0; i<  nvec; i++) {
> >>   		irq_set_msi_desc_off(irq_base, i, NULL);
> >>   		clear_bit(pos + i, pp->msi_irq_in_use);
> >>   		/* Disable corresponding interrupt on MSI controller */
> >> -		res = ((pos + i) / 32) * 12;
> >> -		bit = (pos + i) % 32;
> >> -		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
> >> 4,&val);
> >> -		val&= ~(1<<  bit);
> >> -		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
> >> 4, val);
> >> +		if (pp->ops->msi_clear_irq)
> >> +			pp->ops->msi_clear_irq(pp, pos + i);
> >> +		else
> >> +			dw_pcie_msi_clear_irq(pp, pos + i);
> >>   	}
> >>   }
> >>
> >> +static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq) {
> >> +	unsigned int res, bit, val;
> >> +
> >> +	res = (irq / 32) * 12;
> >> +	bit = irq % 32;
> >> +	dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,&val);
> >> +	val |= 1<<  bit;
> >> +	dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val); }
> >> +
> >>   static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)  {
> >> -	int res, bit, irq, pos0, pos1, i;
> >> -	u32 val;
> >> +	int irq, pos0, pos1, i;
> >>   	struct pcie_port *pp = sys_to_pcie(desc->dev->bus->sysdata);
> >>
> >>   	if (!pp) {
> >> @@ -281,11 +301,10 @@ static int assign_irq(int no_irqs, struct msi_desc
> >> *desc, int *pos)
> >>   		}
> >>   		set_bit(pos0 + i, pp->msi_irq_in_use);
> >>   		/*Enable corresponding interrupt in MSI interrupt controller
> >> */
> >> -		res = ((pos0 + i) / 32) * 12;
> >> -		bit = (pos0 + i) % 32;
> >> -		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
> >> 4,&val);
> >> -		val |= 1<<  bit;
> >> -		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res,
> >> 4, val);
> >> +		if (pp->ops->msi_set_irq)
> >> +			pp->ops->msi_set_irq(pp, pos0 + i);
> >> +		else
> >> +			dw_pcie_msi_set_irq(pp, pos0 + i);
> >>   	}
> >>
> >>   	*pos = pos0;
> >> @@ -353,7 +372,10 @@ static int dw_msi_setup_irq(struct msi_chip *chip,
> >> struct pci_dev *pdev,
> >>   	 */
> >>   	desc->msi_attrib.multiple = msgvec;
> >>
> >> -	msg.address_lo = virt_to_phys((void *)pp->msi_data);
> >> +	if (pp->ops->get_msi_data)
> >> +		msg.address_lo = pp->ops->get_msi_data(pp);
> >> +	else
> >> +		msg.address_lo = virt_to_phys((void *)pp->msi_data);
> >>   	msg.address_hi = 0x0;
> >>   	msg.data = pos;
> >>   	write_msi_msg(irq,&msg);
> >> diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-
> >> designware.h
> >> index 8121901..387f69e 100644
> >> --- a/drivers/pci/host/pcie-designware.h
> >> +++ b/drivers/pci/host/pcie-designware.h
> >> @@ -67,6 +67,9 @@ struct pcie_host_ops {
> >>   			unsigned int devfn, int where, int size, u32 val);
> >>   	int (*link_up)(struct pcie_port *pp);
> >>   	void (*host_init)(struct pcie_port *pp);
> >> +	void (*msi_set_irq)(struct pcie_port *pp, int irq);
> >> +	void (*msi_clear_irq)(struct pcie_port *pp, int irq);
> >> +	u32 (*get_msi_data)(struct pcie_port *pp);
> >>   };
> >>
> >>   int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val);
> >
> > - Now MSI specific dw code can be shared b/w old Synopsys controller (ver<  3.70)
> > and newer controller that standardize the MSI settings inside design ware core itself.
> >
> > Jingoo,
> >
> > Pls let us know if you have any concern or comment over this.
> >
> > Acked-by: Mohit Kumar<mohit.kumar@st.com>
> >
> > Regards
> > Mohit
> >
> >> --
> >> 1.7.9.5
> >
> Mohit,
> 
> Thanks.
> 
> Jingoo, could you provide your response or Ack?

Acked-by: Jingoo Han <jg1.han@samsung.com>

Best regards,
Jingoo Han

> 
> Thanks
> --


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

* Re: [PATCH v3 5/5] PCI: add PCI controller for Keystone PCIe h/w
  2014-06-30 21:45   ` Murali Karicheri
  (?)
  (?)
@ 2014-07-08 12:43   ` Jingoo Han
  -1 siblings, 0 replies; 33+ messages in thread
From: Jingoo Han @ 2014-07-08 12:43 UTC (permalink / raw)
  To: 'Murali Karicheri', linux-pci, linux-kernel, devicetree
  Cc: 'Santosh Shilimkar', 'Russell King',
	'Grant Likely', 'Rob Herring',
	'Mohit Kumar', 'Bjorn Helgaas',
	'Pratyush Anand', 'Richard Zhu',
	'Kishon Vijay Abraham I', 'Marek Vasut',
	'Arnd Bergmann', 'Pawel Moll',
	'Mark Rutland', 'Ian Campbell',
	'Kumar Gala', 'Randy Dunlap',
	'Jingoo Han'

On Tuesday, July 01, 2014 6:45 AM, Murali Karicheri wrote:
> 
> Keystone PCIe controller is based on v3.65 version of the
> designware h/w. Main differences are
> 	1. No ATU support
> 	2. Legacy and MSI irq functions are implemented in
> 	   application register space
> 	3. MSI interrupts are multiplexed over 8 IRQ lines to the Host
> 	   side.
> All of the Application register space handing code are organized into
> pci-keystone-dw.c and the functions are called from pci-keystone.c
> to implement PCI controller driver. Also add necessary DT documentation
> for the driver.
> 
> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
> 
> CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
> CC: Russell King <linux@arm.linux.org.uk>
> CC: Grant Likely <grant.likely@linaro.org>
> CC: Rob Herring <robh+dt@kernel.org>
> CC: Mohit Kumar <mohit.kumar@st.com>
> CC: Jingoo Han <jg1.han@samsung.com>
> CC: Bjorn Helgaas <bhelgaas@google.com>
> CC: Pratyush Anand <pratyush.anand@st.com>
> CC: Richard Zhu <r65037@freescale.com>
> CC: Kishon Vijay Abraham I <kishon@ti.com>
> CC: Marek Vasut <marex@denx.de>
> CC: Arnd Bergmann <arnd@arndb.de>
> CC: Pawel Moll <pawel.moll@arm.com>
> CC: Mark Rutland <mark.rutland@arm.com>
> CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
> CC: Kumar Gala <galak@codeaurora.org>
> CC: Randy Dunlap <rdunlap@infradead.org>
> CC: Grant Likely <grant.likely@linaro.org>
> ---
>  .../devicetree/bindings/pci/pci-keystone.txt       |   69 +++
>  drivers/pci/host/Kconfig                           |    5 +
>  drivers/pci/host/Makefile                          |    1 +
>  drivers/pci/host/pci-keystone-dw.c                 |  523 ++++++++++++++++++++
>  drivers/pci/host/pci-keystone.c                    |  381 ++++++++++++++
>  drivers/pci/host/pci-keystone.h                    |   56 +++
>  6 files changed, 1035 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/pci/pci-keystone.txt
>  create mode 100644 drivers/pci/host/pci-keystone-dw.c
>  create mode 100644 drivers/pci/host/pci-keystone.c
>  create mode 100644 drivers/pci/host/pci-keystone.h
> 

[.....]

> +
> +static int __init ks_pcie_probe(struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	struct device *dev = &pdev->dev;
> +	struct keystone_pcie *ks_pcie;
> +	struct pcie_port *pp;
> +	struct resource *res;
> +	void __iomem *reg_p;
> +	struct phy *phy;
> +	int ret = 0;
> +	u32 val;
> +
> +	ks_pcie = devm_kzalloc(&pdev->dev, sizeof(*ks_pcie),
> +				GFP_KERNEL);
> +	if (!ks_pcie) {
> +		dev_err(dev, "no memory for keystone pcie\n");
> +		return -ENOMEM;
> +	}
> +	pp = &ks_pcie->pp;
> +
> +	/* initialize SerDes Phy if present */
> +	phy = devm_phy_get(dev, "pcie-phy");
> +	if (phy)
> +		ret = phy_init(phy);

Why don't you check 'ret' value?
How about the following?

+	/* initialize SerDes Phy if present */
+	phy = devm_phy_get(dev, "pcie-phy");
+	if (!IS_ERR_OR_NULL(phy) {
+		ret = phy_init(phy);
+		if (ret <0)
+			return ret;
+	}


Best regards,
Jingoo Han

[....]



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

* Re: [PATCH v3 0/5] Add Keystone PCIe controller driver
@ 2014-07-08 12:49     ` Murali Karicheri
  0 siblings, 0 replies; 33+ messages in thread
From: Murali Karicheri @ 2014-07-08 12:49 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: linux-pci, linux-kernel, devicetree, Santosh Shilimkar,
	Russell King, Grant Likely, Rob Herring, Mohit Kumar, Jingoo Han,
	Pratyush Anand, Richard Zhu, Kishon Vijay Abraham I, Marek Vasut,
	Arnd Bergmann, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Randy Dunlap

On 07/05/2014 02:23 PM, Bjorn Helgaas wrote:
> On Mon, Jun 30, 2014 at 05:45:15PM -0400, Murali Karicheri wrote:
>> This patch add PCIe controller driver for Keystone SoCs. This
>> is based on v2 of the series posted to the mailing list.
>> Keystone PCI controller is based on version 3.65 of the DW
>> hardware. This driver re-uses some of the DW core driver
>> functions and required modification in some to support
>> the old DW h/w based Keystone driver.
>>
>> Please review and let me know if you have any comments.
>
> I'm waiting for acks from Mohit or Jingoo for the designware changes.
>
Bjorn,

Thanks for your email.

So far I got Ack for 1/5 and 2/5. I will ping them today for 3/5 and 4/5.

> I'd also like an ack from the devicetree folks for the Keystone binding.
>
Ok
> And I think we need a MAINTAINERS update for drivers/pci/host/\*keystone\*
I will address your comments against 5/5 and discuss them if any and 
make the above update for v4 and send the patch set to the list.

Thanks and regards,

Murali
>
>> CC: Santosh Shilimkar<santosh.shilimkar@ti.com>
>> CC: Russell King<linux@arm.linux.org.uk>
>> CC: Grant Likely<grant.likely@linaro.org>
>> CC: Rob Herring<robh+dt@kernel.org>
>> CC: Mohit Kumar<mohit.kumar@st.com>
>> CC: Jingoo Han<jg1.han@samsung.com>
>> CC: Bjorn Helgaas<bhelgaas@google.com>
>> CC: Pratyush Anand<pratyush.anand@st.com>
>> CC: Richard Zhu<r65037@freescale.com>
>> CC: Kishon Vijay Abraham I<kishon@ti.com>
>> CC: Marek Vasut<marex@denx.de>
>> CC: Arnd Bergmann<arnd@arndb.de>
>> CC: Pawel Moll<pawel.moll@arm.com>
>> CC: Mark Rutland<mark.rutland@arm.com>
>> CC: Ian Campbell<ijc+devicetree@hellion.org.uk>
>> CC: Kumar Gala<galak@codeaurora.org>
>> CC: Randy Dunlap<rdunlap@infradead.org>
>> CC: Grant Likely<grant.likely@linaro.org>
>>
>> Changelog:
>>
>> v3
>>   - DW application register handling code is now part of
>>     Keystone PCI driver. RFC had this code part of Keystone
>>     PCI driver, then V1 moved this to a separate file to
>>     re-use on other platforms that uses this version of the
>>     DW h/w. Then based on comments against v2, this is moved
>>     back to Keystone driver.
>>   - Keystone SerDes phy driver is removed from this series so that
>>     this can be merged independent of that patch
>>   - added msi_set_irq()/clear_irq() API's to support Keystone
>>
>> V2
>>   - Split the designware pcie enhancement patch to multiple
>>     patches based on functionality added
>>   - Remove the quirk code and add a patch to fix mps/mrss
>>     tuning for ARM. Use kernel command line parameter
>>     pci=pcie_bus_perf to work with Keystone PCI Controller.
>>     Following patch addressed this.
>>       [PATCH v1] ARM: pci: add call to pcie_bus_configure_settings()
>>   - Add documentation for device tree bindings
>>   - Add separate interrupt controller nodes for MSI and Legacy
>>     IRQs and use irq map for legacy IRQ
>>   - Use compatibility to identify v3.65 version of the DW hardware
>>     and use it to customize the designware common code.
>>   - Use reg property for configuration space instead of range
>>   - Other minor updates based on code inspection.
>>
>> V1
>>   - Add an interrupt controller node for Legacy irq chip and use
>>     interrupt map/map-mask property to map legacy IRQs A/B/C/D
>>   - Add a Phy driver to replace the original serdes driver
>>   - Move common application register handling code to a separate
>>     file to allow re-use across other platforms that use older
>>     DW PCIe h/w
>>   - PCI quirk for maximum read request size. Check and override only
>>     if the maximum is higher than what controller can handle.
>>   - Converted to a module platform driver.
>>
>> Murali Karicheri (5):
>>    PCI: designware: add rd[wr]_other_conf API
>>    PCI: designware: refactor MSI code to work with v3.65 dw hardware
>>    PCI: designware: refactor host init code to re-use on keystone PCI
>>    PCI: designware: enhance dw core driver to support Keystone PCI host
>>      controller
>>    PCI: add PCI controller for Keystone PCIe h/w
>>
>>   .../devicetree/bindings/pci/designware-pcie.txt    |    2 +
>>   .../devicetree/bindings/pci/pci-keystone.txt       |   69 +++
>>   drivers/pci/host/Kconfig                           |    5 +
>>   drivers/pci/host/Makefile                          |    1 +
>>   drivers/pci/host/pci-keystone-dw.c                 |  523 ++++++++++++++++++++
>>   drivers/pci/host/pci-keystone.c                    |  381 ++++++++++++++
>>   drivers/pci/host/pci-keystone.h                    |   56 +++
>>   drivers/pci/host/pcie-designware.c                 |  206 ++++++--
>>   drivers/pci/host/pcie-designware.h                 |   17 +-
>>   9 files changed, 1207 insertions(+), 53 deletions(-)
>>   create mode 100644 Documentation/devicetree/bindings/pci/pci-keystone.txt
>>   create mode 100644 drivers/pci/host/pci-keystone-dw.c
>>   create mode 100644 drivers/pci/host/pci-keystone.c
>>   create mode 100644 drivers/pci/host/pci-keystone.h
>>
>> --
>> 1.7.9.5
>>


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

* Re: [PATCH v3 0/5] Add Keystone PCIe controller driver
@ 2014-07-08 12:49     ` Murali Karicheri
  0 siblings, 0 replies; 33+ messages in thread
From: Murali Karicheri @ 2014-07-08 12:49 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: linux-pci-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Santosh Shilimkar,
	Russell King, Grant Likely, Rob Herring, Mohit Kumar, Jingoo Han,
	Pratyush Anand, Richard Zhu, Kishon Vijay Abraham I, Marek Vasut,
	Arnd Bergmann, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Randy Dunlap

On 07/05/2014 02:23 PM, Bjorn Helgaas wrote:
> On Mon, Jun 30, 2014 at 05:45:15PM -0400, Murali Karicheri wrote:
>> This patch add PCIe controller driver for Keystone SoCs. This
>> is based on v2 of the series posted to the mailing list.
>> Keystone PCI controller is based on version 3.65 of the DW
>> hardware. This driver re-uses some of the DW core driver
>> functions and required modification in some to support
>> the old DW h/w based Keystone driver.
>>
>> Please review and let me know if you have any comments.
>
> I'm waiting for acks from Mohit or Jingoo for the designware changes.
>
Bjorn,

Thanks for your email.

So far I got Ack for 1/5 and 2/5. I will ping them today for 3/5 and 4/5.

> I'd also like an ack from the devicetree folks for the Keystone binding.
>
Ok
> And I think we need a MAINTAINERS update for drivers/pci/host/\*keystone\*
I will address your comments against 5/5 and discuss them if any and 
make the above update for v4 and send the patch set to the list.

Thanks and regards,

Murali
>
>> CC: Santosh Shilimkar<santosh.shilimkar-l0cyMroinI0@public.gmane.org>
>> CC: Russell King<linux-lFZ/pmaqli7XmaaqVzeoHQ@public.gmane.org>
>> CC: Grant Likely<grant.likely-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
>> CC: Rob Herring<robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>> CC: Mohit Kumar<mohit.kumar-qxv4g6HH51o@public.gmane.org>
>> CC: Jingoo Han<jg1.han-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> CC: Bjorn Helgaas<bhelgaas-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
>> CC: Pratyush Anand<pratyush.anand-qxv4g6HH51o@public.gmane.org>
>> CC: Richard Zhu<r65037-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
>> CC: Kishon Vijay Abraham I<kishon-l0cyMroinI0@public.gmane.org>
>> CC: Marek Vasut<marex-ynQEQJNshbs@public.gmane.org>
>> CC: Arnd Bergmann<arnd-r2nGTMty4D4@public.gmane.org>
>> CC: Pawel Moll<pawel.moll-5wv7dgnIgG8@public.gmane.org>
>> CC: Mark Rutland<mark.rutland-5wv7dgnIgG8@public.gmane.org>
>> CC: Ian Campbell<ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg@public.gmane.org>
>> CC: Kumar Gala<galak-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
>> CC: Randy Dunlap<rdunlap-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>
>> CC: Grant Likely<grant.likely-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
>>
>> Changelog:
>>
>> v3
>>   - DW application register handling code is now part of
>>     Keystone PCI driver. RFC had this code part of Keystone
>>     PCI driver, then V1 moved this to a separate file to
>>     re-use on other platforms that uses this version of the
>>     DW h/w. Then based on comments against v2, this is moved
>>     back to Keystone driver.
>>   - Keystone SerDes phy driver is removed from this series so that
>>     this can be merged independent of that patch
>>   - added msi_set_irq()/clear_irq() API's to support Keystone
>>
>> V2
>>   - Split the designware pcie enhancement patch to multiple
>>     patches based on functionality added
>>   - Remove the quirk code and add a patch to fix mps/mrss
>>     tuning for ARM. Use kernel command line parameter
>>     pci=pcie_bus_perf to work with Keystone PCI Controller.
>>     Following patch addressed this.
>>       [PATCH v1] ARM: pci: add call to pcie_bus_configure_settings()
>>   - Add documentation for device tree bindings
>>   - Add separate interrupt controller nodes for MSI and Legacy
>>     IRQs and use irq map for legacy IRQ
>>   - Use compatibility to identify v3.65 version of the DW hardware
>>     and use it to customize the designware common code.
>>   - Use reg property for configuration space instead of range
>>   - Other minor updates based on code inspection.
>>
>> V1
>>   - Add an interrupt controller node for Legacy irq chip and use
>>     interrupt map/map-mask property to map legacy IRQs A/B/C/D
>>   - Add a Phy driver to replace the original serdes driver
>>   - Move common application register handling code to a separate
>>     file to allow re-use across other platforms that use older
>>     DW PCIe h/w
>>   - PCI quirk for maximum read request size. Check and override only
>>     if the maximum is higher than what controller can handle.
>>   - Converted to a module platform driver.
>>
>> Murali Karicheri (5):
>>    PCI: designware: add rd[wr]_other_conf API
>>    PCI: designware: refactor MSI code to work with v3.65 dw hardware
>>    PCI: designware: refactor host init code to re-use on keystone PCI
>>    PCI: designware: enhance dw core driver to support Keystone PCI host
>>      controller
>>    PCI: add PCI controller for Keystone PCIe h/w
>>
>>   .../devicetree/bindings/pci/designware-pcie.txt    |    2 +
>>   .../devicetree/bindings/pci/pci-keystone.txt       |   69 +++
>>   drivers/pci/host/Kconfig                           |    5 +
>>   drivers/pci/host/Makefile                          |    1 +
>>   drivers/pci/host/pci-keystone-dw.c                 |  523 ++++++++++++++++++++
>>   drivers/pci/host/pci-keystone.c                    |  381 ++++++++++++++
>>   drivers/pci/host/pci-keystone.h                    |   56 +++
>>   drivers/pci/host/pcie-designware.c                 |  206 ++++++--
>>   drivers/pci/host/pcie-designware.h                 |   17 +-
>>   9 files changed, 1207 insertions(+), 53 deletions(-)
>>   create mode 100644 Documentation/devicetree/bindings/pci/pci-keystone.txt
>>   create mode 100644 drivers/pci/host/pci-keystone-dw.c
>>   create mode 100644 drivers/pci/host/pci-keystone.c
>>   create mode 100644 drivers/pci/host/pci-keystone.h
>>
>> --
>> 1.7.9.5
>>

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v3 3/5] PCI: designware: refactor host init code to re-use on keystone PCI
  2014-06-30 21:45   ` Murali Karicheri
@ 2014-07-08 13:20     ` Murali Karicheri
  -1 siblings, 0 replies; 33+ messages in thread
From: Murali Karicheri @ 2014-07-08 13:20 UTC (permalink / raw)
  To: Murali Karicheri, Mohit Kumar, Jingoo Han
  Cc: linux-pci, linux-kernel, devicetree, Santosh Shilimkar,
	Russell King, Grant Likely, Rob Herring, Bjorn Helgaas,
	Pratyush Anand, Richard Zhu, Kishon Vijay Abraham I, Marek Vasut,
	Arnd Bergmann, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Randy Dunlap

Mohit, Jingoo,

Thanks for the Ack for 1/5 and 2/5 of this series.

Could you also review 3/5 and 4/5 of this series and provide your Ack or 
comments at the earliest.

Thanks and regards,

Murali

On 06/30/2014 05:45 PM, Murali Karicheri wrote:
> This patch refactor the host controller init code to support Keystone
> PCI controller.
>
> Current DW PCI host controller init code has code specific to newer
> DW hw such as ATU port resource parse and ioremap. Conditionally
> execute this code if DW h/w is not v3.65. Keystone PCI controller
> is based on v3.65 DW PCI h/w and it has MSI controller implemented
> in application space and requires different controller initialization
> code. So factor out the MSI host init code to a separate function.
>
> Rename dw_pcie_host_init() to dw_pcie_common_host_init() that takes an
> additional arg, ptr to hw_pci structure. This allows to re-use the code
> for Keystone PCI that can now provide it's own pci hw ops and msi irq
> ops.  dw_pcie_host_init() is now a wrapper function that calls
> dw_pcie_common_host_init() for pci common initialization.
>
> Signed-off-by: Murali Karicheri<m-karicheri2@ti.com>
>
> CC: Santosh Shilimkar<santosh.shilimkar@ti.com>
> CC: Russell King<linux@arm.linux.org.uk>
> CC: Grant Likely<grant.likely@linaro.org>
> CC: Rob Herring<robh+dt@kernel.org>
> CC: Mohit Kumar<mohit.kumar@st.com>
> CC: Jingoo Han<jg1.han@samsung.com>
> CC: Bjorn Helgaas<bhelgaas@google.com>
> CC: Pratyush Anand<pratyush.anand@st.com>
> CC: Richard Zhu<r65037@freescale.com>
> CC: Kishon Vijay Abraham I<kishon@ti.com>
> CC: Marek Vasut<marex@denx.de>
> CC: Arnd Bergmann<arnd@arndb.de>
> CC: Pawel Moll<pawel.moll@arm.com>
> CC: Mark Rutland<mark.rutland@arm.com>
> CC: Ian Campbell<ijc+devicetree@hellion.org.uk>
> CC: Kumar Gala<galak@codeaurora.org>
> CC: Randy Dunlap<rdunlap@infradead.org>
> CC: Grant Likely<grant.likely@linaro.org>
> ---
>   drivers/pci/host/pcie-designware.c |  105 +++++++++++++++++++++++++-----------
>   drivers/pci/host/pcie-designware.h |    3 +-
>   2 files changed, 75 insertions(+), 33 deletions(-)
>
> diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
> index 905941c..c11e4de 100644
> --- a/drivers/pci/host/pcie-designware.c
> +++ b/drivers/pci/host/pcie-designware.c
> @@ -415,19 +415,24 @@ static const struct irq_domain_ops msi_domain_ops = {
>   	.map = dw_pcie_msi_map,
>   };
>
> -int __init dw_pcie_host_init(struct pcie_port *pp)
> +static int __init dw_pcie_common_host_init(struct pcie_port *pp,
> +					   struct hw_pci *hw)
>   {
>   	struct device_node *np = pp->dev->of_node;
>   	struct of_pci_range range;
>   	struct of_pci_range_parser parser;
> +	struct hw_pci *pci_hw = hw;
>   	u32 val;
> -	int i;
>
>   	if (of_pci_range_parser_init(&parser, np)) {
>   		dev_err(pp->dev, "missing ranges property\n");
>   		return -EINVAL;
>   	}
>
> +	/* Default to dw_pci if no hw ops provided */
> +	if (!pci_hw)
> +		pci_hw =&dw_pci;
> +
>   	/* Get the I/O and memory ranges from DT */
>   	for_each_of_pci_range(&parser,&range) {
>   		unsigned long restype = range.flags&  IORESOURCE_TYPE_BITS;
> @@ -467,21 +472,24 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
>   		}
>   	}
>
> -	pp->cfg0_base = pp->cfg.start;
> -	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
>   	pp->mem_base = pp->mem.start;
> -
> -	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
> -					pp->config.cfg0_size);
> -	if (!pp->va_cfg0_base) {
> -		dev_err(pp->dev, "error with ioremap in function\n");
> -		return -ENOMEM;
> -	}
> -	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
> -					pp->config.cfg1_size);
> -	if (!pp->va_cfg1_base) {
> -		dev_err(pp->dev, "error with ioremap\n");
> -		return -ENOMEM;
> +	if (!pp->version&  DW_HW_V3_65) {
> +		/* Default is with ATU port. */
> +		pp->cfg0_base = pp->cfg.start;
> +		pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
> +
> +		pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
> +						pp->config.cfg0_size);
> +		if (!pp->va_cfg0_base) {
> +			dev_err(pp->dev, "error with ioremap in function\n");
> +			return -ENOMEM;
> +		}
> +		pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
> +						pp->config.cfg1_size);
> +		if (!pp->va_cfg1_base) {
> +			dev_err(pp->dev, "error with ioremap\n");
> +			return -ENOMEM;
> +		}
>   	}
>
>   	if (of_property_read_u32(np, "num-lanes",&pp->lanes)) {
> @@ -489,19 +497,6 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
>   		return -EINVAL;
>   	}
>
> -	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> -		pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
> -					MAX_MSI_IRQS,&msi_domain_ops,
> -					&dw_pcie_msi_chip);
> -		if (!pp->irq_domain) {
> -			dev_err(pp->dev, "irq domain init failed\n");
> -			return -ENXIO;
> -		}
> -
> -		for (i = 0; i<  MAX_MSI_IRQS; i++)
> -			irq_create_mapping(pp->irq_domain, i);
> -	}
> -
>   	if (pp->ops->host_init)
>   		pp->ops->host_init(pp);
>
> @@ -514,10 +509,10 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
>   	val |= PORT_LOGIC_SPEED_CHANGE;
>   	dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
>
> -	dw_pci.nr_controllers = 1;
> -	dw_pci.private_data = (void **)&pp;
> +	pci_hw->nr_controllers = 1;
> +	pci_hw->private_data = (void **)&pp;
>
> -	pci_common_init_dev(pp->dev,&dw_pci);
> +	pci_common_init_dev(pp->dev, pci_hw);
>   	pci_assign_unassigned_resources();
>   #ifdef CONFIG_PCI_DOMAINS
>   	dw_pci.domain++;
> @@ -526,6 +521,52 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
>   	return 0;
>   }
>
> +/*
> + * dw_pcie_msi_host_init() - Function to initialize msi host controller
> + * @pp: ptr to pcie port
> + * @msi_irqc_np: device node ptr to msi irq controller
> + * @irq_msi_ops: ptr to MSI irq_domain_ops struct
> + *
> + * Function register irq domain for msi irq controller and create mappings
> + * for MSI irqs.
> + */
> +static int dw_pcie_msi_host_init(struct pcie_port *pp,
> +				 struct device_node *msi_irqc_np,
> +				 const struct irq_domain_ops *msi_irq_ops)
> +{
> +	const struct irq_domain_ops *msi_irq_domain_ops = msi_irq_ops;
> +	int i;
> +
> +	/* Default to  msi_domain_ops if no msi irq domain ops provided */
> +	if (!msi_irq_domain_ops)
> +		msi_irq_domain_ops =&msi_domain_ops;
> +
> +	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> +		pp->irq_domain = irq_domain_add_linear(msi_irqc_np,
> +					MAX_MSI_IRQS, msi_irq_domain_ops,
> +					&dw_pcie_msi_chip);
> +		if (!pp->irq_domain) {
> +			dev_err(pp->dev, "irq domain init failed\n");
> +			return -ENXIO;
> +		}
> +
> +		for (i = 0; i<  MAX_MSI_IRQS; i++)
> +			irq_create_mapping(pp->irq_domain, i);
> +	}
> +	return 0;
> +}
> +
> +int __init dw_pcie_host_init(struct pcie_port *pp)
> +{
> +	int ret;
> +
> +	ret = dw_pcie_msi_host_init(pp, pp->dev->of_node, NULL);
> +	if (ret)
> +		return ret;
> +
> +	return dw_pcie_common_host_init(pp, NULL);
> +}
> +
>   static void dw_pcie_prog_viewport_cfg0(struct pcie_port *pp, u32 busdev)
>   {
>   	/* Program viewport 0 : OUTBOUND : CFG0 */
> diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
> index 387f69e..db0260f 100644
> --- a/drivers/pci/host/pcie-designware.h
> +++ b/drivers/pci/host/pcie-designware.h
> @@ -51,6 +51,8 @@ struct pcie_port {
>   	int			msi_irq;
>   	struct irq_domain	*irq_domain;
>   	unsigned long		msi_data;
> +#define DW_HW_V3_65		BIT(0)
> +	u32			version;
>   	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
>   };
>
> @@ -79,5 +81,4 @@ void dw_pcie_msi_init(struct pcie_port *pp);
>   int dw_pcie_link_up(struct pcie_port *pp);
>   void dw_pcie_setup_rc(struct pcie_port *pp);
>   int dw_pcie_host_init(struct pcie_port *pp);
> -
>   #endif /* _PCIE_DESIGNWARE_H */


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

* Re: [PATCH v3 3/5] PCI: designware: refactor host init code to re-use on keystone PCI
@ 2014-07-08 13:20     ` Murali Karicheri
  0 siblings, 0 replies; 33+ messages in thread
From: Murali Karicheri @ 2014-07-08 13:20 UTC (permalink / raw)
  To: Murali Karicheri, Mohit Kumar, Jingoo Han
  Cc: linux-pci, linux-kernel, devicetree, Santosh Shilimkar,
	Russell King, Grant Likely, Rob Herring, Bjorn Helgaas,
	Pratyush Anand, Richard Zhu, Kishon Vijay Abraham I, Marek Vasut,
	Arnd Bergmann, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Randy Dunlap

Mohit, Jingoo,

Thanks for the Ack for 1/5 and 2/5 of this series.

Could you also review 3/5 and 4/5 of this series and provide your Ack or 
comments at the earliest.

Thanks and regards,

Murali

On 06/30/2014 05:45 PM, Murali Karicheri wrote:
> This patch refactor the host controller init code to support Keystone
> PCI controller.
>
> Current DW PCI host controller init code has code specific to newer
> DW hw such as ATU port resource parse and ioremap. Conditionally
> execute this code if DW h/w is not v3.65. Keystone PCI controller
> is based on v3.65 DW PCI h/w and it has MSI controller implemented
> in application space and requires different controller initialization
> code. So factor out the MSI host init code to a separate function.
>
> Rename dw_pcie_host_init() to dw_pcie_common_host_init() that takes an
> additional arg, ptr to hw_pci structure. This allows to re-use the code
> for Keystone PCI that can now provide it's own pci hw ops and msi irq
> ops.  dw_pcie_host_init() is now a wrapper function that calls
> dw_pcie_common_host_init() for pci common initialization.
>
> Signed-off-by: Murali Karicheri<m-karicheri2@ti.com>
>
> CC: Santosh Shilimkar<santosh.shilimkar@ti.com>
> CC: Russell King<linux@arm.linux.org.uk>
> CC: Grant Likely<grant.likely@linaro.org>
> CC: Rob Herring<robh+dt@kernel.org>
> CC: Mohit Kumar<mohit.kumar@st.com>
> CC: Jingoo Han<jg1.han@samsung.com>
> CC: Bjorn Helgaas<bhelgaas@google.com>
> CC: Pratyush Anand<pratyush.anand@st.com>
> CC: Richard Zhu<r65037@freescale.com>
> CC: Kishon Vijay Abraham I<kishon@ti.com>
> CC: Marek Vasut<marex@denx.de>
> CC: Arnd Bergmann<arnd@arndb.de>
> CC: Pawel Moll<pawel.moll@arm.com>
> CC: Mark Rutland<mark.rutland@arm.com>
> CC: Ian Campbell<ijc+devicetree@hellion.org.uk>
> CC: Kumar Gala<galak@codeaurora.org>
> CC: Randy Dunlap<rdunlap@infradead.org>
> CC: Grant Likely<grant.likely@linaro.org>
> ---
>   drivers/pci/host/pcie-designware.c |  105 +++++++++++++++++++++++++-----------
>   drivers/pci/host/pcie-designware.h |    3 +-
>   2 files changed, 75 insertions(+), 33 deletions(-)
>
> diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
> index 905941c..c11e4de 100644
> --- a/drivers/pci/host/pcie-designware.c
> +++ b/drivers/pci/host/pcie-designware.c
> @@ -415,19 +415,24 @@ static const struct irq_domain_ops msi_domain_ops = {
>   	.map = dw_pcie_msi_map,
>   };
>
> -int __init dw_pcie_host_init(struct pcie_port *pp)
> +static int __init dw_pcie_common_host_init(struct pcie_port *pp,
> +					   struct hw_pci *hw)
>   {
>   	struct device_node *np = pp->dev->of_node;
>   	struct of_pci_range range;
>   	struct of_pci_range_parser parser;
> +	struct hw_pci *pci_hw = hw;
>   	u32 val;
> -	int i;
>
>   	if (of_pci_range_parser_init(&parser, np)) {
>   		dev_err(pp->dev, "missing ranges property\n");
>   		return -EINVAL;
>   	}
>
> +	/* Default to dw_pci if no hw ops provided */
> +	if (!pci_hw)
> +		pci_hw =&dw_pci;
> +
>   	/* Get the I/O and memory ranges from DT */
>   	for_each_of_pci_range(&parser,&range) {
>   		unsigned long restype = range.flags&  IORESOURCE_TYPE_BITS;
> @@ -467,21 +472,24 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
>   		}
>   	}
>
> -	pp->cfg0_base = pp->cfg.start;
> -	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
>   	pp->mem_base = pp->mem.start;
> -
> -	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
> -					pp->config.cfg0_size);
> -	if (!pp->va_cfg0_base) {
> -		dev_err(pp->dev, "error with ioremap in function\n");
> -		return -ENOMEM;
> -	}
> -	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
> -					pp->config.cfg1_size);
> -	if (!pp->va_cfg1_base) {
> -		dev_err(pp->dev, "error with ioremap\n");
> -		return -ENOMEM;
> +	if (!pp->version&  DW_HW_V3_65) {
> +		/* Default is with ATU port. */
> +		pp->cfg0_base = pp->cfg.start;
> +		pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
> +
> +		pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
> +						pp->config.cfg0_size);
> +		if (!pp->va_cfg0_base) {
> +			dev_err(pp->dev, "error with ioremap in function\n");
> +			return -ENOMEM;
> +		}
> +		pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
> +						pp->config.cfg1_size);
> +		if (!pp->va_cfg1_base) {
> +			dev_err(pp->dev, "error with ioremap\n");
> +			return -ENOMEM;
> +		}
>   	}
>
>   	if (of_property_read_u32(np, "num-lanes",&pp->lanes)) {
> @@ -489,19 +497,6 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
>   		return -EINVAL;
>   	}
>
> -	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> -		pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
> -					MAX_MSI_IRQS,&msi_domain_ops,
> -					&dw_pcie_msi_chip);
> -		if (!pp->irq_domain) {
> -			dev_err(pp->dev, "irq domain init failed\n");
> -			return -ENXIO;
> -		}
> -
> -		for (i = 0; i<  MAX_MSI_IRQS; i++)
> -			irq_create_mapping(pp->irq_domain, i);
> -	}
> -
>   	if (pp->ops->host_init)
>   		pp->ops->host_init(pp);
>
> @@ -514,10 +509,10 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
>   	val |= PORT_LOGIC_SPEED_CHANGE;
>   	dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
>
> -	dw_pci.nr_controllers = 1;
> -	dw_pci.private_data = (void **)&pp;
> +	pci_hw->nr_controllers = 1;
> +	pci_hw->private_data = (void **)&pp;
>
> -	pci_common_init_dev(pp->dev,&dw_pci);
> +	pci_common_init_dev(pp->dev, pci_hw);
>   	pci_assign_unassigned_resources();
>   #ifdef CONFIG_PCI_DOMAINS
>   	dw_pci.domain++;
> @@ -526,6 +521,52 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
>   	return 0;
>   }
>
> +/*
> + * dw_pcie_msi_host_init() - Function to initialize msi host controller
> + * @pp: ptr to pcie port
> + * @msi_irqc_np: device node ptr to msi irq controller
> + * @irq_msi_ops: ptr to MSI irq_domain_ops struct
> + *
> + * Function register irq domain for msi irq controller and create mappings
> + * for MSI irqs.
> + */
> +static int dw_pcie_msi_host_init(struct pcie_port *pp,
> +				 struct device_node *msi_irqc_np,
> +				 const struct irq_domain_ops *msi_irq_ops)
> +{
> +	const struct irq_domain_ops *msi_irq_domain_ops = msi_irq_ops;
> +	int i;
> +
> +	/* Default to  msi_domain_ops if no msi irq domain ops provided */
> +	if (!msi_irq_domain_ops)
> +		msi_irq_domain_ops =&msi_domain_ops;
> +
> +	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> +		pp->irq_domain = irq_domain_add_linear(msi_irqc_np,
> +					MAX_MSI_IRQS, msi_irq_domain_ops,
> +					&dw_pcie_msi_chip);
> +		if (!pp->irq_domain) {
> +			dev_err(pp->dev, "irq domain init failed\n");
> +			return -ENXIO;
> +		}
> +
> +		for (i = 0; i<  MAX_MSI_IRQS; i++)
> +			irq_create_mapping(pp->irq_domain, i);
> +	}
> +	return 0;
> +}
> +
> +int __init dw_pcie_host_init(struct pcie_port *pp)
> +{
> +	int ret;
> +
> +	ret = dw_pcie_msi_host_init(pp, pp->dev->of_node, NULL);
> +	if (ret)
> +		return ret;
> +
> +	return dw_pcie_common_host_init(pp, NULL);
> +}
> +
>   static void dw_pcie_prog_viewport_cfg0(struct pcie_port *pp, u32 busdev)
>   {
>   	/* Program viewport 0 : OUTBOUND : CFG0 */
> diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
> index 387f69e..db0260f 100644
> --- a/drivers/pci/host/pcie-designware.h
> +++ b/drivers/pci/host/pcie-designware.h
> @@ -51,6 +51,8 @@ struct pcie_port {
>   	int			msi_irq;
>   	struct irq_domain	*irq_domain;
>   	unsigned long		msi_data;
> +#define DW_HW_V3_65		BIT(0)
> +	u32			version;
>   	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
>   };
>
> @@ -79,5 +81,4 @@ void dw_pcie_msi_init(struct pcie_port *pp);
>   int dw_pcie_link_up(struct pcie_port *pp);
>   void dw_pcie_setup_rc(struct pcie_port *pp);
>   int dw_pcie_host_init(struct pcie_port *pp);
> -
>   #endif /* _PCIE_DESIGNWARE_H */

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

* Re: [PATCH v3 4/5] PCI: designware: enhance dw core driver to support Keystone PCI host controller
@ 2014-07-08 13:24     ` Murali Karicheri
  0 siblings, 0 replies; 33+ messages in thread
From: Murali Karicheri @ 2014-07-08 13:24 UTC (permalink / raw)
  To: Murali Karicheri
  Cc: linux-pci, linux-kernel, devicetree, Santosh Shilimkar,
	Russell King, Grant Likely, Rob Herring, Mohit Kumar, Jingoo Han,
	Bjorn Helgaas, Pratyush Anand, Richard Zhu,
	Kishon Vijay Abraham I, Marek Vasut, Arnd Bergmann, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap

On 06/30/2014 05:45 PM, Murali Karicheri wrote:
> Add API dw_pcie_v3_65_host_init() to support host controller initialization
> for Keystone PCI driver. The Keystone PCI uses v3.65 version of the DW hardware
> identified by compatibility string "dw,snps-pcie-v3.65". This allow for
> different treatment for this version of the h/w during host initialization.
> Key differences in v3.65 DW h/w are
> 	1. No ATU support
> 	2. Legacy and MSI irq functions are implemented in application
> 	   register space
> 	3. MSI interrupts are multiplexed over 8 IRQ lines to the Host side.
> So a msi irq chip is needed and the irq domain ops ptr is passed in
> dw_pcie_v3_65_host_init() to allow re-use of common MSI code in dw core.  The
> Keystone PCI host controller requires a modified pci scan function to allow
> setup BAR0 for EP's access to MSI_IRQ register in application register to
> raise MSI irq.  So a ptr to pci hw ops struct is passed to the host init code.
>
> Keystone PCI controller re-uses the DW Core driver code wherever there is
> common functionality. So this patch makes these functions global and added
> their prototypes in pcie-designware.h to allow re-use on Keystone.
>
> Signed-off-by: Murali Karicheri<m-karicheri2@ti.com>
>
> CC: Santosh Shilimkar<santosh.shilimkar@ti.com>
> CC: Russell King<linux@arm.linux.org.uk>
> CC: Grant Likely<grant.likely@linaro.org>
> CC: Rob Herring<robh+dt@kernel.org>
> CC: Mohit Kumar<mohit.kumar@st.com>
> CC: Jingoo Han<jg1.han@samsung.com>
> CC: Bjorn Helgaas<bhelgaas@google.com>
> CC: Pratyush Anand<pratyush.anand@st.com>
> CC: Richard Zhu<r65037@freescale.com>
> CC: Kishon Vijay Abraham I<kishon@ti.com>
> CC: Marek Vasut<marex@denx.de>
> CC: Arnd Bergmann<arnd@arndb.de>
> CC: Pawel Moll<pawel.moll@arm.com>
> CC: Mark Rutland<mark.rutland@arm.com>
> CC: Ian Campbell<ijc+devicetree@hellion.org.uk>
> CC: Kumar Gala<galak@codeaurora.org>
> CC: Randy Dunlap<rdunlap@infradead.org>
> CC: Grant Likely<grant.likely@linaro.org>
> ---
>   .../devicetree/bindings/pci/designware-pcie.txt    |    2 +
>   drivers/pci/host/pcie-designware.c                 |   39 ++++++++++++++++++--
>   drivers/pci/host/pcie-designware.h                 |    7 ++++
>   3 files changed, 44 insertions(+), 4 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/pci/designware-pcie.txt b/Documentation/devicetree/bindings/pci/designware-pcie.txt
> index d0d15ee..0cb10c0 100644
> --- a/Documentation/devicetree/bindings/pci/designware-pcie.txt
> +++ b/Documentation/devicetree/bindings/pci/designware-pcie.txt
> @@ -2,6 +2,8 @@
>
>   Required properties:
>   - compatible: should contain "snps,dw-pcie" to identify the core.
> +  Additionally contains "dw,snps-pcie-v3.65" to identify v3.65 version of the DW
> +  hardware.
>   - #address-cells: set to<3>
>   - #size-cells: set to<2>
>   - device_type: set to "pci"
> diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
> index c11e4de..4dcbebe 100644
> --- a/drivers/pci/host/pcie-designware.c
> +++ b/drivers/pci/host/pcie-designware.c
> @@ -556,6 +556,37 @@ static int dw_pcie_msi_host_init(struct pcie_port *pp,
>   	return 0;
>   }
>
> +int __init dw_pcie_v3_65_host_init(struct pcie_port *pp, struct hw_pci *hw,
> +				   struct device_node *msi_irqc_np,
> +				   const struct irq_domain_ops *msi_irq_ops)
> +{
> +	int ret = -EINVAL;
> +
> +	/* check if compatible with v3.65 DW h/w */
> +	if (!of_device_is_compatible(pp->dev->of_node, "dw,snps-pcie-v3.65")) {
> +		dev_err(pp->dev,
> +			"PCI Controller not compatible with v3.65 DW h/w\n");
> +		goto out;
> +	}
> +	pp->version = DW_HW_V3_65;
> +
> +	/* v3.65 PCI controller is expected to provide its own PCI h/w ops */
> +	if (!hw || !msi_irq_ops) {
> +		dev_err(pp->dev,
> +			"v3.65 PCI Controllers doesn't provide %s\n",
> +			(hw == NULL) ? "PCI hw ops" : "PCI MSI irq domain ops");
> +		goto out;
> +	}
> +
> +	ret = dw_pcie_msi_host_init(pp, msi_irqc_np,  msi_irq_ops);
> +	if (ret)
> +		goto out;
> +
> +	ret = dw_pcie_common_host_init(pp, hw);
> +out:
> +	return ret;
> +}
> +
>   int __init dw_pcie_host_init(struct pcie_port *pp)
>   {
>   	int ret;
> @@ -763,7 +794,7 @@ static struct pci_ops dw_pcie_ops = {
>   	.write = dw_pcie_wr_conf,
>   };
>
> -static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
> +int dw_pcie_setup(int nr, struct pci_sys_data *sys)
>   {
>   	struct pcie_port *pp;
>
> @@ -786,7 +817,7 @@ static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
>   	return 1;
>   }
>
> -static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
> +struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
>   {
>   	struct pci_bus *bus;
>   	struct pcie_port *pp = sys_to_pcie(sys);
> @@ -803,7 +834,7 @@ static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
>   	return bus;
>   }
>
> -static int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
> +int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
>   {
>   	struct pcie_port *pp = sys_to_pcie(dev->bus->sysdata);
>   	int irq;
> @@ -815,7 +846,7 @@ static int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
>   	return irq;
>   }
>
> -static void dw_pcie_add_bus(struct pci_bus *bus)
> +void dw_pcie_add_bus(struct pci_bus *bus)
>   {
>   	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>   		struct pcie_port *pp = sys_to_pcie(bus->sysdata);
> diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
> index db0260f..2681826 100644
> --- a/drivers/pci/host/pcie-designware.h
> +++ b/drivers/pci/host/pcie-designware.h
> @@ -81,4 +81,11 @@ void dw_pcie_msi_init(struct pcie_port *pp);
>   int dw_pcie_link_up(struct pcie_port *pp);
>   void dw_pcie_setup_rc(struct pcie_port *pp);
>   int dw_pcie_host_init(struct pcie_port *pp);
> +int dw_pcie_v3_65_host_init(struct pcie_port *pp, struct hw_pci *hw,
> +			   struct device_node *msi_irqc_np,
> +			   const struct irq_domain_ops *msi_irq_ops);
> +int dw_pcie_setup(int nr, struct pci_sys_data *sys);
> +struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys);
> +void dw_pcie_add_bus(struct pci_bus *bus);
> +int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin);
>   #endif /* _PCIE_DESIGNWARE_H */
DT Maintainers,

Could you provide your comments or Ack for the DT update made in this patch?

Thanks

Murali

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

* Re: [PATCH v3 4/5] PCI: designware: enhance dw core driver to support Keystone PCI host controller
@ 2014-07-08 13:24     ` Murali Karicheri
  0 siblings, 0 replies; 33+ messages in thread
From: Murali Karicheri @ 2014-07-08 13:24 UTC (permalink / raw)
  To: Murali Karicheri
  Cc: linux-pci-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Santosh Shilimkar,
	Russell King, Grant Likely, Rob Herring, Mohit Kumar, Jingoo Han,
	Bjorn Helgaas, Pratyush Anand, Richard Zhu,
	Kishon Vijay Abraham I, Marek Vasut, Arnd Bergmann, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap

On 06/30/2014 05:45 PM, Murali Karicheri wrote:
> Add API dw_pcie_v3_65_host_init() to support host controller initialization
> for Keystone PCI driver. The Keystone PCI uses v3.65 version of the DW hardware
> identified by compatibility string "dw,snps-pcie-v3.65". This allow for
> different treatment for this version of the h/w during host initialization.
> Key differences in v3.65 DW h/w are
> 	1. No ATU support
> 	2. Legacy and MSI irq functions are implemented in application
> 	   register space
> 	3. MSI interrupts are multiplexed over 8 IRQ lines to the Host side.
> So a msi irq chip is needed and the irq domain ops ptr is passed in
> dw_pcie_v3_65_host_init() to allow re-use of common MSI code in dw core.  The
> Keystone PCI host controller requires a modified pci scan function to allow
> setup BAR0 for EP's access to MSI_IRQ register in application register to
> raise MSI irq.  So a ptr to pci hw ops struct is passed to the host init code.
>
> Keystone PCI controller re-uses the DW Core driver code wherever there is
> common functionality. So this patch makes these functions global and added
> their prototypes in pcie-designware.h to allow re-use on Keystone.
>
> Signed-off-by: Murali Karicheri<m-karicheri2-l0cyMroinI0@public.gmane.org>
>
> CC: Santosh Shilimkar<santosh.shilimkar-l0cyMroinI0@public.gmane.org>
> CC: Russell King<linux-lFZ/pmaqli7XmaaqVzeoHQ@public.gmane.org>
> CC: Grant Likely<grant.likely-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> CC: Rob Herring<robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> CC: Mohit Kumar<mohit.kumar-qxv4g6HH51o@public.gmane.org>
> CC: Jingoo Han<jg1.han-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> CC: Bjorn Helgaas<bhelgaas-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
> CC: Pratyush Anand<pratyush.anand-qxv4g6HH51o@public.gmane.org>
> CC: Richard Zhu<r65037-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
> CC: Kishon Vijay Abraham I<kishon-l0cyMroinI0@public.gmane.org>
> CC: Marek Vasut<marex-ynQEQJNshbs@public.gmane.org>
> CC: Arnd Bergmann<arnd-r2nGTMty4D4@public.gmane.org>
> CC: Pawel Moll<pawel.moll-5wv7dgnIgG8@public.gmane.org>
> CC: Mark Rutland<mark.rutland-5wv7dgnIgG8@public.gmane.org>
> CC: Ian Campbell<ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg@public.gmane.org>
> CC: Kumar Gala<galak-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> CC: Randy Dunlap<rdunlap-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>
> CC: Grant Likely<grant.likely-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> ---
>   .../devicetree/bindings/pci/designware-pcie.txt    |    2 +
>   drivers/pci/host/pcie-designware.c                 |   39 ++++++++++++++++++--
>   drivers/pci/host/pcie-designware.h                 |    7 ++++
>   3 files changed, 44 insertions(+), 4 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/pci/designware-pcie.txt b/Documentation/devicetree/bindings/pci/designware-pcie.txt
> index d0d15ee..0cb10c0 100644
> --- a/Documentation/devicetree/bindings/pci/designware-pcie.txt
> +++ b/Documentation/devicetree/bindings/pci/designware-pcie.txt
> @@ -2,6 +2,8 @@
>
>   Required properties:
>   - compatible: should contain "snps,dw-pcie" to identify the core.
> +  Additionally contains "dw,snps-pcie-v3.65" to identify v3.65 version of the DW
> +  hardware.
>   - #address-cells: set to<3>
>   - #size-cells: set to<2>
>   - device_type: set to "pci"
> diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
> index c11e4de..4dcbebe 100644
> --- a/drivers/pci/host/pcie-designware.c
> +++ b/drivers/pci/host/pcie-designware.c
> @@ -556,6 +556,37 @@ static int dw_pcie_msi_host_init(struct pcie_port *pp,
>   	return 0;
>   }
>
> +int __init dw_pcie_v3_65_host_init(struct pcie_port *pp, struct hw_pci *hw,
> +				   struct device_node *msi_irqc_np,
> +				   const struct irq_domain_ops *msi_irq_ops)
> +{
> +	int ret = -EINVAL;
> +
> +	/* check if compatible with v3.65 DW h/w */
> +	if (!of_device_is_compatible(pp->dev->of_node, "dw,snps-pcie-v3.65")) {
> +		dev_err(pp->dev,
> +			"PCI Controller not compatible with v3.65 DW h/w\n");
> +		goto out;
> +	}
> +	pp->version = DW_HW_V3_65;
> +
> +	/* v3.65 PCI controller is expected to provide its own PCI h/w ops */
> +	if (!hw || !msi_irq_ops) {
> +		dev_err(pp->dev,
> +			"v3.65 PCI Controllers doesn't provide %s\n",
> +			(hw == NULL) ? "PCI hw ops" : "PCI MSI irq domain ops");
> +		goto out;
> +	}
> +
> +	ret = dw_pcie_msi_host_init(pp, msi_irqc_np,  msi_irq_ops);
> +	if (ret)
> +		goto out;
> +
> +	ret = dw_pcie_common_host_init(pp, hw);
> +out:
> +	return ret;
> +}
> +
>   int __init dw_pcie_host_init(struct pcie_port *pp)
>   {
>   	int ret;
> @@ -763,7 +794,7 @@ static struct pci_ops dw_pcie_ops = {
>   	.write = dw_pcie_wr_conf,
>   };
>
> -static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
> +int dw_pcie_setup(int nr, struct pci_sys_data *sys)
>   {
>   	struct pcie_port *pp;
>
> @@ -786,7 +817,7 @@ static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
>   	return 1;
>   }
>
> -static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
> +struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
>   {
>   	struct pci_bus *bus;
>   	struct pcie_port *pp = sys_to_pcie(sys);
> @@ -803,7 +834,7 @@ static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
>   	return bus;
>   }
>
> -static int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
> +int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
>   {
>   	struct pcie_port *pp = sys_to_pcie(dev->bus->sysdata);
>   	int irq;
> @@ -815,7 +846,7 @@ static int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
>   	return irq;
>   }
>
> -static void dw_pcie_add_bus(struct pci_bus *bus)
> +void dw_pcie_add_bus(struct pci_bus *bus)
>   {
>   	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>   		struct pcie_port *pp = sys_to_pcie(bus->sysdata);
> diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
> index db0260f..2681826 100644
> --- a/drivers/pci/host/pcie-designware.h
> +++ b/drivers/pci/host/pcie-designware.h
> @@ -81,4 +81,11 @@ void dw_pcie_msi_init(struct pcie_port *pp);
>   int dw_pcie_link_up(struct pcie_port *pp);
>   void dw_pcie_setup_rc(struct pcie_port *pp);
>   int dw_pcie_host_init(struct pcie_port *pp);
> +int dw_pcie_v3_65_host_init(struct pcie_port *pp, struct hw_pci *hw,
> +			   struct device_node *msi_irqc_np,
> +			   const struct irq_domain_ops *msi_irq_ops);
> +int dw_pcie_setup(int nr, struct pci_sys_data *sys);
> +struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys);
> +void dw_pcie_add_bus(struct pci_bus *bus);
> +int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin);
>   #endif /* _PCIE_DESIGNWARE_H */
DT Maintainers,

Could you provide your comments or Ack for the DT update made in this patch?

Thanks

Murali
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v3 5/5] PCI: add PCI controller for Keystone PCIe h/w
  2014-06-30 21:45   ` Murali Karicheri
@ 2014-07-08 13:25     ` Murali Karicheri
  -1 siblings, 0 replies; 33+ messages in thread
From: Murali Karicheri @ 2014-07-08 13:25 UTC (permalink / raw)
  To: Murali Karicheri
  Cc: linux-pci, linux-kernel, devicetree, Santosh Shilimkar,
	Russell King, Grant Likely, Rob Herring, Mohit Kumar, Jingoo Han,
	Bjorn Helgaas, Pratyush Anand, Richard Zhu,
	Kishon Vijay Abraham I, Marek Vasut, Arnd Bergmann, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap

On 06/30/2014 05:45 PM, Murali Karicheri wrote:
> Keystone PCIe controller is based on v3.65 version of the
> designware h/w. Main differences are
> 	1. No ATU support
> 	2. Legacy and MSI irq functions are implemented in
> 	   application register space
> 	3. MSI interrupts are multiplexed over 8 IRQ lines to the Host
> 	   side.
> All of the Application register space handing code are organized into
> pci-keystone-dw.c and the functions are called from pci-keystone.c
> to implement PCI controller driver. Also add necessary DT documentation
> for the driver.
>
> Signed-off-by: Murali Karicheri<m-karicheri2@ti.com>
>
> CC: Santosh Shilimkar<santosh.shilimkar@ti.com>
> CC: Russell King<linux@arm.linux.org.uk>
> CC: Grant Likely<grant.likely@linaro.org>
> CC: Rob Herring<robh+dt@kernel.org>
> CC: Mohit Kumar<mohit.kumar@st.com>
> CC: Jingoo Han<jg1.han@samsung.com>
> CC: Bjorn Helgaas<bhelgaas@google.com>
> CC: Pratyush Anand<pratyush.anand@st.com>
> CC: Richard Zhu<r65037@freescale.com>
> CC: Kishon Vijay Abraham I<kishon@ti.com>
> CC: Marek Vasut<marex@denx.de>
> CC: Arnd Bergmann<arnd@arndb.de>
> CC: Pawel Moll<pawel.moll@arm.com>
> CC: Mark Rutland<mark.rutland@arm.com>
> CC: Ian Campbell<ijc+devicetree@hellion.org.uk>
> CC: Kumar Gala<galak@codeaurora.org>
> CC: Randy Dunlap<rdunlap@infradead.org>
> CC: Grant Likely<grant.likely@linaro.org>
> ---
>   .../devicetree/bindings/pci/pci-keystone.txt       |   69 +++
>   drivers/pci/host/Kconfig                           |    5 +
>   drivers/pci/host/Makefile                          |    1 +
>   drivers/pci/host/pci-keystone-dw.c                 |  523 ++++++++++++++++++++
>   drivers/pci/host/pci-keystone.c                    |  381 ++++++++++++++
>   drivers/pci/host/pci-keystone.h                    |   56 +++
>   6 files changed, 1035 insertions(+)
>   create mode 100644 Documentation/devicetree/bindings/pci/pci-keystone.txt
>   create mode 100644 drivers/pci/host/pci-keystone-dw.c
>   create mode 100644 drivers/pci/host/pci-keystone.c
>   create mode 100644 drivers/pci/host/pci-keystone.h
>
> diff --git a/Documentation/devicetree/bindings/pci/pci-keystone.txt b/Documentation/devicetree/bindings/pci/pci-keystone.txt
> new file mode 100644
> index 0000000..bb39601
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/pci-keystone.txt
> @@ -0,0 +1,69 @@
> +TI Keystone PCIe interface
> +
> +Keystone PCI host Controller is based on Designware PCI h/w version 3.65.
> +It shares common functions with PCIE Designware core driver and inherit
> +common properties defined in
> +Documentation/devicetree/bindings/pci/designware-pci.txt
> +Compatibility string "dw,snps-pcie-v3.65" is used to identify the verison
> +of the DW h/w used on Keystone.
> +
> +Please refer to Documentation/devicetree/bindings/pci/designware-pci.txt
> +for the details of designware DT bindings. Additional properties are
> +described here as well propeties that are not applicable.
> +
> +Required Properties:-
> +
> +compatibility: "ti,keystone-pcie"
> +reg:	index 1 is the base address and length of DW application registers.
> +	index 2 is the base address and length of PCI mode configuration
> +	register.
> +	index 3 is the base address and length of PCI device ID register.
> +
> +pcie_msi_intc : Interrupt controller device node for MSI irq chip
> +	interrupt-cells: should be set to 1
> +	interrupt-parent: Parent interrupt controller phandle
> +	interrupts: GIC interrupt lines connected to PCI MSI interrupt lines
> +
> + Example:
> +	pcie_msi_intc: msi-interrupt-controller {
> +			interrupt-controller;
> +			#interrupt-cells =<1>;
> +			interrupt-parent =<&gic>;
> +			interrupts =<GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
> +					<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>,
> +					<GIC_SPI 32 IRQ_TYPE_EDGE_RISING>,
> +					<GIC_SPI 33 IRQ_TYPE_EDGE_RISING>,
> +					<GIC_SPI 34 IRQ_TYPE_EDGE_RISING>,
> +					<GIC_SPI 35 IRQ_TYPE_EDGE_RISING>,
> +					<GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
> +					<GIC_SPI 37 IRQ_TYPE_EDGE_RISING>;
> +	};
> +
> +pcie_intc: Interrupt controller device node for Legacy irq chip
> +	interrupt-cells: should be set to 1
> +	interrupt-parent: Parent interrupt controller phandle
> +	interrupts: GIC interrupt lines connected to PCI Legacy interrupt lines
> +
> + Example:
> +	pcie_intc: legacy-interrupt-controller {
> +		interrupt-controller;
> +		#interrupt-cells =<1>;
> +		interrupt-parent =<&gic>;
> +		interrupts =<GIC_SPI 26 IRQ_TYPE_EDGE_RISING>,
> +			<GIC_SPI 27 IRQ_TYPE_EDGE_RISING>,
> +			<GIC_SPI 28 IRQ_TYPE_EDGE_RISING>,
> +			<GIC_SPI 29 IRQ_TYPE_EDGE_RISING>;
> +	};
> +
> +Optional properties:-
> +	phys: phandle to Generic Keystone SerDes phy for PCI
> +	phy-names: name of the Generic Keystine SerDes phy for PCI
> +	  - If boot loader already does PCI link establishment, then phys and
> +	    phy-names shouldn't be present.
> +	ti,enable-linktrain - Enable Link training.
> +	  - If boot loader already does PCI link establishment, then this
> +	    shouldn't be present.
> +
> +Designware DT Properties not applicable for Keystone PCI
> +
> +1. pcie_bus clock-names not used. Instead, a phandle to phys is used.
> diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
> index 21df477..f8bc475 100644
> --- a/drivers/pci/host/Kconfig
> +++ b/drivers/pci/host/Kconfig
> @@ -46,4 +46,9 @@ config PCI_HOST_GENERIC
>   	  Say Y here if you want to support a simple generic PCI host
>   	  controller, such as the one emulated by kvmtool.
>
> +config PCI_KEYSTONE
> +	bool "TI Keystone PCIe controller"
> +	depends on ARCH_KEYSTONE
> +	select PCIE_DW
> +	select PCIEPORTBUS
>   endmenu
> diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
> index 611ba4b..d1b6ce1 100644
> --- a/drivers/pci/host/Makefile
> +++ b/drivers/pci/host/Makefile
> @@ -6,3 +6,4 @@ obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
>   obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
>   obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o
>   obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o
> +obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o
> diff --git a/drivers/pci/host/pci-keystone-dw.c b/drivers/pci/host/pci-keystone-dw.c
> new file mode 100644
> index 0000000..3b5b075
> --- /dev/null
> +++ b/drivers/pci/host/pci-keystone-dw.c
> @@ -0,0 +1,523 @@
> +/*
> + * Designware application register space functions for Keystone PCI controller
> + *
> + * Copyright (C) 2013-2014 Texas Instruments., Ltd.
> + *		http://www.ti.com
> + *
> + * Author: Murali Karicheri<m-karicheri2@ti.com>
> + *
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include<linux/irq.h>
> +#include<linux/irqdomain.h>
> +#include<linux/module.h>
> +#include<linux/of.h>
> +#include<linux/of_pci.h>
> +#include<linux/pci.h>
> +#include<linux/platform_device.h>
> +
> +#include "pcie-designware.h"
> +#include "pci-keystone.h"
> +
> +/* Application register defines */
> +#define LTSSM_EN_VAL		        BIT(0)
> +#define LTSSM_STATE_MASK	        0x1f
> +#define LTSSM_STATE_L0		        0x11
> +#define DIR_SPD				(1<<  17)
> +#define DBI_CS2_EN_VAL		        BIT(5)
> +#define OB_XLAT_EN_VAL		        BIT(1)
> +
> +/* Application registers */
> +#define CMD_STATUS			0x004
> +#define CFG_SETUP			0x008
> +#define OB_SIZE				0x030
> +#define CFG_PCIM_WIN_SZ_IDX	        3
> +#define CFG_PCIM_WIN_CNT	        32
> +#define SPACE0_REMOTE_CFG_OFFSET	0x1000
> +#define OB_OFFSET_INDEX(n)		(0x200 + (8 * n))
> +#define OB_OFFSET_HI(n)			(0x204 + (8 * n))
> +
> +/* IRQ register defines */
> +#define IRQ_EOI                         0x050
> +#define IRQ_STATUS			0x184
> +#define IRQ_ENABLE_SET			0x188
> +#define IRQ_ENABLE_CLR			0x18c
> +
> +#define MSI_IRQ				0x054
> +#define MSI0_IRQ_STATUS			0x104
> +#define MSI0_IRQ_ENABLE_SET		0x108
> +#define MSI0_IRQ_ENABLE_CLR		0x10c
> +#define IRQ_STATUS			0x184
> +#define MSI_IRQ_OFFSET			4
> +
> +/* Config space registers */
> +#define DEBUG0			        0x728
> +
> +#define to_keystone_pcie(x)	container_of(x, struct keystone_pcie, pp)
> +
> +static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
> +{
> +	return sys->private_data;
> +}
> +
> +static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset,
> +					u32 *bit_pos)
> +{
> +	*reg_offset = offset % 8;
> +	*bit_pos = offset>>  3;
> +}
> +
> +inline u32 ks_dw_pcie_get_msi_data(struct pcie_port *pp)
> +{
> +	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
> +
> +	return ks_pcie->app.start + MSI_IRQ;
> +}
> +
> +void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie , int offset)
> +{
> +	struct pcie_port *pp =&ks_pcie->pp;
> +	u32 pending, vector;
> +	int src, virq;
> +
> +	pending = readl(ks_pcie->va_app_base + MSI0_IRQ_STATUS + (offset<<  4));
> +	/*
> +	 * MSI0, Status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit
> +	 * shows 1, 9, 17, 25 and so forth
> +	 */
> +	for (src = 0; src<  4; src++) {
> +		if (BIT(src)&  pending) {
> +			vector = offset + (src<<  3);
> +			virq = irq_linear_revmap(pp->irq_domain, vector);
> +			dev_dbg(pp->dev,
> +				"irq: bit %d, vector %d, virq %d\n",
> +				 src, vector, virq);
> +			generic_handle_irq(virq);
> +		}
> +	}
> +}
> +
> +static void ks_dw_pcie_msi_irq_ack(struct irq_data *d)
> +{
> +	u32 offset, reg_offset, bit_pos;
> +	struct keystone_pcie *ks_pcie;
> +	unsigned int irq = d->irq;
> +	struct msi_desc *msi;
> +	struct pcie_port *pp;
> +
> +	msi = irq_get_msi_desc(irq);
> +	pp = sys_to_pcie(msi->dev->bus->sysdata);
> +	ks_pcie = to_keystone_pcie(pp);
> +	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
> +	update_reg_offset_bit_pos(offset,&reg_offset,&bit_pos);
> +
> +	writel(BIT(bit_pos),
> +		ks_pcie->va_app_base + MSI0_IRQ_STATUS + (reg_offset<<  4));
> +	writel(reg_offset + MSI_IRQ_OFFSET, ks_pcie->va_app_base + IRQ_EOI);
> +}
> +
> +void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq)
> +{
> +	u32 reg_offset, bit_pos;
> +	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
> +
> +	update_reg_offset_bit_pos(irq,&reg_offset,&bit_pos);
> +	writel(BIT(bit_pos),
> +		ks_pcie->va_app_base + MSI0_IRQ_ENABLE_SET + (reg_offset<<  4));
> +}
> +
> +void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
> +{
> +	u32 reg_offset, bit_pos;
> +	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
> +
> +	update_reg_offset_bit_pos(irq,&reg_offset,&bit_pos);
> +	writel(BIT(bit_pos),
> +		ks_pcie->va_app_base + MSI0_IRQ_ENABLE_CLR + (reg_offset<<  4));
> +}
> +
> +static void ks_dw_pcie_msi_irq_mask(struct irq_data *d)
> +{
> +	struct keystone_pcie *ks_pcie;
> +	unsigned int irq = d->irq;
> +	struct msi_desc *msi;
> +	struct pcie_port *pp;
> +	u32 offset;
> +
> +	msi = irq_get_msi_desc(irq);
> +	pp = sys_to_pcie(msi->dev->bus->sysdata);
> +	ks_pcie = to_keystone_pcie(pp);
> +	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
> +
> +	/* mask the end point if PVM implemented */
> +	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> +		if (msi->msi_attrib.maskbit)
> +			mask_msi_irq(d);
> +	}
> +
> +	ks_dw_pcie_msi_clear_irq(pp, offset);
> +}
> +
> +static void ks_dw_pcie_msi_irq_unmask(struct irq_data *d)
> +{
> +	struct keystone_pcie *ks_pcie;
> +	unsigned int irq = d->irq;
> +	struct msi_desc *msi;
> +	struct pcie_port *pp;
> +	u32 offset;
> +
> +	msi = irq_get_msi_desc(irq);
> +	pp = sys_to_pcie(msi->dev->bus->sysdata);
> +	ks_pcie = to_keystone_pcie(pp);
> +	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
> +
> +	/* mask the end point if PVM implemented */
> +	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> +		if (msi->msi_attrib.maskbit)
> +			unmask_msi_irq(d);
> +	}
> +
> +	ks_dw_pcie_msi_set_irq(pp, offset);
> +}
> +
> +static struct irq_chip ks_dw_pcie_msi_irq_chip = {
> +	.name = "Keystone-PCIe-MSI-IRQ",
> +	.irq_ack = ks_dw_pcie_msi_irq_ack,
> +	.irq_mask = ks_dw_pcie_msi_irq_mask,
> +	.irq_unmask = ks_dw_pcie_msi_irq_unmask,
> +};
> +
> +static int ks_dw_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
> +			irq_hw_number_t hwirq)
> +{
> +	irq_set_chip_and_handler(irq,&ks_dw_pcie_msi_irq_chip,
> +				 handle_level_irq);
> +	irq_set_chip_data(irq, domain->host_data);
> +	set_irq_flags(irq, IRQF_VALID);
> +
> +	return 0;
> +}
> +
> +const struct irq_domain_ops ks_dw_pcie_msi_domain_ops = {
> +	.map = ks_dw_pcie_msi_map,
> +};
> +
> +void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie)
> +{
> +	int i;
> +
> +	for (i = 0; i<  MAX_LEGACY_IRQS; i++)
> +		writel(0x1, ks_pcie->va_app_base + IRQ_ENABLE_SET + (i<<  4));
> +}
> +
> +void ks_dw_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, int offset)
> +{
> +	struct pcie_port *pp =&ks_pcie->pp;
> +	u32 pending;
> +	int virq;
> +
> +	pending = readl(ks_pcie->va_app_base + IRQ_STATUS + (offset<<  4));
> +
> +	if (BIT(0)&  pending) {
> +		virq = irq_linear_revmap(ks_pcie->legacy_irq_domain, offset);
> +		dev_dbg(pp->dev,
> +			": irq: irq_offset %d, virq %d\n", offset, virq);
> +		generic_handle_irq(virq);
> +	}
> +
> +	/* EOI the INTx interrupt */
> +	writel(offset, ks_pcie->va_app_base + IRQ_EOI);
> +}
> +
> +static void ks_dw_pcie_ack_legacy_irq(struct irq_data *d)
> +{
> +}
> +
> +static void ks_dw_pcie_mask_legacy_irq(struct irq_data *d)
> +{
> +}
> +
> +static void ks_dw_pcie_unmask_legacy_irq(struct irq_data *d)
> +{
> +}
> +
> +static struct irq_chip ks_dw_pcie_legacy_irq_chip = {
> +	.name = "Keystone-PCI-Legacy-IRQ",
> +	.irq_ack = ks_dw_pcie_ack_legacy_irq,
> +	.irq_mask = ks_dw_pcie_mask_legacy_irq,
> +	.irq_unmask = ks_dw_pcie_unmask_legacy_irq,
> +};
> +
> +static int ks_dw_pcie_init_legacy_irq_map(struct irq_domain *d,
> +				unsigned int irq, irq_hw_number_t hw_irq)
> +{
> +	irq_set_chip_and_handler(irq,&ks_dw_pcie_legacy_irq_chip,
> +				handle_level_irq);
> +	irq_set_chip_data(irq, d->host_data);
> +	set_irq_flags(irq, IRQF_VALID);
> +
> +	return 0;
> +}
> +
> +static const struct irq_domain_ops ks_dw_pcie_legacy_irq_domian_ops = {
> +	.map = ks_dw_pcie_init_legacy_irq_map,
> +	.xlate = irq_domain_xlate_onetwocell,
> +};
> +
> +/**
> + * ks_dw_pcie_set_dbi_mode() - Set DBI mode to access overlaid BAR mask registers
> + *
> + * Since modification of dbi_cs2 involves different clock domain, read the
> + * status back to ensure the transition is complete.
> + */
> +static inline void ks_dw_pcie_set_dbi_mode(void __iomem *reg_virt)
> +{
> +	u32 val;
> +
> +	writel(DBI_CS2_EN_VAL | readl(reg_virt + CMD_STATUS),
> +		     reg_virt + CMD_STATUS);
> +
> +	do {
> +		val = readl(reg_virt + CMD_STATUS);
> +	} while (!(val&  DBI_CS2_EN_VAL));
> +}
> +
> +/**
> + * ks_dw_pcie_clear_dbi_mode() - Disable DBI mode
> + *
> + * Since modification of dbi_cs2 involves different clock domain, read the
> + * status back to ensure the transition is complete.
> + */
> +static inline void ks_dw_pcie_clear_dbi_mode(void __iomem *reg_virt)
> +{
> +	u32 val;
> +
> +	writel(~DBI_CS2_EN_VAL&  readl(reg_virt + CMD_STATUS),
> +		     reg_virt + CMD_STATUS);
> +
> +	do {
> +		val = readl(reg_virt + CMD_STATUS);
> +	} while (val&  DBI_CS2_EN_VAL);
> +}
> +
> +void ks_dw_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie)
> +{
> +	struct pcie_port *pp =&ks_pcie->pp;
> +	u32 start = pp->mem.start, end = pp->mem.end;
> +	int i, tr_size;
> +
> +	/* disable BARS for inbound access */
> +	ks_dw_pcie_set_dbi_mode(ks_pcie->va_app_base);
> +	writel(0, pp->dbi_base + PCI_BASE_ADDRESS_0);
> +	writel(0, pp->dbi_base + PCI_BASE_ADDRESS_1);
> +	ks_dw_pcie_clear_dbi_mode(ks_pcie->va_app_base);
> +
> +	/* Set outbound translation size per window division */
> +	writel(CFG_PCIM_WIN_SZ_IDX&  0x7, ks_pcie->va_app_base + OB_SIZE);
> +
> +	tr_size = (1<<  (CFG_PCIM_WIN_SZ_IDX&  0x7)) * SZ_1M;
> +
> +	/* Using Direct 1:1 mapping of RC<->  PCI memory space */
> +	for (i = 0; (i<  CFG_PCIM_WIN_CNT)&&  (start<  end); i++) {
> +		writel(start | 1, ks_pcie->va_app_base + OB_OFFSET_INDEX(i));
> +		writel(0, ks_pcie->va_app_base + OB_OFFSET_HI(i));
> +		start += tr_size;
> +	}
> +
> +	/* Enable OB translation */
> +	writel(OB_XLAT_EN_VAL | readl(ks_pcie->va_app_base + CMD_STATUS),
> +		ks_pcie->va_app_base + CMD_STATUS);
> +}
> +
> +/**
> + * ks_pcie_setup_config_addr() - Set up configuration space address for a
> + * device
> + *
> + * @ks_pcie: ptr to keystone_pcie structure
> + * @bus: Bus number the device is residing on
> + * @device: Device number
> + * @function: Function number in device
> + *
> + * Forms and returns the address of configuration space mapped in PCIESS
> + * address space 0. Also configures CFG_SETUP for remote configuration space
> + * access.
> + *
> + * The address space has two regions to access configuration - local and remote.
> + * We access local region for bus 0 (as RC is attached on bus 0) and remote
> + * region for others with TYPE 1 access when bus>  1. As for device on bus = 1,
> + * we will do TYPE 0 access as it will be on our secondary bus (logical).
> + * CFG_SETUP is needed only for remote configuration access.
> + */
> +static inline void __iomem *
> +ks_pcie_setup_config_addr(struct keystone_pcie *ks_pcie, u8 bus, u8 device,
> +			  u8 function)
> +{
> +	struct pcie_port *pp =&ks_pcie->pp;
> +	u32 regval;
> +
> +	if (bus == 0)
> +		return pp->dbi_base;
> +
> +	regval = (bus<<  16) | (device<<  8) | function;
> +	/*
> +	 * Since Bus#1 will be a virtual bus, we need to have TYPE0
> +	 * access only.
> +	 * TYPE 1
> +	 */
> +	if (bus != 1)
> +		regval |= BIT(24);
> +
> +	writel(regval, ks_pcie->va_app_base + CFG_SETUP);
> +
> +	return pp->dbi_base + SPACE0_REMOTE_CFG_OFFSET;
> +}
> +
> +int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
> +		unsigned int devfn, int where, int size, u32 *val)
> +{
> +	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
> +	u8 bus_num = bus->number;
> +	void __iomem *addr;
> +	int ret;
> +
> +	addr = ks_pcie_setup_config_addr(ks_pcie, bus_num, PCI_SLOT(devfn),
> +					 PCI_FUNC(devfn));
> +
> +	ret = dw_pcie_cfg_read(addr + (where&  ~0x3), where, size, val);
> +
> +	return ret;
> +}
> +
> +int ks_dw_pcie_wr_other_conf(struct pcie_port *pp,
> +		struct pci_bus *bus, unsigned int devfn, int where,
> +		int size, u32 val)
> +{
> +	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
> +	u8 bus_num = bus->number;
> +	void __iomem *addr;
> +
> +	addr = ks_pcie_setup_config_addr(ks_pcie, bus_num, PCI_SLOT(devfn),
> +					 PCI_FUNC(devfn));
> +	return dw_pcie_cfg_write(addr + (where&  ~0x3), where, size, val);
> +}
> +
> +/**
> + * ks_dw_pcie_set_ib_access() - Setup inbound access
> + *
> + * Configure BAR0 for inbound access. BAR0 is set up in h/w to have
> + * access to PCIESS application register space and just needs to set up
> + * inbound address (mainly used for MSI).
> + */
> +static void ks_dw_pcie_set_ib_access(struct keystone_pcie *ks_pcie)
> +{
> +	struct pcie_port *pp =&ks_pcie->pp;
> +
> +	/* Configure and set up BAR0 */
> +	ks_dw_pcie_set_dbi_mode(ks_pcie->va_app_base);
> +
> +	/* Enable BAR0 */
> +	writel(1, pp->dbi_base + PCI_BASE_ADDRESS_0);
> +	writel(SZ_4K - 1, pp->dbi_base + PCI_BASE_ADDRESS_0);
> +
> +	ks_dw_pcie_clear_dbi_mode(ks_pcie->va_app_base);
> +	 /*
> +	  * For BAR0, just setting bus address for inbound writes (MSI) should
> +	  * be sufficient. Use physical address to avoid any conflicts.
> +	  */
> +	writel(ks_pcie->app.start, pp->dbi_base + PCI_BASE_ADDRESS_0);
> +}
> +
> +/**
> + * ks_dw_pcie_v3_65_scan_bus() - common function to scan bus
> + *
> + * common functin to scan v3_65 dw based pci bus. This also sets inbound access
> + * after scan.
> + */
> +static struct pci_bus *ks_dw_pcie_v3_65_scan_bus(int nr,
> +						 struct pci_sys_data *sys)
> +{
> +	struct pcie_port *pp = sys_to_pcie(sys);
> +	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
> +	struct pci_bus *bus;
> +
> +	bus = dw_pcie_scan_bus(nr, sys);
> +	if (bus)
> +		ks_dw_pcie_set_ib_access(ks_pcie);
> +
> +	return bus;
> +}
> +
> +/**
> + * ks_dw_pcie_link_up() - Check if link up
> + *
> + */
> +int ks_dw_pcie_link_up(struct pcie_port *pp)
> +{
> +	u32 val = readl(pp->dbi_base + DEBUG0);
> +
> +	return (val&  LTSSM_STATE_MASK) == LTSSM_STATE_L0;
> +}
> +
> +void ks_dw_pcie_initiate_link_train(struct keystone_pcie *ks_pcie)
> +{
> +	u32 val;
> +
> +	/* Initiate Link Training.  */
> +	val = readl(ks_pcie->va_app_base + CMD_STATUS);
> +	writel(LTSSM_EN_VAL | val,  ks_pcie->va_app_base + CMD_STATUS);
> +}
> +
> +static struct hw_pci ks_dw_pcie_v3_65_hw = {
> +	.nr_controllers	= 1,
> +	.setup		= dw_pcie_setup,
> +	.scan		= ks_dw_pcie_v3_65_scan_bus,
> +	.add_bus	= dw_pcie_add_bus,
> +	.map_irq	= dw_pcie_map_irq,
> +};
> +
> +/**
> + * ks_dw_pcie_host_init() - initialize host for v3_65 dw hardware
> + *
> + * It ioremap the register resources, initialize legacy irq domain
> + * and then call dw_pcie_v3_65_host_init() API to intialize the Keystone
> + * PCI host controller.
> + *
> + */
> +int __init ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie,
> +				struct device_node *msi_intc_np)
> +{
> +	struct pcie_port *pp =&ks_pcie->pp;
> +	struct platform_device *pdev = to_platform_device(pp->dev);
> +	struct resource *res;
> +
> +	/* index 0 is the config reg. space address */
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	pp->dbi_base = devm_ioremap_resource(pp->dev, res);
> +	if (IS_ERR(pp->dbi_base))
> +		return PTR_ERR(pp->dbi_base);
> +
> +	/* index 1 is the application reg. space address */
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> +	ks_pcie->app = *res;
> +	ks_pcie->va_app_base = devm_ioremap_resource(pp->dev, res);
> +	if (IS_ERR(ks_pcie->va_app_base))
> +		return PTR_ERR(ks_pcie->va_app_base);
> +
> +	/* create legacy irq domain */
> +	ks_pcie->legacy_irq_domain =
> +			irq_domain_add_linear(ks_pcie->legacy_intc_np,
> +					MAX_LEGACY_IRQS,
> +					&ks_dw_pcie_legacy_irq_domian_ops,
> +					NULL);
> +	if (!ks_pcie->legacy_irq_domain) {
> +		dev_err(pp->dev, "Failed to add irq domain for legacy irqs\n");
> +		return -EINVAL;
> +	}
> +
> +	return dw_pcie_v3_65_host_init(pp,&ks_dw_pcie_v3_65_hw, msi_intc_np,
> +					&ks_dw_pcie_msi_domain_ops);
> +}
> diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c
> new file mode 100644
> index 0000000..e1cf671
> --- /dev/null
> +++ b/drivers/pci/host/pci-keystone.c
> @@ -0,0 +1,381 @@
> +/*
> + * PCIe host controller driver for Texas Instruments Keystone SoCs
> + *
> + * Copyright (C) 2013-2014 Texas Instruments., Ltd.
> + *		http://www.ti.com
> + *
> + * Author: Murali Karicheri<m-karicheri2@ti.com>
> + * Implementation based on pci-exynos.c and pcie-designware.c
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include<linux/irqchip/chained_irq.h>
> +#include<linux/clk.h>
> +#include<linux/delay.h>
> +#include<linux/irqdomain.h>
> +#include<linux/module.h>
> +#include<linux/msi.h>
> +#include<linux/of_irq.h>
> +#include<linux/of.h>
> +#include<linux/of_pci.h>
> +#include<linux/platform_device.h>
> +#include<linux/phy/phy.h>
> +#include<linux/resource.h>
> +#include<linux/signal.h>
> +
> +#include "pcie-designware.h"
> +#include "pci-keystone.h"
> +
> +#define DRIVER_NAME	"keystone-pcie"
> +
> +/* driver specific constants */
> +#define MAX_MSI_HOST_IRQS		8
> +#define MAX_LEGACY_HOST_IRQS		4
> +
> +/* RC mode settings */
> +#define PCIE_RC_MODE		(BIT(2))
> +#define PCIE_MODE_MASK		(BIT(1) | BIT(2))
> +
> +/* DEV_STAT_CTRL */
> +#define PCIE_CAP_BASE       0x70
> +
> +#define to_keystone_pcie(x)	container_of(x, struct keystone_pcie, pp)
> +
> +static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie)
> +{
> +	struct pcie_port *pp =&ks_pcie->pp;
> +	int count = 200;
> +
> +	dw_pcie_setup_rc(pp);
> +	if (ks_pcie->link_train)
> +		ks_dw_pcie_initiate_link_train(ks_pcie);
> +
> +	/* check if the link is up or not */
> +	while (!dw_pcie_link_up(pp)) {
> +		usleep_range(100, 1000);
> +		if (--count)
> +			continue;
> +		dev_err(pp->dev, "phy link never came up\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static void ks_pcie_msi_irq_handler(unsigned int irq, struct irq_desc *desc)
> +{
> +	struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
> +	u32 offset = irq - ks_pcie->msi_host_irqs[0];
> +	struct pcie_port *pp =&ks_pcie->pp;
> +	struct irq_chip *chip = irq_desc_get_chip(desc);
> +
> +	dev_dbg(pp->dev, "ks_pci_msi_irq_handler, irq %d\n", irq);
> +
> +	/*
> +	 * The chained irq handler installation would have replaced normal
> +	 * interrupt driver handler so we need to take care of mask/unmask and
> +	 * ack operation.
> +	 */
> +	chained_irq_enter(chip, desc);
> +	ks_dw_pcie_handle_msi_irq(ks_pcie, offset);
> +	chained_irq_exit(chip, desc);
> +}
> +
> +/**
> + * ks_pcie_legacy_irq_handler() - Handle legacy interrupt
> + * @irq: IRQ line for legacy interrupts
> + * @desc: Pointer to irq descriptor
> + *
> + * Traverse through pending legacy interrupts and invoke handler for each. Also
> + * takes care of interrupt controller level mask/ack operation.
> + */
> +static void ks_pcie_legacy_irq_handler(unsigned int irq, struct irq_desc *desc)
> +{
> +	struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
> +	struct pcie_port *pp =&ks_pcie->pp;
> +	u32 irq_offset = irq - ks_pcie->legacy_host_irqs[0];
> +	struct irq_chip *chip = irq_desc_get_chip(desc);
> +
> +	dev_dbg(pp->dev, ": Handling legacy irq %d\n", irq);
> +
> +	/*
> +	 * The chained irq handler installation would have replaced normal
> +	 * interrupt driver handler so we need to take care of mask/unmask and
> +	 * ack operation.
> +	 */
> +	chained_irq_enter(chip, desc);
> +	ks_dw_pcie_handle_legacy_irq(ks_pcie, irq_offset);
> +	chained_irq_exit(chip, desc);
> +}
> +
> +static int ks_pcie_get_irq_controller_info(struct keystone_pcie *ks_pcie,
> +					   char *controller, int *num_irqs)
> +{
> +	int temp, max_host_irqs, legacy = 1, *host_irqs, ret = -EINVAL;
> +	struct device *dev = ks_pcie->pp.dev;
> +	struct device_node *np_pcie = dev->of_node, **np_temp;
> +
> +	if (!strcmp(controller, "msi-interrupt-controller"))
> +		legacy = 0;
> +
> +	if (legacy) {
> +		np_temp =&ks_pcie->legacy_intc_np;
> +		max_host_irqs = MAX_LEGACY_HOST_IRQS;
> +		host_irqs =&ks_pcie->legacy_host_irqs[0];
> +	} else {
> +		np_temp =&ks_pcie->msi_intc_np;
> +		max_host_irqs = MAX_MSI_HOST_IRQS;
> +		host_irqs =&ks_pcie->msi_host_irqs[0];
> +	}
> +
> +	/* interrupt controller is in a child node */
> +	*np_temp = of_find_node_by_name(np_pcie, controller);
> +	if (!(*np_temp)) {
> +		dev_err(dev, "Node for %s is absent\n", controller);
> +		goto out;
> +	}
> +	temp = of_irq_count(*np_temp);
> +	if (!temp)
> +		goto out;
> +	if (temp>  max_host_irqs)
> +		dev_warn(dev, "Too many %s interrupts defined %u\n",
> +			(legacy ? "legacy" : "MSI"), temp);
> +
> +	/*
> +	 * support upto max_host_irqs. In dt from index 0 to 3 (legacy) or 0 to
> +	 * 7 (MSI)
> +	 */
> +	for (temp = 0; temp<  max_host_irqs; temp++) {
> +		host_irqs[temp] = irq_of_parse_and_map(*np_temp, temp);
> +		if (host_irqs[temp]<  0)
> +			break;
> +	}
> +	if (temp) {
> +		*num_irqs = temp;
> +		ret = 0;
> +	}
> +out:
> +	return ret;
> +}
> +
> +static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie)
> +{
> +	int i;
> +
> +	/* Legacy IRQ */
> +	for (i = 0; i<  ks_pcie->num_legacy_host_irqs; i++) {
> +		irq_set_handler_data(ks_pcie->legacy_host_irqs[i], ks_pcie);
> +		irq_set_chained_handler(ks_pcie->legacy_host_irqs[i],
> +					ks_pcie_legacy_irq_handler);
> +	}
> +	ks_dw_pcie_enable_legacy_irqs(ks_pcie);
> +
> +	/* MSI IRQ */
> +	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> +		for (i = 0; i<  ks_pcie->num_msi_host_irqs; i++) {
> +			irq_set_chained_handler(ks_pcie->msi_host_irqs[i],
> +						ks_pcie_msi_irq_handler);
> +			irq_set_handler_data(ks_pcie->msi_host_irqs[i],
> +					     ks_pcie);
> +		}
> +	}
> +}
> +
> +/*
> + * When a PCI device does not exist during config cycles, keystone host gets a
> + * bus error instead of returning 0xffffffff. This handler always returns 0
> + * for this kind of faults.
> + */
> +static int
> +keystone_pcie_fault(unsigned long addr, unsigned int fsr,
> +		struct pt_regs *regs)
> +{
> +	unsigned long instr = *(unsigned long *) instruction_pointer(regs);
> +
> +	if ((instr&  0x0e100090) == 0x00100090) {
> +		int reg = (instr>>  12)&  15;
> +
> +		regs->uregs[reg] = -1;
> +		regs->ARM_pc += 4;
> +	}
> +
> +	return 0;
> +}
> +
> +static void __init ks_pcie_host_init(struct pcie_port *pp)
> +{
> +	u32 vendor_device_id, val;
> +	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
> +
> +	ks_pcie_establish_link(ks_pcie);
> +	ks_dw_pcie_setup_rc_app_regs(ks_pcie);
> +	ks_pcie_setup_interrupts(ks_pcie);
> +	writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32<<  8),
> +			pp->dbi_base + PCI_IO_BASE);
> +
> +	/* update the Vendor ID */
> +	vendor_device_id = readl(ks_pcie->va_reg_pciid);
> +	writew((vendor_device_id>>  16), pp->dbi_base + PCI_DEVICE_ID);
> +
> +	/* update the DEV_STAT_CTRL to publish right mrrs */
> +	val = readl(pp->dbi_base + PCIE_CAP_BASE + PCI_EXP_DEVCTL);
> +	val&= ~PCI_EXP_DEVCTL_READRQ;
> +	/* set the mrrs to 256 bytes */
> +	val |= BIT(12);
> +	writel(val, pp->dbi_base + PCIE_CAP_BASE + PCI_EXP_DEVCTL);
> +
> +	/*
> +	 * PCIe access errors that result into OCP errors are caught by ARM as
> +	 * "External aborts"
> +	 */
> +	hook_fault_code(17, keystone_pcie_fault, SIGBUS, 0,
> +			"Asynchronous external abort");
> +}
> +
> +static struct pcie_host_ops keystone_pcie_host_ops = {
> +	.rd_other_conf = ks_dw_pcie_rd_other_conf,
> +	.wr_other_conf = ks_dw_pcie_wr_other_conf,
> +	.link_up = ks_dw_pcie_link_up,
> +	.host_init = ks_pcie_host_init,
> +	.msi_set_irq = ks_dw_pcie_msi_set_irq,
> +	.msi_clear_irq = ks_dw_pcie_msi_clear_irq,
> +	.get_msi_data = ks_dw_pcie_get_msi_data,
> +};
> +
> +static int add_pcie_port(struct keystone_pcie *ks_pcie,
> +			 struct platform_device *pdev)
> +{
> +	struct pcie_port *pp =&ks_pcie->pp;
> +	int ret;
> +
> +	ret = ks_pcie_get_irq_controller_info(ks_pcie,
> +					"legacy-interrupt-controller",
> +					&ks_pcie->num_legacy_host_irqs);
> +	if (ret)
> +		return ret;
> +
> +	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> +		ret = ks_pcie_get_irq_controller_info(ks_pcie,
> +						"msi-interrupt-controller",
> +						&ks_pcie->num_msi_host_irqs);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	pp->root_bus_nr = -1;
> +	pp->ops =&keystone_pcie_host_ops;
> +	ret = ks_dw_pcie_host_init(ks_pcie, ks_pcie->msi_intc_np);
> +	if (ret) {
> +		dev_err(&pdev->dev, "failed to initialize host\n");
> +		return ret;
> +	}
> +
> +	return ret;
> +}
> +
> +static const struct of_device_id ks_pcie_of_match[] = {
> +	{
> +		.type = "pci",
> +		.compatible = "ti,keystone-pcie",
> +	},
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, ks_pcie_of_match);
> +
> +static int __exit ks_pcie_remove(struct platform_device *pdev)
> +{
> +	struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev);
> +
> +	clk_disable_unprepare(ks_pcie->clk);
> +
> +	return 0;
> +}
> +
> +static int __init ks_pcie_probe(struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	struct device *dev =&pdev->dev;
> +	struct keystone_pcie *ks_pcie;
> +	struct pcie_port *pp;
> +	struct resource *res;
> +	void __iomem *reg_p;
> +	struct phy *phy;
> +	int ret = 0;
> +	u32 val;
> +
> +	ks_pcie = devm_kzalloc(&pdev->dev, sizeof(*ks_pcie),
> +				GFP_KERNEL);
> +	if (!ks_pcie) {
> +		dev_err(dev, "no memory for keystone pcie\n");
> +		return -ENOMEM;
> +	}
> +	pp =&ks_pcie->pp;
> +
> +	/* initialize SerDes Phy if present */
> +	phy = devm_phy_get(dev, "pcie-phy");
> +	if (phy)
> +		ret = phy_init(phy);
> +
> +	/* index 2 is the devcfg register for RC mode settings */
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
> +	reg_p = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(reg_p))
> +		return PTR_ERR(reg_p);
> +
> +	/* enable RC mode in devcfg */
> +	val = readl(reg_p);
> +	val&= ~PCIE_MODE_MASK;
> +	val |= PCIE_RC_MODE;
> +	writel(val, reg_p);
> +
> +	/* index 3 is to read PCI DEVICE_ID */
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
> +	reg_p = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(reg_p))
> +		return PTR_ERR(reg_p);
> +	ks_pcie->va_reg_pciid = reg_p;
> +
> +	/* check if we need to enable link training */
> +	ks_pcie->link_train =
> +		(of_get_property(np, "ti,enable-linktrain", NULL) != NULL);
> +
> +	pp->dev = dev;
> +	platform_set_drvdata(pdev, ks_pcie);
> +	ks_pcie->clk = devm_clk_get(dev, "pcie");
> +	if (IS_ERR(ks_pcie->clk)) {
> +		dev_err(dev, "Failed to get pcie rc clock\n");
> +		return PTR_ERR(ks_pcie->clk);
> +	}
> +	ret = clk_prepare_enable(ks_pcie->clk);
> +	if (ret)
> +		return ret;
> +
> +	ret = add_pcie_port(ks_pcie, pdev);
> +	if (ret<  0)
> +		goto fail_clk;
> +
> +	return 0;
> +fail_clk:
> +	clk_disable_unprepare(ks_pcie->clk);
> +
> +	return ret;
> +}
> +
> +static struct platform_driver ks_pcie_driver __refdata = {
> +	.probe  = ks_pcie_probe,
> +	.remove = __exit_p(ks_pcie_remove),
> +	.driver = {
> +		.name	= "keystone-pcie",
> +		.owner	= THIS_MODULE,
> +		.of_match_table = of_match_ptr(ks_pcie_of_match),
> +	},
> +};
> +
> +module_platform_driver(ks_pcie_driver);
> +
> +MODULE_AUTHOR("Murali Karicheri<m-karicheri2@ti.com>");
> +MODULE_DESCRIPTION("Keystone PCIe host controller driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/pci/host/pci-keystone.h b/drivers/pci/host/pci-keystone.h
> new file mode 100644
> index 0000000..b133f5c
> --- /dev/null
> +++ b/drivers/pci/host/pci-keystone.h
> @@ -0,0 +1,56 @@
> +/*
> + * Keystone PCI Controller's common includes
> + *
> + * Copyright (C) 2013-2014 Texas Instruments., Ltd.
> + *		http://www.ti.com
> + *
> + * Author: Murali Karicheri<m-karicheri2@ti.com>
> + *
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#define MAX_LEGACY_IRQS			4
> +#define MAX_MSI_HOST_IRQS		8
> +#define MAX_LEGACY_HOST_IRQS		4
> +
> +struct keystone_pcie {
> +	struct	clk		*clk;
> +	int			link_train;
> +	struct	pcie_port	pp;
> +	void __iomem		*va_reg_pciid;
> +
> +	int			num_legacy_host_irqs;
> +	int			legacy_host_irqs[MAX_LEGACY_HOST_IRQS];
> +	struct			device_node *legacy_intc_np;
> +
> +	int			num_msi_host_irqs;
> +	int			msi_host_irqs[MAX_MSI_HOST_IRQS];
> +	struct			device_node *msi_intc_np;
> +	struct irq_domain	*legacy_irq_domain;
> +
> +	/* Application register space */
> +	void __iomem		*va_app_base;
> +	struct resource		app;
> +};
> +
> +/* Keystone DW specific MSI controller APIs/definitions */
> +void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset);
> +u32 ks_dw_pcie_get_msi_data(struct pcie_port *pp);
> +
> +/* Keystone specific PCI controller APIs */
> +void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie);
> +void ks_dw_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, int offset);
> +int  ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie,
> +			struct device_node *msi_intc_np);
> +int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
> +		unsigned int devfn, int where, int size, u32 val);
> +int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
> +		unsigned int devfn, int where, int size, u32 *val);
> +void ks_dw_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie);
> +int ks_dw_pcie_link_up(struct pcie_port *pp);
> +void ks_dw_pcie_initiate_link_train(struct keystone_pcie *ks_pcie);
> +void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq);
> +void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq);
DT Maintainers,

Could you provide your comments or Ack for the DT bindings change made 
by this patch?

Murali

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

* Re: [PATCH v3 5/5] PCI: add PCI controller for Keystone PCIe h/w
@ 2014-07-08 13:25     ` Murali Karicheri
  0 siblings, 0 replies; 33+ messages in thread
From: Murali Karicheri @ 2014-07-08 13:25 UTC (permalink / raw)
  To: Murali Karicheri
  Cc: linux-pci, linux-kernel, devicetree, Santosh Shilimkar,
	Russell King, Grant Likely, Rob Herring, Mohit Kumar, Jingoo Han,
	Bjorn Helgaas, Pratyush Anand, Richard Zhu,
	Kishon Vijay Abraham I, Marek Vasut, Arnd Bergmann, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap

On 06/30/2014 05:45 PM, Murali Karicheri wrote:
> Keystone PCIe controller is based on v3.65 version of the
> designware h/w. Main differences are
> 	1. No ATU support
> 	2. Legacy and MSI irq functions are implemented in
> 	   application register space
> 	3. MSI interrupts are multiplexed over 8 IRQ lines to the Host
> 	   side.
> All of the Application register space handing code are organized into
> pci-keystone-dw.c and the functions are called from pci-keystone.c
> to implement PCI controller driver. Also add necessary DT documentation
> for the driver.
>
> Signed-off-by: Murali Karicheri<m-karicheri2@ti.com>
>
> CC: Santosh Shilimkar<santosh.shilimkar@ti.com>
> CC: Russell King<linux@arm.linux.org.uk>
> CC: Grant Likely<grant.likely@linaro.org>
> CC: Rob Herring<robh+dt@kernel.org>
> CC: Mohit Kumar<mohit.kumar@st.com>
> CC: Jingoo Han<jg1.han@samsung.com>
> CC: Bjorn Helgaas<bhelgaas@google.com>
> CC: Pratyush Anand<pratyush.anand@st.com>
> CC: Richard Zhu<r65037@freescale.com>
> CC: Kishon Vijay Abraham I<kishon@ti.com>
> CC: Marek Vasut<marex@denx.de>
> CC: Arnd Bergmann<arnd@arndb.de>
> CC: Pawel Moll<pawel.moll@arm.com>
> CC: Mark Rutland<mark.rutland@arm.com>
> CC: Ian Campbell<ijc+devicetree@hellion.org.uk>
> CC: Kumar Gala<galak@codeaurora.org>
> CC: Randy Dunlap<rdunlap@infradead.org>
> CC: Grant Likely<grant.likely@linaro.org>
> ---
>   .../devicetree/bindings/pci/pci-keystone.txt       |   69 +++
>   drivers/pci/host/Kconfig                           |    5 +
>   drivers/pci/host/Makefile                          |    1 +
>   drivers/pci/host/pci-keystone-dw.c                 |  523 ++++++++++++++++++++
>   drivers/pci/host/pci-keystone.c                    |  381 ++++++++++++++
>   drivers/pci/host/pci-keystone.h                    |   56 +++
>   6 files changed, 1035 insertions(+)
>   create mode 100644 Documentation/devicetree/bindings/pci/pci-keystone.txt
>   create mode 100644 drivers/pci/host/pci-keystone-dw.c
>   create mode 100644 drivers/pci/host/pci-keystone.c
>   create mode 100644 drivers/pci/host/pci-keystone.h
>
> diff --git a/Documentation/devicetree/bindings/pci/pci-keystone.txt b/Documentation/devicetree/bindings/pci/pci-keystone.txt
> new file mode 100644
> index 0000000..bb39601
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/pci-keystone.txt
> @@ -0,0 +1,69 @@
> +TI Keystone PCIe interface
> +
> +Keystone PCI host Controller is based on Designware PCI h/w version 3.65.
> +It shares common functions with PCIE Designware core driver and inherit
> +common properties defined in
> +Documentation/devicetree/bindings/pci/designware-pci.txt
> +Compatibility string "dw,snps-pcie-v3.65" is used to identify the verison
> +of the DW h/w used on Keystone.
> +
> +Please refer to Documentation/devicetree/bindings/pci/designware-pci.txt
> +for the details of designware DT bindings. Additional properties are
> +described here as well propeties that are not applicable.
> +
> +Required Properties:-
> +
> +compatibility: "ti,keystone-pcie"
> +reg:	index 1 is the base address and length of DW application registers.
> +	index 2 is the base address and length of PCI mode configuration
> +	register.
> +	index 3 is the base address and length of PCI device ID register.
> +
> +pcie_msi_intc : Interrupt controller device node for MSI irq chip
> +	interrupt-cells: should be set to 1
> +	interrupt-parent: Parent interrupt controller phandle
> +	interrupts: GIC interrupt lines connected to PCI MSI interrupt lines
> +
> + Example:
> +	pcie_msi_intc: msi-interrupt-controller {
> +			interrupt-controller;
> +			#interrupt-cells =<1>;
> +			interrupt-parent =<&gic>;
> +			interrupts =<GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
> +					<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>,
> +					<GIC_SPI 32 IRQ_TYPE_EDGE_RISING>,
> +					<GIC_SPI 33 IRQ_TYPE_EDGE_RISING>,
> +					<GIC_SPI 34 IRQ_TYPE_EDGE_RISING>,
> +					<GIC_SPI 35 IRQ_TYPE_EDGE_RISING>,
> +					<GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
> +					<GIC_SPI 37 IRQ_TYPE_EDGE_RISING>;
> +	};
> +
> +pcie_intc: Interrupt controller device node for Legacy irq chip
> +	interrupt-cells: should be set to 1
> +	interrupt-parent: Parent interrupt controller phandle
> +	interrupts: GIC interrupt lines connected to PCI Legacy interrupt lines
> +
> + Example:
> +	pcie_intc: legacy-interrupt-controller {
> +		interrupt-controller;
> +		#interrupt-cells =<1>;
> +		interrupt-parent =<&gic>;
> +		interrupts =<GIC_SPI 26 IRQ_TYPE_EDGE_RISING>,
> +			<GIC_SPI 27 IRQ_TYPE_EDGE_RISING>,
> +			<GIC_SPI 28 IRQ_TYPE_EDGE_RISING>,
> +			<GIC_SPI 29 IRQ_TYPE_EDGE_RISING>;
> +	};
> +
> +Optional properties:-
> +	phys: phandle to Generic Keystone SerDes phy for PCI
> +	phy-names: name of the Generic Keystine SerDes phy for PCI
> +	  - If boot loader already does PCI link establishment, then phys and
> +	    phy-names shouldn't be present.
> +	ti,enable-linktrain - Enable Link training.
> +	  - If boot loader already does PCI link establishment, then this
> +	    shouldn't be present.
> +
> +Designware DT Properties not applicable for Keystone PCI
> +
> +1. pcie_bus clock-names not used. Instead, a phandle to phys is used.
> diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
> index 21df477..f8bc475 100644
> --- a/drivers/pci/host/Kconfig
> +++ b/drivers/pci/host/Kconfig
> @@ -46,4 +46,9 @@ config PCI_HOST_GENERIC
>   	  Say Y here if you want to support a simple generic PCI host
>   	  controller, such as the one emulated by kvmtool.
>
> +config PCI_KEYSTONE
> +	bool "TI Keystone PCIe controller"
> +	depends on ARCH_KEYSTONE
> +	select PCIE_DW
> +	select PCIEPORTBUS
>   endmenu
> diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
> index 611ba4b..d1b6ce1 100644
> --- a/drivers/pci/host/Makefile
> +++ b/drivers/pci/host/Makefile
> @@ -6,3 +6,4 @@ obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
>   obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
>   obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o
>   obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o
> +obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o
> diff --git a/drivers/pci/host/pci-keystone-dw.c b/drivers/pci/host/pci-keystone-dw.c
> new file mode 100644
> index 0000000..3b5b075
> --- /dev/null
> +++ b/drivers/pci/host/pci-keystone-dw.c
> @@ -0,0 +1,523 @@
> +/*
> + * Designware application register space functions for Keystone PCI controller
> + *
> + * Copyright (C) 2013-2014 Texas Instruments., Ltd.
> + *		http://www.ti.com
> + *
> + * Author: Murali Karicheri<m-karicheri2@ti.com>
> + *
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include<linux/irq.h>
> +#include<linux/irqdomain.h>
> +#include<linux/module.h>
> +#include<linux/of.h>
> +#include<linux/of_pci.h>
> +#include<linux/pci.h>
> +#include<linux/platform_device.h>
> +
> +#include "pcie-designware.h"
> +#include "pci-keystone.h"
> +
> +/* Application register defines */
> +#define LTSSM_EN_VAL		        BIT(0)
> +#define LTSSM_STATE_MASK	        0x1f
> +#define LTSSM_STATE_L0		        0x11
> +#define DIR_SPD				(1<<  17)
> +#define DBI_CS2_EN_VAL		        BIT(5)
> +#define OB_XLAT_EN_VAL		        BIT(1)
> +
> +/* Application registers */
> +#define CMD_STATUS			0x004
> +#define CFG_SETUP			0x008
> +#define OB_SIZE				0x030
> +#define CFG_PCIM_WIN_SZ_IDX	        3
> +#define CFG_PCIM_WIN_CNT	        32
> +#define SPACE0_REMOTE_CFG_OFFSET	0x1000
> +#define OB_OFFSET_INDEX(n)		(0x200 + (8 * n))
> +#define OB_OFFSET_HI(n)			(0x204 + (8 * n))
> +
> +/* IRQ register defines */
> +#define IRQ_EOI                         0x050
> +#define IRQ_STATUS			0x184
> +#define IRQ_ENABLE_SET			0x188
> +#define IRQ_ENABLE_CLR			0x18c
> +
> +#define MSI_IRQ				0x054
> +#define MSI0_IRQ_STATUS			0x104
> +#define MSI0_IRQ_ENABLE_SET		0x108
> +#define MSI0_IRQ_ENABLE_CLR		0x10c
> +#define IRQ_STATUS			0x184
> +#define MSI_IRQ_OFFSET			4
> +
> +/* Config space registers */
> +#define DEBUG0			        0x728
> +
> +#define to_keystone_pcie(x)	container_of(x, struct keystone_pcie, pp)
> +
> +static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
> +{
> +	return sys->private_data;
> +}
> +
> +static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset,
> +					u32 *bit_pos)
> +{
> +	*reg_offset = offset % 8;
> +	*bit_pos = offset>>  3;
> +}
> +
> +inline u32 ks_dw_pcie_get_msi_data(struct pcie_port *pp)
> +{
> +	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
> +
> +	return ks_pcie->app.start + MSI_IRQ;
> +}
> +
> +void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie , int offset)
> +{
> +	struct pcie_port *pp =&ks_pcie->pp;
> +	u32 pending, vector;
> +	int src, virq;
> +
> +	pending = readl(ks_pcie->va_app_base + MSI0_IRQ_STATUS + (offset<<  4));
> +	/*
> +	 * MSI0, Status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit
> +	 * shows 1, 9, 17, 25 and so forth
> +	 */
> +	for (src = 0; src<  4; src++) {
> +		if (BIT(src)&  pending) {
> +			vector = offset + (src<<  3);
> +			virq = irq_linear_revmap(pp->irq_domain, vector);
> +			dev_dbg(pp->dev,
> +				"irq: bit %d, vector %d, virq %d\n",
> +				 src, vector, virq);
> +			generic_handle_irq(virq);
> +		}
> +	}
> +}
> +
> +static void ks_dw_pcie_msi_irq_ack(struct irq_data *d)
> +{
> +	u32 offset, reg_offset, bit_pos;
> +	struct keystone_pcie *ks_pcie;
> +	unsigned int irq = d->irq;
> +	struct msi_desc *msi;
> +	struct pcie_port *pp;
> +
> +	msi = irq_get_msi_desc(irq);
> +	pp = sys_to_pcie(msi->dev->bus->sysdata);
> +	ks_pcie = to_keystone_pcie(pp);
> +	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
> +	update_reg_offset_bit_pos(offset,&reg_offset,&bit_pos);
> +
> +	writel(BIT(bit_pos),
> +		ks_pcie->va_app_base + MSI0_IRQ_STATUS + (reg_offset<<  4));
> +	writel(reg_offset + MSI_IRQ_OFFSET, ks_pcie->va_app_base + IRQ_EOI);
> +}
> +
> +void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq)
> +{
> +	u32 reg_offset, bit_pos;
> +	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
> +
> +	update_reg_offset_bit_pos(irq,&reg_offset,&bit_pos);
> +	writel(BIT(bit_pos),
> +		ks_pcie->va_app_base + MSI0_IRQ_ENABLE_SET + (reg_offset<<  4));
> +}
> +
> +void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
> +{
> +	u32 reg_offset, bit_pos;
> +	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
> +
> +	update_reg_offset_bit_pos(irq,&reg_offset,&bit_pos);
> +	writel(BIT(bit_pos),
> +		ks_pcie->va_app_base + MSI0_IRQ_ENABLE_CLR + (reg_offset<<  4));
> +}
> +
> +static void ks_dw_pcie_msi_irq_mask(struct irq_data *d)
> +{
> +	struct keystone_pcie *ks_pcie;
> +	unsigned int irq = d->irq;
> +	struct msi_desc *msi;
> +	struct pcie_port *pp;
> +	u32 offset;
> +
> +	msi = irq_get_msi_desc(irq);
> +	pp = sys_to_pcie(msi->dev->bus->sysdata);
> +	ks_pcie = to_keystone_pcie(pp);
> +	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
> +
> +	/* mask the end point if PVM implemented */
> +	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> +		if (msi->msi_attrib.maskbit)
> +			mask_msi_irq(d);
> +	}
> +
> +	ks_dw_pcie_msi_clear_irq(pp, offset);
> +}
> +
> +static void ks_dw_pcie_msi_irq_unmask(struct irq_data *d)
> +{
> +	struct keystone_pcie *ks_pcie;
> +	unsigned int irq = d->irq;
> +	struct msi_desc *msi;
> +	struct pcie_port *pp;
> +	u32 offset;
> +
> +	msi = irq_get_msi_desc(irq);
> +	pp = sys_to_pcie(msi->dev->bus->sysdata);
> +	ks_pcie = to_keystone_pcie(pp);
> +	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
> +
> +	/* mask the end point if PVM implemented */
> +	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> +		if (msi->msi_attrib.maskbit)
> +			unmask_msi_irq(d);
> +	}
> +
> +	ks_dw_pcie_msi_set_irq(pp, offset);
> +}
> +
> +static struct irq_chip ks_dw_pcie_msi_irq_chip = {
> +	.name = "Keystone-PCIe-MSI-IRQ",
> +	.irq_ack = ks_dw_pcie_msi_irq_ack,
> +	.irq_mask = ks_dw_pcie_msi_irq_mask,
> +	.irq_unmask = ks_dw_pcie_msi_irq_unmask,
> +};
> +
> +static int ks_dw_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
> +			irq_hw_number_t hwirq)
> +{
> +	irq_set_chip_and_handler(irq,&ks_dw_pcie_msi_irq_chip,
> +				 handle_level_irq);
> +	irq_set_chip_data(irq, domain->host_data);
> +	set_irq_flags(irq, IRQF_VALID);
> +
> +	return 0;
> +}
> +
> +const struct irq_domain_ops ks_dw_pcie_msi_domain_ops = {
> +	.map = ks_dw_pcie_msi_map,
> +};
> +
> +void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie)
> +{
> +	int i;
> +
> +	for (i = 0; i<  MAX_LEGACY_IRQS; i++)
> +		writel(0x1, ks_pcie->va_app_base + IRQ_ENABLE_SET + (i<<  4));
> +}
> +
> +void ks_dw_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, int offset)
> +{
> +	struct pcie_port *pp =&ks_pcie->pp;
> +	u32 pending;
> +	int virq;
> +
> +	pending = readl(ks_pcie->va_app_base + IRQ_STATUS + (offset<<  4));
> +
> +	if (BIT(0)&  pending) {
> +		virq = irq_linear_revmap(ks_pcie->legacy_irq_domain, offset);
> +		dev_dbg(pp->dev,
> +			": irq: irq_offset %d, virq %d\n", offset, virq);
> +		generic_handle_irq(virq);
> +	}
> +
> +	/* EOI the INTx interrupt */
> +	writel(offset, ks_pcie->va_app_base + IRQ_EOI);
> +}
> +
> +static void ks_dw_pcie_ack_legacy_irq(struct irq_data *d)
> +{
> +}
> +
> +static void ks_dw_pcie_mask_legacy_irq(struct irq_data *d)
> +{
> +}
> +
> +static void ks_dw_pcie_unmask_legacy_irq(struct irq_data *d)
> +{
> +}
> +
> +static struct irq_chip ks_dw_pcie_legacy_irq_chip = {
> +	.name = "Keystone-PCI-Legacy-IRQ",
> +	.irq_ack = ks_dw_pcie_ack_legacy_irq,
> +	.irq_mask = ks_dw_pcie_mask_legacy_irq,
> +	.irq_unmask = ks_dw_pcie_unmask_legacy_irq,
> +};
> +
> +static int ks_dw_pcie_init_legacy_irq_map(struct irq_domain *d,
> +				unsigned int irq, irq_hw_number_t hw_irq)
> +{
> +	irq_set_chip_and_handler(irq,&ks_dw_pcie_legacy_irq_chip,
> +				handle_level_irq);
> +	irq_set_chip_data(irq, d->host_data);
> +	set_irq_flags(irq, IRQF_VALID);
> +
> +	return 0;
> +}
> +
> +static const struct irq_domain_ops ks_dw_pcie_legacy_irq_domian_ops = {
> +	.map = ks_dw_pcie_init_legacy_irq_map,
> +	.xlate = irq_domain_xlate_onetwocell,
> +};
> +
> +/**
> + * ks_dw_pcie_set_dbi_mode() - Set DBI mode to access overlaid BAR mask registers
> + *
> + * Since modification of dbi_cs2 involves different clock domain, read the
> + * status back to ensure the transition is complete.
> + */
> +static inline void ks_dw_pcie_set_dbi_mode(void __iomem *reg_virt)
> +{
> +	u32 val;
> +
> +	writel(DBI_CS2_EN_VAL | readl(reg_virt + CMD_STATUS),
> +		     reg_virt + CMD_STATUS);
> +
> +	do {
> +		val = readl(reg_virt + CMD_STATUS);
> +	} while (!(val&  DBI_CS2_EN_VAL));
> +}
> +
> +/**
> + * ks_dw_pcie_clear_dbi_mode() - Disable DBI mode
> + *
> + * Since modification of dbi_cs2 involves different clock domain, read the
> + * status back to ensure the transition is complete.
> + */
> +static inline void ks_dw_pcie_clear_dbi_mode(void __iomem *reg_virt)
> +{
> +	u32 val;
> +
> +	writel(~DBI_CS2_EN_VAL&  readl(reg_virt + CMD_STATUS),
> +		     reg_virt + CMD_STATUS);
> +
> +	do {
> +		val = readl(reg_virt + CMD_STATUS);
> +	} while (val&  DBI_CS2_EN_VAL);
> +}
> +
> +void ks_dw_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie)
> +{
> +	struct pcie_port *pp =&ks_pcie->pp;
> +	u32 start = pp->mem.start, end = pp->mem.end;
> +	int i, tr_size;
> +
> +	/* disable BARS for inbound access */
> +	ks_dw_pcie_set_dbi_mode(ks_pcie->va_app_base);
> +	writel(0, pp->dbi_base + PCI_BASE_ADDRESS_0);
> +	writel(0, pp->dbi_base + PCI_BASE_ADDRESS_1);
> +	ks_dw_pcie_clear_dbi_mode(ks_pcie->va_app_base);
> +
> +	/* Set outbound translation size per window division */
> +	writel(CFG_PCIM_WIN_SZ_IDX&  0x7, ks_pcie->va_app_base + OB_SIZE);
> +
> +	tr_size = (1<<  (CFG_PCIM_WIN_SZ_IDX&  0x7)) * SZ_1M;
> +
> +	/* Using Direct 1:1 mapping of RC<->  PCI memory space */
> +	for (i = 0; (i<  CFG_PCIM_WIN_CNT)&&  (start<  end); i++) {
> +		writel(start | 1, ks_pcie->va_app_base + OB_OFFSET_INDEX(i));
> +		writel(0, ks_pcie->va_app_base + OB_OFFSET_HI(i));
> +		start += tr_size;
> +	}
> +
> +	/* Enable OB translation */
> +	writel(OB_XLAT_EN_VAL | readl(ks_pcie->va_app_base + CMD_STATUS),
> +		ks_pcie->va_app_base + CMD_STATUS);
> +}
> +
> +/**
> + * ks_pcie_setup_config_addr() - Set up configuration space address for a
> + * device
> + *
> + * @ks_pcie: ptr to keystone_pcie structure
> + * @bus: Bus number the device is residing on
> + * @device: Device number
> + * @function: Function number in device
> + *
> + * Forms and returns the address of configuration space mapped in PCIESS
> + * address space 0. Also configures CFG_SETUP for remote configuration space
> + * access.
> + *
> + * The address space has two regions to access configuration - local and remote.
> + * We access local region for bus 0 (as RC is attached on bus 0) and remote
> + * region for others with TYPE 1 access when bus>  1. As for device on bus = 1,
> + * we will do TYPE 0 access as it will be on our secondary bus (logical).
> + * CFG_SETUP is needed only for remote configuration access.
> + */
> +static inline void __iomem *
> +ks_pcie_setup_config_addr(struct keystone_pcie *ks_pcie, u8 bus, u8 device,
> +			  u8 function)
> +{
> +	struct pcie_port *pp =&ks_pcie->pp;
> +	u32 regval;
> +
> +	if (bus == 0)
> +		return pp->dbi_base;
> +
> +	regval = (bus<<  16) | (device<<  8) | function;
> +	/*
> +	 * Since Bus#1 will be a virtual bus, we need to have TYPE0
> +	 * access only.
> +	 * TYPE 1
> +	 */
> +	if (bus != 1)
> +		regval |= BIT(24);
> +
> +	writel(regval, ks_pcie->va_app_base + CFG_SETUP);
> +
> +	return pp->dbi_base + SPACE0_REMOTE_CFG_OFFSET;
> +}
> +
> +int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
> +		unsigned int devfn, int where, int size, u32 *val)
> +{
> +	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
> +	u8 bus_num = bus->number;
> +	void __iomem *addr;
> +	int ret;
> +
> +	addr = ks_pcie_setup_config_addr(ks_pcie, bus_num, PCI_SLOT(devfn),
> +					 PCI_FUNC(devfn));
> +
> +	ret = dw_pcie_cfg_read(addr + (where&  ~0x3), where, size, val);
> +
> +	return ret;
> +}
> +
> +int ks_dw_pcie_wr_other_conf(struct pcie_port *pp,
> +		struct pci_bus *bus, unsigned int devfn, int where,
> +		int size, u32 val)
> +{
> +	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
> +	u8 bus_num = bus->number;
> +	void __iomem *addr;
> +
> +	addr = ks_pcie_setup_config_addr(ks_pcie, bus_num, PCI_SLOT(devfn),
> +					 PCI_FUNC(devfn));
> +	return dw_pcie_cfg_write(addr + (where&  ~0x3), where, size, val);
> +}
> +
> +/**
> + * ks_dw_pcie_set_ib_access() - Setup inbound access
> + *
> + * Configure BAR0 for inbound access. BAR0 is set up in h/w to have
> + * access to PCIESS application register space and just needs to set up
> + * inbound address (mainly used for MSI).
> + */
> +static void ks_dw_pcie_set_ib_access(struct keystone_pcie *ks_pcie)
> +{
> +	struct pcie_port *pp =&ks_pcie->pp;
> +
> +	/* Configure and set up BAR0 */
> +	ks_dw_pcie_set_dbi_mode(ks_pcie->va_app_base);
> +
> +	/* Enable BAR0 */
> +	writel(1, pp->dbi_base + PCI_BASE_ADDRESS_0);
> +	writel(SZ_4K - 1, pp->dbi_base + PCI_BASE_ADDRESS_0);
> +
> +	ks_dw_pcie_clear_dbi_mode(ks_pcie->va_app_base);
> +	 /*
> +	  * For BAR0, just setting bus address for inbound writes (MSI) should
> +	  * be sufficient. Use physical address to avoid any conflicts.
> +	  */
> +	writel(ks_pcie->app.start, pp->dbi_base + PCI_BASE_ADDRESS_0);
> +}
> +
> +/**
> + * ks_dw_pcie_v3_65_scan_bus() - common function to scan bus
> + *
> + * common functin to scan v3_65 dw based pci bus. This also sets inbound access
> + * after scan.
> + */
> +static struct pci_bus *ks_dw_pcie_v3_65_scan_bus(int nr,
> +						 struct pci_sys_data *sys)
> +{
> +	struct pcie_port *pp = sys_to_pcie(sys);
> +	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
> +	struct pci_bus *bus;
> +
> +	bus = dw_pcie_scan_bus(nr, sys);
> +	if (bus)
> +		ks_dw_pcie_set_ib_access(ks_pcie);
> +
> +	return bus;
> +}
> +
> +/**
> + * ks_dw_pcie_link_up() - Check if link up
> + *
> + */
> +int ks_dw_pcie_link_up(struct pcie_port *pp)
> +{
> +	u32 val = readl(pp->dbi_base + DEBUG0);
> +
> +	return (val&  LTSSM_STATE_MASK) == LTSSM_STATE_L0;
> +}
> +
> +void ks_dw_pcie_initiate_link_train(struct keystone_pcie *ks_pcie)
> +{
> +	u32 val;
> +
> +	/* Initiate Link Training.  */
> +	val = readl(ks_pcie->va_app_base + CMD_STATUS);
> +	writel(LTSSM_EN_VAL | val,  ks_pcie->va_app_base + CMD_STATUS);
> +}
> +
> +static struct hw_pci ks_dw_pcie_v3_65_hw = {
> +	.nr_controllers	= 1,
> +	.setup		= dw_pcie_setup,
> +	.scan		= ks_dw_pcie_v3_65_scan_bus,
> +	.add_bus	= dw_pcie_add_bus,
> +	.map_irq	= dw_pcie_map_irq,
> +};
> +
> +/**
> + * ks_dw_pcie_host_init() - initialize host for v3_65 dw hardware
> + *
> + * It ioremap the register resources, initialize legacy irq domain
> + * and then call dw_pcie_v3_65_host_init() API to intialize the Keystone
> + * PCI host controller.
> + *
> + */
> +int __init ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie,
> +				struct device_node *msi_intc_np)
> +{
> +	struct pcie_port *pp =&ks_pcie->pp;
> +	struct platform_device *pdev = to_platform_device(pp->dev);
> +	struct resource *res;
> +
> +	/* index 0 is the config reg. space address */
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	pp->dbi_base = devm_ioremap_resource(pp->dev, res);
> +	if (IS_ERR(pp->dbi_base))
> +		return PTR_ERR(pp->dbi_base);
> +
> +	/* index 1 is the application reg. space address */
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> +	ks_pcie->app = *res;
> +	ks_pcie->va_app_base = devm_ioremap_resource(pp->dev, res);
> +	if (IS_ERR(ks_pcie->va_app_base))
> +		return PTR_ERR(ks_pcie->va_app_base);
> +
> +	/* create legacy irq domain */
> +	ks_pcie->legacy_irq_domain =
> +			irq_domain_add_linear(ks_pcie->legacy_intc_np,
> +					MAX_LEGACY_IRQS,
> +					&ks_dw_pcie_legacy_irq_domian_ops,
> +					NULL);
> +	if (!ks_pcie->legacy_irq_domain) {
> +		dev_err(pp->dev, "Failed to add irq domain for legacy irqs\n");
> +		return -EINVAL;
> +	}
> +
> +	return dw_pcie_v3_65_host_init(pp,&ks_dw_pcie_v3_65_hw, msi_intc_np,
> +					&ks_dw_pcie_msi_domain_ops);
> +}
> diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c
> new file mode 100644
> index 0000000..e1cf671
> --- /dev/null
> +++ b/drivers/pci/host/pci-keystone.c
> @@ -0,0 +1,381 @@
> +/*
> + * PCIe host controller driver for Texas Instruments Keystone SoCs
> + *
> + * Copyright (C) 2013-2014 Texas Instruments., Ltd.
> + *		http://www.ti.com
> + *
> + * Author: Murali Karicheri<m-karicheri2@ti.com>
> + * Implementation based on pci-exynos.c and pcie-designware.c
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include<linux/irqchip/chained_irq.h>
> +#include<linux/clk.h>
> +#include<linux/delay.h>
> +#include<linux/irqdomain.h>
> +#include<linux/module.h>
> +#include<linux/msi.h>
> +#include<linux/of_irq.h>
> +#include<linux/of.h>
> +#include<linux/of_pci.h>
> +#include<linux/platform_device.h>
> +#include<linux/phy/phy.h>
> +#include<linux/resource.h>
> +#include<linux/signal.h>
> +
> +#include "pcie-designware.h"
> +#include "pci-keystone.h"
> +
> +#define DRIVER_NAME	"keystone-pcie"
> +
> +/* driver specific constants */
> +#define MAX_MSI_HOST_IRQS		8
> +#define MAX_LEGACY_HOST_IRQS		4
> +
> +/* RC mode settings */
> +#define PCIE_RC_MODE		(BIT(2))
> +#define PCIE_MODE_MASK		(BIT(1) | BIT(2))
> +
> +/* DEV_STAT_CTRL */
> +#define PCIE_CAP_BASE       0x70
> +
> +#define to_keystone_pcie(x)	container_of(x, struct keystone_pcie, pp)
> +
> +static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie)
> +{
> +	struct pcie_port *pp =&ks_pcie->pp;
> +	int count = 200;
> +
> +	dw_pcie_setup_rc(pp);
> +	if (ks_pcie->link_train)
> +		ks_dw_pcie_initiate_link_train(ks_pcie);
> +
> +	/* check if the link is up or not */
> +	while (!dw_pcie_link_up(pp)) {
> +		usleep_range(100, 1000);
> +		if (--count)
> +			continue;
> +		dev_err(pp->dev, "phy link never came up\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static void ks_pcie_msi_irq_handler(unsigned int irq, struct irq_desc *desc)
> +{
> +	struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
> +	u32 offset = irq - ks_pcie->msi_host_irqs[0];
> +	struct pcie_port *pp =&ks_pcie->pp;
> +	struct irq_chip *chip = irq_desc_get_chip(desc);
> +
> +	dev_dbg(pp->dev, "ks_pci_msi_irq_handler, irq %d\n", irq);
> +
> +	/*
> +	 * The chained irq handler installation would have replaced normal
> +	 * interrupt driver handler so we need to take care of mask/unmask and
> +	 * ack operation.
> +	 */
> +	chained_irq_enter(chip, desc);
> +	ks_dw_pcie_handle_msi_irq(ks_pcie, offset);
> +	chained_irq_exit(chip, desc);
> +}
> +
> +/**
> + * ks_pcie_legacy_irq_handler() - Handle legacy interrupt
> + * @irq: IRQ line for legacy interrupts
> + * @desc: Pointer to irq descriptor
> + *
> + * Traverse through pending legacy interrupts and invoke handler for each. Also
> + * takes care of interrupt controller level mask/ack operation.
> + */
> +static void ks_pcie_legacy_irq_handler(unsigned int irq, struct irq_desc *desc)
> +{
> +	struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
> +	struct pcie_port *pp =&ks_pcie->pp;
> +	u32 irq_offset = irq - ks_pcie->legacy_host_irqs[0];
> +	struct irq_chip *chip = irq_desc_get_chip(desc);
> +
> +	dev_dbg(pp->dev, ": Handling legacy irq %d\n", irq);
> +
> +	/*
> +	 * The chained irq handler installation would have replaced normal
> +	 * interrupt driver handler so we need to take care of mask/unmask and
> +	 * ack operation.
> +	 */
> +	chained_irq_enter(chip, desc);
> +	ks_dw_pcie_handle_legacy_irq(ks_pcie, irq_offset);
> +	chained_irq_exit(chip, desc);
> +}
> +
> +static int ks_pcie_get_irq_controller_info(struct keystone_pcie *ks_pcie,
> +					   char *controller, int *num_irqs)
> +{
> +	int temp, max_host_irqs, legacy = 1, *host_irqs, ret = -EINVAL;
> +	struct device *dev = ks_pcie->pp.dev;
> +	struct device_node *np_pcie = dev->of_node, **np_temp;
> +
> +	if (!strcmp(controller, "msi-interrupt-controller"))
> +		legacy = 0;
> +
> +	if (legacy) {
> +		np_temp =&ks_pcie->legacy_intc_np;
> +		max_host_irqs = MAX_LEGACY_HOST_IRQS;
> +		host_irqs =&ks_pcie->legacy_host_irqs[0];
> +	} else {
> +		np_temp =&ks_pcie->msi_intc_np;
> +		max_host_irqs = MAX_MSI_HOST_IRQS;
> +		host_irqs =&ks_pcie->msi_host_irqs[0];
> +	}
> +
> +	/* interrupt controller is in a child node */
> +	*np_temp = of_find_node_by_name(np_pcie, controller);
> +	if (!(*np_temp)) {
> +		dev_err(dev, "Node for %s is absent\n", controller);
> +		goto out;
> +	}
> +	temp = of_irq_count(*np_temp);
> +	if (!temp)
> +		goto out;
> +	if (temp>  max_host_irqs)
> +		dev_warn(dev, "Too many %s interrupts defined %u\n",
> +			(legacy ? "legacy" : "MSI"), temp);
> +
> +	/*
> +	 * support upto max_host_irqs. In dt from index 0 to 3 (legacy) or 0 to
> +	 * 7 (MSI)
> +	 */
> +	for (temp = 0; temp<  max_host_irqs; temp++) {
> +		host_irqs[temp] = irq_of_parse_and_map(*np_temp, temp);
> +		if (host_irqs[temp]<  0)
> +			break;
> +	}
> +	if (temp) {
> +		*num_irqs = temp;
> +		ret = 0;
> +	}
> +out:
> +	return ret;
> +}
> +
> +static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie)
> +{
> +	int i;
> +
> +	/* Legacy IRQ */
> +	for (i = 0; i<  ks_pcie->num_legacy_host_irqs; i++) {
> +		irq_set_handler_data(ks_pcie->legacy_host_irqs[i], ks_pcie);
> +		irq_set_chained_handler(ks_pcie->legacy_host_irqs[i],
> +					ks_pcie_legacy_irq_handler);
> +	}
> +	ks_dw_pcie_enable_legacy_irqs(ks_pcie);
> +
> +	/* MSI IRQ */
> +	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> +		for (i = 0; i<  ks_pcie->num_msi_host_irqs; i++) {
> +			irq_set_chained_handler(ks_pcie->msi_host_irqs[i],
> +						ks_pcie_msi_irq_handler);
> +			irq_set_handler_data(ks_pcie->msi_host_irqs[i],
> +					     ks_pcie);
> +		}
> +	}
> +}
> +
> +/*
> + * When a PCI device does not exist during config cycles, keystone host gets a
> + * bus error instead of returning 0xffffffff. This handler always returns 0
> + * for this kind of faults.
> + */
> +static int
> +keystone_pcie_fault(unsigned long addr, unsigned int fsr,
> +		struct pt_regs *regs)
> +{
> +	unsigned long instr = *(unsigned long *) instruction_pointer(regs);
> +
> +	if ((instr&  0x0e100090) == 0x00100090) {
> +		int reg = (instr>>  12)&  15;
> +
> +		regs->uregs[reg] = -1;
> +		regs->ARM_pc += 4;
> +	}
> +
> +	return 0;
> +}
> +
> +static void __init ks_pcie_host_init(struct pcie_port *pp)
> +{
> +	u32 vendor_device_id, val;
> +	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
> +
> +	ks_pcie_establish_link(ks_pcie);
> +	ks_dw_pcie_setup_rc_app_regs(ks_pcie);
> +	ks_pcie_setup_interrupts(ks_pcie);
> +	writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32<<  8),
> +			pp->dbi_base + PCI_IO_BASE);
> +
> +	/* update the Vendor ID */
> +	vendor_device_id = readl(ks_pcie->va_reg_pciid);
> +	writew((vendor_device_id>>  16), pp->dbi_base + PCI_DEVICE_ID);
> +
> +	/* update the DEV_STAT_CTRL to publish right mrrs */
> +	val = readl(pp->dbi_base + PCIE_CAP_BASE + PCI_EXP_DEVCTL);
> +	val&= ~PCI_EXP_DEVCTL_READRQ;
> +	/* set the mrrs to 256 bytes */
> +	val |= BIT(12);
> +	writel(val, pp->dbi_base + PCIE_CAP_BASE + PCI_EXP_DEVCTL);
> +
> +	/*
> +	 * PCIe access errors that result into OCP errors are caught by ARM as
> +	 * "External aborts"
> +	 */
> +	hook_fault_code(17, keystone_pcie_fault, SIGBUS, 0,
> +			"Asynchronous external abort");
> +}
> +
> +static struct pcie_host_ops keystone_pcie_host_ops = {
> +	.rd_other_conf = ks_dw_pcie_rd_other_conf,
> +	.wr_other_conf = ks_dw_pcie_wr_other_conf,
> +	.link_up = ks_dw_pcie_link_up,
> +	.host_init = ks_pcie_host_init,
> +	.msi_set_irq = ks_dw_pcie_msi_set_irq,
> +	.msi_clear_irq = ks_dw_pcie_msi_clear_irq,
> +	.get_msi_data = ks_dw_pcie_get_msi_data,
> +};
> +
> +static int add_pcie_port(struct keystone_pcie *ks_pcie,
> +			 struct platform_device *pdev)
> +{
> +	struct pcie_port *pp =&ks_pcie->pp;
> +	int ret;
> +
> +	ret = ks_pcie_get_irq_controller_info(ks_pcie,
> +					"legacy-interrupt-controller",
> +					&ks_pcie->num_legacy_host_irqs);
> +	if (ret)
> +		return ret;
> +
> +	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> +		ret = ks_pcie_get_irq_controller_info(ks_pcie,
> +						"msi-interrupt-controller",
> +						&ks_pcie->num_msi_host_irqs);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	pp->root_bus_nr = -1;
> +	pp->ops =&keystone_pcie_host_ops;
> +	ret = ks_dw_pcie_host_init(ks_pcie, ks_pcie->msi_intc_np);
> +	if (ret) {
> +		dev_err(&pdev->dev, "failed to initialize host\n");
> +		return ret;
> +	}
> +
> +	return ret;
> +}
> +
> +static const struct of_device_id ks_pcie_of_match[] = {
> +	{
> +		.type = "pci",
> +		.compatible = "ti,keystone-pcie",
> +	},
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, ks_pcie_of_match);
> +
> +static int __exit ks_pcie_remove(struct platform_device *pdev)
> +{
> +	struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev);
> +
> +	clk_disable_unprepare(ks_pcie->clk);
> +
> +	return 0;
> +}
> +
> +static int __init ks_pcie_probe(struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	struct device *dev =&pdev->dev;
> +	struct keystone_pcie *ks_pcie;
> +	struct pcie_port *pp;
> +	struct resource *res;
> +	void __iomem *reg_p;
> +	struct phy *phy;
> +	int ret = 0;
> +	u32 val;
> +
> +	ks_pcie = devm_kzalloc(&pdev->dev, sizeof(*ks_pcie),
> +				GFP_KERNEL);
> +	if (!ks_pcie) {
> +		dev_err(dev, "no memory for keystone pcie\n");
> +		return -ENOMEM;
> +	}
> +	pp =&ks_pcie->pp;
> +
> +	/* initialize SerDes Phy if present */
> +	phy = devm_phy_get(dev, "pcie-phy");
> +	if (phy)
> +		ret = phy_init(phy);
> +
> +	/* index 2 is the devcfg register for RC mode settings */
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
> +	reg_p = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(reg_p))
> +		return PTR_ERR(reg_p);
> +
> +	/* enable RC mode in devcfg */
> +	val = readl(reg_p);
> +	val&= ~PCIE_MODE_MASK;
> +	val |= PCIE_RC_MODE;
> +	writel(val, reg_p);
> +
> +	/* index 3 is to read PCI DEVICE_ID */
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
> +	reg_p = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(reg_p))
> +		return PTR_ERR(reg_p);
> +	ks_pcie->va_reg_pciid = reg_p;
> +
> +	/* check if we need to enable link training */
> +	ks_pcie->link_train =
> +		(of_get_property(np, "ti,enable-linktrain", NULL) != NULL);
> +
> +	pp->dev = dev;
> +	platform_set_drvdata(pdev, ks_pcie);
> +	ks_pcie->clk = devm_clk_get(dev, "pcie");
> +	if (IS_ERR(ks_pcie->clk)) {
> +		dev_err(dev, "Failed to get pcie rc clock\n");
> +		return PTR_ERR(ks_pcie->clk);
> +	}
> +	ret = clk_prepare_enable(ks_pcie->clk);
> +	if (ret)
> +		return ret;
> +
> +	ret = add_pcie_port(ks_pcie, pdev);
> +	if (ret<  0)
> +		goto fail_clk;
> +
> +	return 0;
> +fail_clk:
> +	clk_disable_unprepare(ks_pcie->clk);
> +
> +	return ret;
> +}
> +
> +static struct platform_driver ks_pcie_driver __refdata = {
> +	.probe  = ks_pcie_probe,
> +	.remove = __exit_p(ks_pcie_remove),
> +	.driver = {
> +		.name	= "keystone-pcie",
> +		.owner	= THIS_MODULE,
> +		.of_match_table = of_match_ptr(ks_pcie_of_match),
> +	},
> +};
> +
> +module_platform_driver(ks_pcie_driver);
> +
> +MODULE_AUTHOR("Murali Karicheri<m-karicheri2@ti.com>");
> +MODULE_DESCRIPTION("Keystone PCIe host controller driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/pci/host/pci-keystone.h b/drivers/pci/host/pci-keystone.h
> new file mode 100644
> index 0000000..b133f5c
> --- /dev/null
> +++ b/drivers/pci/host/pci-keystone.h
> @@ -0,0 +1,56 @@
> +/*
> + * Keystone PCI Controller's common includes
> + *
> + * Copyright (C) 2013-2014 Texas Instruments., Ltd.
> + *		http://www.ti.com
> + *
> + * Author: Murali Karicheri<m-karicheri2@ti.com>
> + *
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#define MAX_LEGACY_IRQS			4
> +#define MAX_MSI_HOST_IRQS		8
> +#define MAX_LEGACY_HOST_IRQS		4
> +
> +struct keystone_pcie {
> +	struct	clk		*clk;
> +	int			link_train;
> +	struct	pcie_port	pp;
> +	void __iomem		*va_reg_pciid;
> +
> +	int			num_legacy_host_irqs;
> +	int			legacy_host_irqs[MAX_LEGACY_HOST_IRQS];
> +	struct			device_node *legacy_intc_np;
> +
> +	int			num_msi_host_irqs;
> +	int			msi_host_irqs[MAX_MSI_HOST_IRQS];
> +	struct			device_node *msi_intc_np;
> +	struct irq_domain	*legacy_irq_domain;
> +
> +	/* Application register space */
> +	void __iomem		*va_app_base;
> +	struct resource		app;
> +};
> +
> +/* Keystone DW specific MSI controller APIs/definitions */
> +void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset);
> +u32 ks_dw_pcie_get_msi_data(struct pcie_port *pp);
> +
> +/* Keystone specific PCI controller APIs */
> +void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie);
> +void ks_dw_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, int offset);
> +int  ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie,
> +			struct device_node *msi_intc_np);
> +int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
> +		unsigned int devfn, int where, int size, u32 val);
> +int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
> +		unsigned int devfn, int where, int size, u32 *val);
> +void ks_dw_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie);
> +int ks_dw_pcie_link_up(struct pcie_port *pp);
> +void ks_dw_pcie_initiate_link_train(struct keystone_pcie *ks_pcie);
> +void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq);
> +void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq);
DT Maintainers,

Could you provide your comments or Ack for the DT bindings change made 
by this patch?

Murali

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

* Re: [PATCH v3 3/5] PCI: designware: refactor host init code to re-use on keystone PCI
  2014-07-08 13:20     ` Murali Karicheri
  (?)
@ 2014-07-08 13:31     ` Jingoo Han
  -1 siblings, 0 replies; 33+ messages in thread
From: Jingoo Han @ 2014-07-08 13:31 UTC (permalink / raw)
  To: 'Murali Karicheri', 'Mohit Kumar'
  Cc: linux-pci, linux-kernel, devicetree, 'Santosh Shilimkar',
	'Russell King', 'Grant Likely',
	'Rob Herring', 'Bjorn Helgaas',
	'Pratyush Anand', 'Richard Zhu',
	'Kishon Vijay Abraham I', 'Marek Vasut',
	'Arnd Bergmann', 'Pawel Moll',
	'Mark Rutland', 'Ian Campbell',
	'Kumar Gala', 'Randy Dunlap',
	'Jingoo Han'

On Tuesday, July 08, 2014 10:21 PM, Murali Karicheri wrote:
> 
> Mohit, Jingoo,
> 
> Thanks for the Ack for 1/5 and 2/5 of this series.
> 
> Could you also review 3/5 and 4/5 of this series and provide your Ack or
> comments at the earliest.

Sorry, I cannot review 3/5 and 4/5.

For a few years, I have done mainline work without any payment,
as other hobbyists have done. It means that it is very hard to
spend reviewing the patch from mailing list. Currently, I am up to
my neck in work. In the case of 3/5 and 4/5 of your patchset,
it requires me to spend a lot of time.

I will go the extra miles to review all patches including your
patches. But, I am not sure that I can do it. Thank you.

Best regards,
Jingoo Han
> 
> Thanks and regards,
> 
> Murali
> 
> On 06/30/2014 05:45 PM, Murali Karicheri wrote:
> > This patch refactor the host controller init code to support Keystone
> > PCI controller.
> >
> > Current DW PCI host controller init code has code specific to newer
> > DW hw such as ATU port resource parse and ioremap. Conditionally
> > execute this code if DW h/w is not v3.65. Keystone PCI controller
> > is based on v3.65 DW PCI h/w and it has MSI controller implemented
> > in application space and requires different controller initialization
> > code. So factor out the MSI host init code to a separate function.
> >
> > Rename dw_pcie_host_init() to dw_pcie_common_host_init() that takes an
> > additional arg, ptr to hw_pci structure. This allows to re-use the code
> > for Keystone PCI that can now provide it's own pci hw ops and msi irq
> > ops.  dw_pcie_host_init() is now a wrapper function that calls
> > dw_pcie_common_host_init() for pci common initialization.
> >
> > Signed-off-by: Murali Karicheri<m-karicheri2@ti.com>
> >
> > CC: Santosh Shilimkar<santosh.shilimkar@ti.com>
> > CC: Russell King<linux@arm.linux.org.uk>
> > CC: Grant Likely<grant.likely@linaro.org>
> > CC: Rob Herring<robh+dt@kernel.org>
> > CC: Mohit Kumar<mohit.kumar@st.com>
> > CC: Jingoo Han<jg1.han@samsung.com>
> > CC: Bjorn Helgaas<bhelgaas@google.com>
> > CC: Pratyush Anand<pratyush.anand@st.com>
> > CC: Richard Zhu<r65037@freescale.com>
> > CC: Kishon Vijay Abraham I<kishon@ti.com>
> > CC: Marek Vasut<marex@denx.de>
> > CC: Arnd Bergmann<arnd@arndb.de>
> > CC: Pawel Moll<pawel.moll@arm.com>
> > CC: Mark Rutland<mark.rutland@arm.com>
> > CC: Ian Campbell<ijc+devicetree@hellion.org.uk>
> > CC: Kumar Gala<galak@codeaurora.org>
> > CC: Randy Dunlap<rdunlap@infradead.org>
> > CC: Grant Likely<grant.likely@linaro.org>
> > ---
> >   drivers/pci/host/pcie-designware.c |  105 +++++++++++++++++++++++++-----------
> >   drivers/pci/host/pcie-designware.h |    3 +-
> >   2 files changed, 75 insertions(+), 33 deletions(-)
> >
> > diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
> > index 905941c..c11e4de 100644
> > --- a/drivers/pci/host/pcie-designware.c
> > +++ b/drivers/pci/host/pcie-designware.c
> > @@ -415,19 +415,24 @@ static const struct irq_domain_ops msi_domain_ops = {
> >   	.map = dw_pcie_msi_map,
> >   };
> >
> > -int __init dw_pcie_host_init(struct pcie_port *pp)
> > +static int __init dw_pcie_common_host_init(struct pcie_port *pp,
> > +					   struct hw_pci *hw)
> >   {
> >   	struct device_node *np = pp->dev->of_node;
> >   	struct of_pci_range range;
> >   	struct of_pci_range_parser parser;
> > +	struct hw_pci *pci_hw = hw;
> >   	u32 val;
> > -	int i;
> >
> >   	if (of_pci_range_parser_init(&parser, np)) {
> >   		dev_err(pp->dev, "missing ranges property\n");
> >   		return -EINVAL;
> >   	}
> >
> > +	/* Default to dw_pci if no hw ops provided */
> > +	if (!pci_hw)
> > +		pci_hw =&dw_pci;
> > +
> >   	/* Get the I/O and memory ranges from DT */
> >   	for_each_of_pci_range(&parser,&range) {
> >   		unsigned long restype = range.flags&  IORESOURCE_TYPE_BITS;
> > @@ -467,21 +472,24 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
> >   		}
> >   	}
> >
> > -	pp->cfg0_base = pp->cfg.start;
> > -	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
> >   	pp->mem_base = pp->mem.start;
> > -
> > -	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
> > -					pp->config.cfg0_size);
> > -	if (!pp->va_cfg0_base) {
> > -		dev_err(pp->dev, "error with ioremap in function\n");
> > -		return -ENOMEM;
> > -	}
> > -	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
> > -					pp->config.cfg1_size);
> > -	if (!pp->va_cfg1_base) {
> > -		dev_err(pp->dev, "error with ioremap\n");
> > -		return -ENOMEM;
> > +	if (!pp->version&  DW_HW_V3_65) {
> > +		/* Default is with ATU port. */
> > +		pp->cfg0_base = pp->cfg.start;
> > +		pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
> > +
> > +		pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
> > +						pp->config.cfg0_size);
> > +		if (!pp->va_cfg0_base) {
> > +			dev_err(pp->dev, "error with ioremap in function\n");
> > +			return -ENOMEM;
> > +		}
> > +		pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
> > +						pp->config.cfg1_size);
> > +		if (!pp->va_cfg1_base) {
> > +			dev_err(pp->dev, "error with ioremap\n");
> > +			return -ENOMEM;
> > +		}
> >   	}
> >
> >   	if (of_property_read_u32(np, "num-lanes",&pp->lanes)) {
> > @@ -489,19 +497,6 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
> >   		return -EINVAL;
> >   	}
> >
> > -	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> > -		pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
> > -					MAX_MSI_IRQS,&msi_domain_ops,
> > -					&dw_pcie_msi_chip);
> > -		if (!pp->irq_domain) {
> > -			dev_err(pp->dev, "irq domain init failed\n");
> > -			return -ENXIO;
> > -		}
> > -
> > -		for (i = 0; i<  MAX_MSI_IRQS; i++)
> > -			irq_create_mapping(pp->irq_domain, i);
> > -	}
> > -
> >   	if (pp->ops->host_init)
> >   		pp->ops->host_init(pp);
> >
> > @@ -514,10 +509,10 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
> >   	val |= PORT_LOGIC_SPEED_CHANGE;
> >   	dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
> >
> > -	dw_pci.nr_controllers = 1;
> > -	dw_pci.private_data = (void **)&pp;
> > +	pci_hw->nr_controllers = 1;
> > +	pci_hw->private_data = (void **)&pp;
> >
> > -	pci_common_init_dev(pp->dev,&dw_pci);
> > +	pci_common_init_dev(pp->dev, pci_hw);
> >   	pci_assign_unassigned_resources();
> >   #ifdef CONFIG_PCI_DOMAINS
> >   	dw_pci.domain++;
> > @@ -526,6 +521,52 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
> >   	return 0;
> >   }
> >
> > +/*
> > + * dw_pcie_msi_host_init() - Function to initialize msi host controller
> > + * @pp: ptr to pcie port
> > + * @msi_irqc_np: device node ptr to msi irq controller
> > + * @irq_msi_ops: ptr to MSI irq_domain_ops struct
> > + *
> > + * Function register irq domain for msi irq controller and create mappings
> > + * for MSI irqs.
> > + */
> > +static int dw_pcie_msi_host_init(struct pcie_port *pp,
> > +				 struct device_node *msi_irqc_np,
> > +				 const struct irq_domain_ops *msi_irq_ops)
> > +{
> > +	const struct irq_domain_ops *msi_irq_domain_ops = msi_irq_ops;
> > +	int i;
> > +
> > +	/* Default to  msi_domain_ops if no msi irq domain ops provided */
> > +	if (!msi_irq_domain_ops)
> > +		msi_irq_domain_ops =&msi_domain_ops;
> > +
> > +	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> > +		pp->irq_domain = irq_domain_add_linear(msi_irqc_np,
> > +					MAX_MSI_IRQS, msi_irq_domain_ops,
> > +					&dw_pcie_msi_chip);
> > +		if (!pp->irq_domain) {
> > +			dev_err(pp->dev, "irq domain init failed\n");
> > +			return -ENXIO;
> > +		}
> > +
> > +		for (i = 0; i<  MAX_MSI_IRQS; i++)
> > +			irq_create_mapping(pp->irq_domain, i);
> > +	}
> > +	return 0;
> > +}
> > +
> > +int __init dw_pcie_host_init(struct pcie_port *pp)
> > +{
> > +	int ret;
> > +
> > +	ret = dw_pcie_msi_host_init(pp, pp->dev->of_node, NULL);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return dw_pcie_common_host_init(pp, NULL);
> > +}
> > +
> >   static void dw_pcie_prog_viewport_cfg0(struct pcie_port *pp, u32 busdev)
> >   {
> >   	/* Program viewport 0 : OUTBOUND : CFG0 */
> > diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
> > index 387f69e..db0260f 100644
> > --- a/drivers/pci/host/pcie-designware.h
> > +++ b/drivers/pci/host/pcie-designware.h
> > @@ -51,6 +51,8 @@ struct pcie_port {
> >   	int			msi_irq;
> >   	struct irq_domain	*irq_domain;
> >   	unsigned long		msi_data;
> > +#define DW_HW_V3_65		BIT(0)
> > +	u32			version;
> >   	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
> >   };
> >
> > @@ -79,5 +81,4 @@ void dw_pcie_msi_init(struct pcie_port *pp);
> >   int dw_pcie_link_up(struct pcie_port *pp);
> >   void dw_pcie_setup_rc(struct pcie_port *pp);
> >   int dw_pcie_host_init(struct pcie_port *pp);
> > -
> >   #endif /* _PCIE_DESIGNWARE_H */


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

* Re: [PATCH v3 0/5] Add Keystone PCIe controller driver
  2014-06-30 21:45 ` Murali Karicheri
@ 2014-07-09 13:52   ` Santosh Shilimkar
  -1 siblings, 0 replies; 33+ messages in thread
From: Santosh Shilimkar @ 2014-07-09 13:52 UTC (permalink / raw)
  To: Murali Karicheri, devicetree
  Cc: linux-pci, linux-kernel, Russell King, Grant Likely, Rob Herring,
	Mohit Kumar, Jingoo Han, Bjorn Helgaas, Pratyush Anand,
	Richard Zhu, Kishon Vijay Abraham I, Marek Vasut, Arnd Bergmann,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap

On Monday 30 June 2014 05:45 PM, Murali Karicheri wrote:
> This patch add PCIe controller driver for Keystone SoCs. This
> is based on v2 of the series posted to the mailing list.
> Keystone PCI controller is based on version 3.65 of the DW
> hardware. This driver re-uses some of the DW core driver
> functions and required modification in some to support
> the old DW h/w based Keystone driver.
> 
> Please review and let me know if you have any comments.
> 
> CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
> CC: Russell King <linux@arm.linux.org.uk>
> CC: Grant Likely <grant.likely@linaro.org>
> CC: Rob Herring <robh+dt@kernel.org>
> CC: Mohit Kumar <mohit.kumar@st.com>
> CC: Jingoo Han <jg1.han@samsung.com>
> CC: Bjorn Helgaas <bhelgaas@google.com>
> CC: Pratyush Anand <pratyush.anand@st.com>
> CC: Richard Zhu <r65037@freescale.com>
> CC: Kishon Vijay Abraham I <kishon@ti.com>
> CC: Marek Vasut <marex@denx.de>
> CC: Arnd Bergmann <arnd@arndb.de>
> CC: Pawel Moll <pawel.moll@arm.com>
> CC: Mark Rutland <mark.rutland@arm.com>
> CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
> CC: Kumar Gala <galak@codeaurora.org>
> CC: Randy Dunlap <rdunlap@infradead.org>
> CC: Grant Likely <grant.likely@linaro.org> 
> 
> Changelog:
> 
> v3
>  - DW application register handling code is now part of
>    Keystone PCI driver. RFC had this code part of Keystone
>    PCI driver, then V1 moved this to a separate file to
>    re-use on other platforms that uses this version of the
>    DW h/w. Then based on comments against v2, this is moved
>    back to Keystone driver.
>  - Keystone SerDes phy driver is removed from this series so that
>    this can be merged independent of that patch
>  - added msi_set_irq()/clear_irq() API's to support Keystone
> 
> V2
>  - Split the designware pcie enhancement patch to multiple
>    patches based on functionality added
>  - Remove the quirk code and add a patch to fix mps/mrss
>    tuning for ARM. Use kernel command line parameter
>    pci=pcie_bus_perf to work with Keystone PCI Controller.
>    Following patch addressed this.
>      [PATCH v1] ARM: pci: add call to pcie_bus_configure_settings()
>  - Add documentation for device tree bindings
>  - Add separate interrupt controller nodes for MSI and Legacy
>    IRQs and use irq map for legacy IRQ
>  - Use compatibility to identify v3.65 version of the DW hardware
>    and use it to customize the designware common code.
>  - Use reg property for configuration space instead of range
>  - Other minor updates based on code inspection. 
> 
> V1
>  - Add an interrupt controller node for Legacy irq chip and use
>    interrupt map/map-mask property to map legacy IRQs A/B/C/D
>  - Add a Phy driver to replace the original serdes driver
>  - Move common application register handling code to a separate
>    file to allow re-use across other platforms that use older
>    DW PCIe h/w
>  - PCI quirk for maximum read request size. Check and override only
>    if the maximum is higher than what controller can handle.
>  - Converted to a module platform driver.
> 
> Murali Karicheri (5):
>   PCI: designware: add rd[wr]_other_conf API
>   PCI: designware: refactor MSI code to work with v3.65 dw hardware
>   PCI: designware: refactor host init code to re-use on keystone PCI
>   PCI: designware: enhance dw core driver to support Keystone PCI host
>     controller
>   PCI: add PCI controller for Keystone PCIe h/w
> 
I haven't given review remarks on public list but had few internal
review discussions with you. So just in case you need some
additional review/ack tags, feel free to include mine.

Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>

Once the driver changes gets merged by Bjorn, I can they
merge the DTS related changes via my tree.

Thanks for all the work Murali !!

Regards,
Santosh

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

* Re: [PATCH v3 0/5] Add Keystone PCIe controller driver
@ 2014-07-09 13:52   ` Santosh Shilimkar
  0 siblings, 0 replies; 33+ messages in thread
From: Santosh Shilimkar @ 2014-07-09 13:52 UTC (permalink / raw)
  To: Murali Karicheri, devicetree
  Cc: linux-pci, linux-kernel, Russell King, Grant Likely, Rob Herring,
	Mohit Kumar, Jingoo Han, Bjorn Helgaas, Pratyush Anand,
	Richard Zhu, Kishon Vijay Abraham I, Marek Vasut, Arnd Bergmann,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap

On Monday 30 June 2014 05:45 PM, Murali Karicheri wrote:
> This patch add PCIe controller driver for Keystone SoCs. This
> is based on v2 of the series posted to the mailing list.
> Keystone PCI controller is based on version 3.65 of the DW
> hardware. This driver re-uses some of the DW core driver
> functions and required modification in some to support
> the old DW h/w based Keystone driver.
> 
> Please review and let me know if you have any comments.
> 
> CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
> CC: Russell King <linux@arm.linux.org.uk>
> CC: Grant Likely <grant.likely@linaro.org>
> CC: Rob Herring <robh+dt@kernel.org>
> CC: Mohit Kumar <mohit.kumar@st.com>
> CC: Jingoo Han <jg1.han@samsung.com>
> CC: Bjorn Helgaas <bhelgaas@google.com>
> CC: Pratyush Anand <pratyush.anand@st.com>
> CC: Richard Zhu <r65037@freescale.com>
> CC: Kishon Vijay Abraham I <kishon@ti.com>
> CC: Marek Vasut <marex@denx.de>
> CC: Arnd Bergmann <arnd@arndb.de>
> CC: Pawel Moll <pawel.moll@arm.com>
> CC: Mark Rutland <mark.rutland@arm.com>
> CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
> CC: Kumar Gala <galak@codeaurora.org>
> CC: Randy Dunlap <rdunlap@infradead.org>
> CC: Grant Likely <grant.likely@linaro.org> 
> 
> Changelog:
> 
> v3
>  - DW application register handling code is now part of
>    Keystone PCI driver. RFC had this code part of Keystone
>    PCI driver, then V1 moved this to a separate file to
>    re-use on other platforms that uses this version of the
>    DW h/w. Then based on comments against v2, this is moved
>    back to Keystone driver.
>  - Keystone SerDes phy driver is removed from this series so that
>    this can be merged independent of that patch
>  - added msi_set_irq()/clear_irq() API's to support Keystone
> 
> V2
>  - Split the designware pcie enhancement patch to multiple
>    patches based on functionality added
>  - Remove the quirk code and add a patch to fix mps/mrss
>    tuning for ARM. Use kernel command line parameter
>    pci=pcie_bus_perf to work with Keystone PCI Controller.
>    Following patch addressed this.
>      [PATCH v1] ARM: pci: add call to pcie_bus_configure_settings()
>  - Add documentation for device tree bindings
>  - Add separate interrupt controller nodes for MSI and Legacy
>    IRQs and use irq map for legacy IRQ
>  - Use compatibility to identify v3.65 version of the DW hardware
>    and use it to customize the designware common code.
>  - Use reg property for configuration space instead of range
>  - Other minor updates based on code inspection. 
> 
> V1
>  - Add an interrupt controller node for Legacy irq chip and use
>    interrupt map/map-mask property to map legacy IRQs A/B/C/D
>  - Add a Phy driver to replace the original serdes driver
>  - Move common application register handling code to a separate
>    file to allow re-use across other platforms that use older
>    DW PCIe h/w
>  - PCI quirk for maximum read request size. Check and override only
>    if the maximum is higher than what controller can handle.
>  - Converted to a module platform driver.
> 
> Murali Karicheri (5):
>   PCI: designware: add rd[wr]_other_conf API
>   PCI: designware: refactor MSI code to work with v3.65 dw hardware
>   PCI: designware: refactor host init code to re-use on keystone PCI
>   PCI: designware: enhance dw core driver to support Keystone PCI host
>     controller
>   PCI: add PCI controller for Keystone PCIe h/w
> 
I haven't given review remarks on public list but had few internal
review discussions with you. So just in case you need some
additional review/ack tags, feel free to include mine.

Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>

Once the driver changes gets merged by Bjorn, I can they
merge the DTS related changes via my tree.

Thanks for all the work Murali !!

Regards,
Santosh

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

end of thread, other threads:[~2014-07-09 13:53 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-30 21:45 [PATCH v3 0/5] Add Keystone PCIe controller driver Murali Karicheri
2014-06-30 21:45 ` Murali Karicheri
2014-06-30 21:45 ` [PATCH v3 1/5] PCI: designware: add rd[wr]_other_conf API Murali Karicheri
2014-06-30 21:45   ` Murali Karicheri
2014-07-07  4:11   ` Mohit KUMAR DCG
2014-07-07 16:53     ` Murali Karicheri
2014-07-08 12:17       ` Jingoo Han
2014-06-30 21:45 ` [PATCH v3 2/5] PCI: designware: refactor MSI code to work with v3.65 dw hardware Murali Karicheri
2014-06-30 21:45   ` Murali Karicheri
2014-07-07  4:17   ` Mohit KUMAR DCG
2014-07-07  4:17     ` Mohit KUMAR DCG
2014-07-07 16:53     ` Murali Karicheri
2014-07-08 12:20       ` Jingoo Han
2014-06-30 21:45 ` [PATCH v3 3/5] PCI: designware: refactor host init code to re-use on keystone PCI Murali Karicheri
2014-06-30 21:45   ` Murali Karicheri
2014-07-08 13:20   ` Murali Karicheri
2014-07-08 13:20     ` Murali Karicheri
2014-07-08 13:31     ` Jingoo Han
2014-06-30 21:45 ` [PATCH v3 4/5] PCI: designware: enhance dw core driver to support Keystone PCI host controller Murali Karicheri
2014-06-30 21:45   ` Murali Karicheri
2014-07-08 13:24   ` Murali Karicheri
2014-07-08 13:24     ` Murali Karicheri
2014-06-30 21:45 ` [PATCH v3 5/5] PCI: add PCI controller for Keystone PCIe h/w Murali Karicheri
2014-06-30 21:45   ` Murali Karicheri
2014-07-05 18:45   ` Bjorn Helgaas
2014-07-08 12:43   ` Jingoo Han
2014-07-08 13:25   ` Murali Karicheri
2014-07-08 13:25     ` Murali Karicheri
2014-07-05 18:23 ` [PATCH v3 0/5] Add Keystone PCIe controller driver Bjorn Helgaas
2014-07-08 12:49   ` Murali Karicheri
2014-07-08 12:49     ` Murali Karicheri
2014-07-09 13:52 ` Santosh Shilimkar
2014-07-09 13:52   ` Santosh Shilimkar

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.