All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 00/14] Add PCIe support to TI's J721E SoC
@ 2020-04-17 12:57 ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: Arnd Bergmann, Greg Kroah-Hartman, linux-arm-kernel, linux-pci,
	devicetree, linux-kernel

TI's J721E SoC uses Cadence PCIe core to implement both RC mode
and EP mode.

The high level features are:
  *) Supports Legacy, MSI and MSI-X interrupt
  *) Supports upto GEN4 speed mode
  *) Supports SR-IOV
  *) Supports multiple physical function
  *) Ability to route all transactions via SMMU

This patch series
  *) Add support in Cadence PCIe core to be used for TI's J721E SoC
  *) Add a driver for J721E PCIe wrapper

v1 of the series can be found @ [1]
v2 of the series can be found @ [2]

Changes from v2:
1) Converting Cadence binding to YAML schema was done as a 
   separate series [3] & [4]. [3] is merged and [4] is
   pending.
2) Included MSI-X support in this series
3) Added link down interrupt handling (only error message)
4) Rebased to latest 5.7-rc1
5) Adapted TI J721E binding to [3] & [4] 

Changes from v1:
1) Added DT schemas cdns-pcie-host.yaml, cdns-pcie-ep.yaml and
   cdns-pcie.yaml for Cadence PCIe core and included it in
   TI's PCIe DT schema.
2) Added cpu_addr_fixup() for Cadence Platform driver.
3) Fixed subject/description/renamed functions as commented by
   Andrew Murray.

[1] -> http://lore.kernel.org/r/20191209092147.22901-1-kishon@ti.com
[2] -> http://lore.kernel.org/r/20200106102058.19183-1-kishon@ti.com
[3] -> http://lore.kernel.org/r/20200305103017.16706-1-kishon@ti.com
[4] -> http://lore.kernel.org/r/20200417114322.31111-1-kishon@ti.com

Alan Douglas (1):
  PCI: cadence: Add MSI-X support to Endpoint driver

Kishon Vijay Abraham I (13):
  PCI: cadence: Fix cdns_pcie_{host|ep}_setup() error path
  linux/kernel.h: Add PTR_ALIGN_DOWN macro
  PCI: cadence: Add support to use custom read and write accessors
  PCI: cadence: Add support to start link and verify link status
  PCI: cadence: Add read/write accessors to perform only 32-bit accesses
  PCI: cadence: Allow pci_host_bridge to have custom pci_ops
  PCI: cadence: Add new *ops* for CPU addr fixup
  PCI: cadence: Fix updating Vendor ID and Subsystem Vendor ID register
  dt-bindings: PCI: Add host mode dt-bindings for TI's J721E SoC
  dt-bindings: PCI: Add EP mode dt-bindings for TI's J721E SoC
  PCI: j721e: Add TI J721E PCIe driver
  misc: pci_endpoint_test: Add J721E in pci_device_id table
  MAINTAINERS: Add Kishon Vijay Abraham I for TI J721E SoC PCIe

 .../bindings/pci/ti,j721e-pci-ep.yaml         |  89 ++++
 .../bindings/pci/ti,j721e-pci-host.yaml       | 113 ++++
 MAINTAINERS                                   |   4 +-
 drivers/misc/pci_endpoint_test.c              |   9 +
 drivers/pci/controller/cadence/Kconfig        |  23 +
 drivers/pci/controller/cadence/Makefile       |   1 +
 drivers/pci/controller/cadence/pci-j721e.c    | 500 ++++++++++++++++++
 .../pci/controller/cadence/pcie-cadence-ep.c  | 129 ++++-
 .../controller/cadence/pcie-cadence-host.c    |  59 ++-
 .../controller/cadence/pcie-cadence-plat.c    |  13 +
 drivers/pci/controller/cadence/pcie-cadence.c |  48 +-
 drivers/pci/controller/cadence/pcie-cadence.h | 158 +++++-
 include/linux/kernel.h                        |   1 +
 13 files changed, 1105 insertions(+), 42 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml
 create mode 100644 Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml
 create mode 100644 drivers/pci/controller/cadence/pci-j721e.c

-- 
2.17.1


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

* [PATCH v3 00/14] Add PCIe support to TI's J721E SoC
@ 2020-04-17 12:57 ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: devicetree, Arnd Bergmann, Greg Kroah-Hartman, linux-kernel,
	linux-pci, linux-arm-kernel

TI's J721E SoC uses Cadence PCIe core to implement both RC mode
and EP mode.

The high level features are:
  *) Supports Legacy, MSI and MSI-X interrupt
  *) Supports upto GEN4 speed mode
  *) Supports SR-IOV
  *) Supports multiple physical function
  *) Ability to route all transactions via SMMU

This patch series
  *) Add support in Cadence PCIe core to be used for TI's J721E SoC
  *) Add a driver for J721E PCIe wrapper

v1 of the series can be found @ [1]
v2 of the series can be found @ [2]

Changes from v2:
1) Converting Cadence binding to YAML schema was done as a 
   separate series [3] & [4]. [3] is merged and [4] is
   pending.
2) Included MSI-X support in this series
3) Added link down interrupt handling (only error message)
4) Rebased to latest 5.7-rc1
5) Adapted TI J721E binding to [3] & [4] 

Changes from v1:
1) Added DT schemas cdns-pcie-host.yaml, cdns-pcie-ep.yaml and
   cdns-pcie.yaml for Cadence PCIe core and included it in
   TI's PCIe DT schema.
2) Added cpu_addr_fixup() for Cadence Platform driver.
3) Fixed subject/description/renamed functions as commented by
   Andrew Murray.

[1] -> http://lore.kernel.org/r/20191209092147.22901-1-kishon@ti.com
[2] -> http://lore.kernel.org/r/20200106102058.19183-1-kishon@ti.com
[3] -> http://lore.kernel.org/r/20200305103017.16706-1-kishon@ti.com
[4] -> http://lore.kernel.org/r/20200417114322.31111-1-kishon@ti.com

Alan Douglas (1):
  PCI: cadence: Add MSI-X support to Endpoint driver

Kishon Vijay Abraham I (13):
  PCI: cadence: Fix cdns_pcie_{host|ep}_setup() error path
  linux/kernel.h: Add PTR_ALIGN_DOWN macro
  PCI: cadence: Add support to use custom read and write accessors
  PCI: cadence: Add support to start link and verify link status
  PCI: cadence: Add read/write accessors to perform only 32-bit accesses
  PCI: cadence: Allow pci_host_bridge to have custom pci_ops
  PCI: cadence: Add new *ops* for CPU addr fixup
  PCI: cadence: Fix updating Vendor ID and Subsystem Vendor ID register
  dt-bindings: PCI: Add host mode dt-bindings for TI's J721E SoC
  dt-bindings: PCI: Add EP mode dt-bindings for TI's J721E SoC
  PCI: j721e: Add TI J721E PCIe driver
  misc: pci_endpoint_test: Add J721E in pci_device_id table
  MAINTAINERS: Add Kishon Vijay Abraham I for TI J721E SoC PCIe

 .../bindings/pci/ti,j721e-pci-ep.yaml         |  89 ++++
 .../bindings/pci/ti,j721e-pci-host.yaml       | 113 ++++
 MAINTAINERS                                   |   4 +-
 drivers/misc/pci_endpoint_test.c              |   9 +
 drivers/pci/controller/cadence/Kconfig        |  23 +
 drivers/pci/controller/cadence/Makefile       |   1 +
 drivers/pci/controller/cadence/pci-j721e.c    | 500 ++++++++++++++++++
 .../pci/controller/cadence/pcie-cadence-ep.c  | 129 ++++-
 .../controller/cadence/pcie-cadence-host.c    |  59 ++-
 .../controller/cadence/pcie-cadence-plat.c    |  13 +
 drivers/pci/controller/cadence/pcie-cadence.c |  48 +-
 drivers/pci/controller/cadence/pcie-cadence.h | 158 +++++-
 include/linux/kernel.h                        |   1 +
 13 files changed, 1105 insertions(+), 42 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml
 create mode 100644 Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml
 create mode 100644 drivers/pci/controller/cadence/pci-j721e.c

-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v3 01/14] PCI: cadence: Fix cdns_pcie_{host|ep}_setup() error path
  2020-04-17 12:57 ` Kishon Vijay Abraham I
@ 2020-04-17 12:57   ` Kishon Vijay Abraham I
  -1 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: Arnd Bergmann, Greg Kroah-Hartman, linux-arm-kernel, linux-pci,
	devicetree, linux-kernel

commit bd22885aa188 ("PCI: cadence: Refactor driver to use as a core
library") while refactoring the Cadence PCIe driver to be used as
library, removed pm_runtime_get_sync() from cdns_pcie_ep_setup()
and cdns_pcie_host_setup() but missed to remove the corresponding
pm_runtime_put_sync() in the error path. Fix it here.

Fixes: bd22885aa188 ("PCI: cadence: Refactor driver to use as a core library")
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/pci/controller/cadence/pcie-cadence-ep.c   | 9 ++-------
 drivers/pci/controller/cadence/pcie-cadence-host.c | 6 +-----
 2 files changed, 3 insertions(+), 12 deletions(-)

diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c
index 1c173dad67d1..1fdae37843ef 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-ep.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c
@@ -8,7 +8,6 @@
 #include <linux/of.h>
 #include <linux/pci-epc.h>
 #include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
 #include <linux/sizes.h>
 
 #include "pcie-cadence.h"
@@ -440,8 +439,7 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
 	epc = devm_pci_epc_create(dev, &cdns_pcie_epc_ops);
 	if (IS_ERR(epc)) {
 		dev_err(dev, "failed to create epc device\n");
-		ret = PTR_ERR(epc);
-		goto err_init;
+		return PTR_ERR(epc);
 	}
 
 	epc_set_drvdata(epc, ep);
@@ -453,7 +451,7 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
 			       resource_size(pcie->mem_res));
 	if (ret < 0) {
 		dev_err(dev, "failed to initialize the memory space\n");
-		goto err_init;
+		return ret;
 	}
 
 	ep->irq_cpu_addr = pci_epc_mem_alloc_addr(epc, &ep->irq_phys_addr,
@@ -472,8 +470,5 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
  free_epc_mem:
 	pci_epc_mem_exit(epc);
 
- err_init:
-	pm_runtime_put_sync(dev);
-
 	return ret;
 }
diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c
index 31e67c9c88cf..465607202bb5 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -7,7 +7,6 @@
 #include <linux/of_address.h>
 #include <linux/of_pci.h>
 #include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
 
 #include "pcie-cadence.h"
 
@@ -259,7 +258,7 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
 
 	ret = cdns_pcie_host_init(dev, &resources, rc);
 	if (ret)
-		goto err_init;
+		return ret;
 
 	list_splice_init(&resources, &bridge->windows);
 	bridge->dev.parent = dev;
@@ -277,8 +276,5 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
  err_host_probe:
 	pci_free_resource_list(&resources);
 
- err_init:
-	pm_runtime_put_sync(dev);
-
 	return ret;
 }
-- 
2.17.1


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

* [PATCH v3 01/14] PCI: cadence: Fix cdns_pcie_{host|ep}_setup() error path
@ 2020-04-17 12:57   ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: devicetree, Arnd Bergmann, Greg Kroah-Hartman, linux-kernel,
	linux-pci, linux-arm-kernel

commit bd22885aa188 ("PCI: cadence: Refactor driver to use as a core
library") while refactoring the Cadence PCIe driver to be used as
library, removed pm_runtime_get_sync() from cdns_pcie_ep_setup()
and cdns_pcie_host_setup() but missed to remove the corresponding
pm_runtime_put_sync() in the error path. Fix it here.

Fixes: bd22885aa188 ("PCI: cadence: Refactor driver to use as a core library")
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/pci/controller/cadence/pcie-cadence-ep.c   | 9 ++-------
 drivers/pci/controller/cadence/pcie-cadence-host.c | 6 +-----
 2 files changed, 3 insertions(+), 12 deletions(-)

diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c
index 1c173dad67d1..1fdae37843ef 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-ep.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c
@@ -8,7 +8,6 @@
 #include <linux/of.h>
 #include <linux/pci-epc.h>
 #include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
 #include <linux/sizes.h>
 
 #include "pcie-cadence.h"
@@ -440,8 +439,7 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
 	epc = devm_pci_epc_create(dev, &cdns_pcie_epc_ops);
 	if (IS_ERR(epc)) {
 		dev_err(dev, "failed to create epc device\n");
-		ret = PTR_ERR(epc);
-		goto err_init;
+		return PTR_ERR(epc);
 	}
 
 	epc_set_drvdata(epc, ep);
@@ -453,7 +451,7 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
 			       resource_size(pcie->mem_res));
 	if (ret < 0) {
 		dev_err(dev, "failed to initialize the memory space\n");
-		goto err_init;
+		return ret;
 	}
 
 	ep->irq_cpu_addr = pci_epc_mem_alloc_addr(epc, &ep->irq_phys_addr,
@@ -472,8 +470,5 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
  free_epc_mem:
 	pci_epc_mem_exit(epc);
 
- err_init:
-	pm_runtime_put_sync(dev);
-
 	return ret;
 }
diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c
index 31e67c9c88cf..465607202bb5 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -7,7 +7,6 @@
 #include <linux/of_address.h>
 #include <linux/of_pci.h>
 #include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
 
 #include "pcie-cadence.h"
 
@@ -259,7 +258,7 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
 
 	ret = cdns_pcie_host_init(dev, &resources, rc);
 	if (ret)
-		goto err_init;
+		return ret;
 
 	list_splice_init(&resources, &bridge->windows);
 	bridge->dev.parent = dev;
@@ -277,8 +276,5 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
  err_host_probe:
 	pci_free_resource_list(&resources);
 
- err_init:
-	pm_runtime_put_sync(dev);
-
 	return ret;
 }
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v3 02/14] linux/kernel.h: Add PTR_ALIGN_DOWN macro
  2020-04-17 12:57 ` Kishon Vijay Abraham I
@ 2020-04-17 12:57   ` Kishon Vijay Abraham I
  -1 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: Arnd Bergmann, Greg Kroah-Hartman, linux-arm-kernel, linux-pci,
	devicetree, linux-kernel

Add a macro for aligning down a pointer. This is useful to get an
aligned register address when a device allows only word access and
doesn't allow half word or byte access.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 include/linux/kernel.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 9b7a8d74a9d6..c3b361b5be54 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -34,6 +34,7 @@
 #define ALIGN_DOWN(x, a)	__ALIGN_KERNEL((x) - ((a) - 1), (a))
 #define __ALIGN_MASK(x, mask)	__ALIGN_KERNEL_MASK((x), (mask))
 #define PTR_ALIGN(p, a)		((typeof(p))ALIGN((unsigned long)(p), (a)))
+#define PTR_ALIGN_DOWN(p, a)	((typeof(p))ALIGN_DOWN((unsigned long)(p), (a)))
 #define IS_ALIGNED(x, a)		(((x) & ((typeof(x))(a) - 1)) == 0)
 
 /* generic data direction definitions */
-- 
2.17.1


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

* [PATCH v3 02/14] linux/kernel.h: Add PTR_ALIGN_DOWN macro
@ 2020-04-17 12:57   ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: devicetree, Arnd Bergmann, Greg Kroah-Hartman, linux-kernel,
	linux-pci, linux-arm-kernel

Add a macro for aligning down a pointer. This is useful to get an
aligned register address when a device allows only word access and
doesn't allow half word or byte access.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 include/linux/kernel.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 9b7a8d74a9d6..c3b361b5be54 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -34,6 +34,7 @@
 #define ALIGN_DOWN(x, a)	__ALIGN_KERNEL((x) - ((a) - 1), (a))
 #define __ALIGN_MASK(x, mask)	__ALIGN_KERNEL_MASK((x), (mask))
 #define PTR_ALIGN(p, a)		((typeof(p))ALIGN((unsigned long)(p), (a)))
+#define PTR_ALIGN_DOWN(p, a)	((typeof(p))ALIGN_DOWN((unsigned long)(p), (a)))
 #define IS_ALIGNED(x, a)		(((x) & ((typeof(x))(a) - 1)) == 0)
 
 /* generic data direction definitions */
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v3 03/14] PCI: cadence: Add support to use custom read and write accessors
  2020-04-17 12:57 ` Kishon Vijay Abraham I
@ 2020-04-17 12:57   ` Kishon Vijay Abraham I
  -1 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: Arnd Bergmann, Greg Kroah-Hartman, linux-arm-kernel, linux-pci,
	devicetree, linux-kernel

Add support to use custom read and write accessors. Platforms that
don't support half word or byte access or any other constraint
while accessing registers can use this feature to populate custom
read and write accessors. These custom accessors are used for both
standard register access and configuration space register access of
the PCIe host bridge.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/pci/controller/cadence/pcie-cadence.h | 107 +++++++++++++++---
 1 file changed, 94 insertions(+), 13 deletions(-)

diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
index df14ad002fe9..70b6b25153e8 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -223,6 +223,11 @@ enum cdns_pcie_msg_routing {
 	MSG_ROUTING_GATHER,
 };
 
+struct cdns_pcie_ops {
+	u32	(*read)(void __iomem *addr, int size);
+	void	(*write)(void __iomem *addr, int size, u32 value);
+};
+
 /**
  * struct cdns_pcie - private data for Cadence PCIe controller drivers
  * @reg_base: IO mapped register base
@@ -239,7 +244,7 @@ struct cdns_pcie {
 	int			phy_count;
 	struct phy		**phy;
 	struct device_link	**link;
-	const struct cdns_pcie_common_ops *ops;
+	const struct cdns_pcie_ops *ops;
 };
 
 /**
@@ -299,69 +304,145 @@ struct cdns_pcie_ep {
 /* Register access */
 static inline void cdns_pcie_writeb(struct cdns_pcie *pcie, u32 reg, u8 value)
 {
-	writeb(value, pcie->reg_base + reg);
+	void __iomem *addr = pcie->reg_base + reg;
+
+	if (pcie->ops && pcie->ops->write) {
+		pcie->ops->write(addr, 0x1, value);
+		return;
+	}
+
+	writeb(value, addr);
 }
 
 static inline void cdns_pcie_writew(struct cdns_pcie *pcie, u32 reg, u16 value)
 {
-	writew(value, pcie->reg_base + reg);
+	void __iomem *addr = pcie->reg_base + reg;
+
+	if (pcie->ops && pcie->ops->write) {
+		pcie->ops->write(addr, 0x2, value);
+		return;
+	}
+
+	writew(value, addr);
 }
 
 static inline void cdns_pcie_writel(struct cdns_pcie *pcie, u32 reg, u32 value)
 {
-	writel(value, pcie->reg_base + reg);
+	void __iomem *addr = pcie->reg_base + reg;
+
+	if (pcie->ops && pcie->ops->write) {
+		pcie->ops->write(addr, 0x4, value);
+		return;
+	}
+
+	writel(value, addr);
 }
 
 static inline u32 cdns_pcie_readl(struct cdns_pcie *pcie, u32 reg)
 {
-	return readl(pcie->reg_base + reg);
+	void __iomem *addr = pcie->reg_base + reg;
+
+	if (pcie->ops && pcie->ops->read)
+		return pcie->ops->read(addr, 0x4);
+
+	return readl(addr);
 }
 
 /* Root Port register access */
 static inline void cdns_pcie_rp_writeb(struct cdns_pcie *pcie,
 				       u32 reg, u8 value)
 {
-	writeb(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
+	void __iomem *addr = pcie->reg_base + CDNS_PCIE_RP_BASE + reg;
+
+	if (pcie->ops && pcie->ops->write) {
+		pcie->ops->write(addr, 0x1, value);
+		return;
+	}
+
+	writeb(value, addr);
 }
 
 static inline void cdns_pcie_rp_writew(struct cdns_pcie *pcie,
 				       u32 reg, u16 value)
 {
-	writew(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
+	void __iomem *addr = pcie->reg_base + CDNS_PCIE_RP_BASE + reg;
+
+	if (pcie->ops && pcie->ops->write) {
+		pcie->ops->write(addr, 0x2, value);
+		return;
+	}
+
+	writew(value, addr);
 }
 
 /* Endpoint Function register access */
 static inline void cdns_pcie_ep_fn_writeb(struct cdns_pcie *pcie, u8 fn,
 					  u32 reg, u8 value)
 {
-	writeb(value, pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
+	void __iomem *addr = pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg;
+
+	if (pcie->ops && pcie->ops->write) {
+		pcie->ops->write(addr, 0x1, value);
+		return;
+	}
+
+	writeb(value, addr);
 }
 
 static inline void cdns_pcie_ep_fn_writew(struct cdns_pcie *pcie, u8 fn,
 					  u32 reg, u16 value)
 {
-	writew(value, pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
+	void __iomem *addr = pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg;
+
+	if (pcie->ops && pcie->ops->write) {
+		pcie->ops->write(addr, 0x2, value);
+		return;
+	}
+
+	writew(value, addr);
 }
 
 static inline void cdns_pcie_ep_fn_writel(struct cdns_pcie *pcie, u8 fn,
 					  u32 reg, u32 value)
 {
-	writel(value, pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
+	void __iomem *addr = pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg;
+
+	if (pcie->ops && pcie->ops->write) {
+		pcie->ops->write(addr, 0x4, value);
+		return;
+	}
+
+	writel(value, addr);
 }
 
 static inline u8 cdns_pcie_ep_fn_readb(struct cdns_pcie *pcie, u8 fn, u32 reg)
 {
-	return readb(pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
+	void __iomem *addr = pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg;
+
+	if (pcie->ops && pcie->ops->read)
+		return pcie->ops->read(addr, 0x1);
+
+	return readb(addr);
 }
 
 static inline u16 cdns_pcie_ep_fn_readw(struct cdns_pcie *pcie, u8 fn, u32 reg)
 {
-	return readw(pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
+	void __iomem *addr = pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg;
+
+	if (pcie->ops && pcie->ops->read)
+		return pcie->ops->read(addr, 0x2);
+
+	return readw(addr);
 }
 
 static inline u32 cdns_pcie_ep_fn_readl(struct cdns_pcie *pcie, u8 fn, u32 reg)
 {
-	return readl(pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
+	void __iomem *addr = pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg;
+
+	if (pcie->ops && pcie->ops->read)
+		return pcie->ops->read(addr, 0x4);
+
+	return readl(addr);
 }
 
 #ifdef CONFIG_PCIE_CADENCE_HOST
-- 
2.17.1


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

* [PATCH v3 03/14] PCI: cadence: Add support to use custom read and write accessors
@ 2020-04-17 12:57   ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: devicetree, Arnd Bergmann, Greg Kroah-Hartman, linux-kernel,
	linux-pci, linux-arm-kernel

Add support to use custom read and write accessors. Platforms that
don't support half word or byte access or any other constraint
while accessing registers can use this feature to populate custom
read and write accessors. These custom accessors are used for both
standard register access and configuration space register access of
the PCIe host bridge.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/pci/controller/cadence/pcie-cadence.h | 107 +++++++++++++++---
 1 file changed, 94 insertions(+), 13 deletions(-)

diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
index df14ad002fe9..70b6b25153e8 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -223,6 +223,11 @@ enum cdns_pcie_msg_routing {
 	MSG_ROUTING_GATHER,
 };
 
+struct cdns_pcie_ops {
+	u32	(*read)(void __iomem *addr, int size);
+	void	(*write)(void __iomem *addr, int size, u32 value);
+};
+
 /**
  * struct cdns_pcie - private data for Cadence PCIe controller drivers
  * @reg_base: IO mapped register base
@@ -239,7 +244,7 @@ struct cdns_pcie {
 	int			phy_count;
 	struct phy		**phy;
 	struct device_link	**link;
-	const struct cdns_pcie_common_ops *ops;
+	const struct cdns_pcie_ops *ops;
 };
 
 /**
@@ -299,69 +304,145 @@ struct cdns_pcie_ep {
 /* Register access */
 static inline void cdns_pcie_writeb(struct cdns_pcie *pcie, u32 reg, u8 value)
 {
-	writeb(value, pcie->reg_base + reg);
+	void __iomem *addr = pcie->reg_base + reg;
+
+	if (pcie->ops && pcie->ops->write) {
+		pcie->ops->write(addr, 0x1, value);
+		return;
+	}
+
+	writeb(value, addr);
 }
 
 static inline void cdns_pcie_writew(struct cdns_pcie *pcie, u32 reg, u16 value)
 {
-	writew(value, pcie->reg_base + reg);
+	void __iomem *addr = pcie->reg_base + reg;
+
+	if (pcie->ops && pcie->ops->write) {
+		pcie->ops->write(addr, 0x2, value);
+		return;
+	}
+
+	writew(value, addr);
 }
 
 static inline void cdns_pcie_writel(struct cdns_pcie *pcie, u32 reg, u32 value)
 {
-	writel(value, pcie->reg_base + reg);
+	void __iomem *addr = pcie->reg_base + reg;
+
+	if (pcie->ops && pcie->ops->write) {
+		pcie->ops->write(addr, 0x4, value);
+		return;
+	}
+
+	writel(value, addr);
 }
 
 static inline u32 cdns_pcie_readl(struct cdns_pcie *pcie, u32 reg)
 {
-	return readl(pcie->reg_base + reg);
+	void __iomem *addr = pcie->reg_base + reg;
+
+	if (pcie->ops && pcie->ops->read)
+		return pcie->ops->read(addr, 0x4);
+
+	return readl(addr);
 }
 
 /* Root Port register access */
 static inline void cdns_pcie_rp_writeb(struct cdns_pcie *pcie,
 				       u32 reg, u8 value)
 {
-	writeb(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
+	void __iomem *addr = pcie->reg_base + CDNS_PCIE_RP_BASE + reg;
+
+	if (pcie->ops && pcie->ops->write) {
+		pcie->ops->write(addr, 0x1, value);
+		return;
+	}
+
+	writeb(value, addr);
 }
 
 static inline void cdns_pcie_rp_writew(struct cdns_pcie *pcie,
 				       u32 reg, u16 value)
 {
-	writew(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
+	void __iomem *addr = pcie->reg_base + CDNS_PCIE_RP_BASE + reg;
+
+	if (pcie->ops && pcie->ops->write) {
+		pcie->ops->write(addr, 0x2, value);
+		return;
+	}
+
+	writew(value, addr);
 }
 
 /* Endpoint Function register access */
 static inline void cdns_pcie_ep_fn_writeb(struct cdns_pcie *pcie, u8 fn,
 					  u32 reg, u8 value)
 {
-	writeb(value, pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
+	void __iomem *addr = pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg;
+
+	if (pcie->ops && pcie->ops->write) {
+		pcie->ops->write(addr, 0x1, value);
+		return;
+	}
+
+	writeb(value, addr);
 }
 
 static inline void cdns_pcie_ep_fn_writew(struct cdns_pcie *pcie, u8 fn,
 					  u32 reg, u16 value)
 {
-	writew(value, pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
+	void __iomem *addr = pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg;
+
+	if (pcie->ops && pcie->ops->write) {
+		pcie->ops->write(addr, 0x2, value);
+		return;
+	}
+
+	writew(value, addr);
 }
 
 static inline void cdns_pcie_ep_fn_writel(struct cdns_pcie *pcie, u8 fn,
 					  u32 reg, u32 value)
 {
-	writel(value, pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
+	void __iomem *addr = pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg;
+
+	if (pcie->ops && pcie->ops->write) {
+		pcie->ops->write(addr, 0x4, value);
+		return;
+	}
+
+	writel(value, addr);
 }
 
 static inline u8 cdns_pcie_ep_fn_readb(struct cdns_pcie *pcie, u8 fn, u32 reg)
 {
-	return readb(pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
+	void __iomem *addr = pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg;
+
+	if (pcie->ops && pcie->ops->read)
+		return pcie->ops->read(addr, 0x1);
+
+	return readb(addr);
 }
 
 static inline u16 cdns_pcie_ep_fn_readw(struct cdns_pcie *pcie, u8 fn, u32 reg)
 {
-	return readw(pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
+	void __iomem *addr = pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg;
+
+	if (pcie->ops && pcie->ops->read)
+		return pcie->ops->read(addr, 0x2);
+
+	return readw(addr);
 }
 
 static inline u32 cdns_pcie_ep_fn_readl(struct cdns_pcie *pcie, u8 fn, u32 reg)
 {
-	return readl(pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
+	void __iomem *addr = pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg;
+
+	if (pcie->ops && pcie->ops->read)
+		return pcie->ops->read(addr, 0x4);
+
+	return readl(addr);
 }
 
 #ifdef CONFIG_PCIE_CADENCE_HOST
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v3 04/14] PCI: cadence: Add support to start link and verify link status
  2020-04-17 12:57 ` Kishon Vijay Abraham I
@ 2020-04-17 12:57   ` Kishon Vijay Abraham I
  -1 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: Arnd Bergmann, Greg Kroah-Hartman, linux-arm-kernel, linux-pci,
	devicetree, linux-kernel

Add cdns_pcie_ops to start link and verify link status. The registers
to start link and to check link status is in Platform specific PCIe
wrapper. Add support for platform specific drivers to add callback
functions for the PCIe Cadence core to start link and verify link status.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 .../pci/controller/cadence/pcie-cadence-ep.c  |  8 +++++
 .../controller/cadence/pcie-cadence-host.c    | 28 +++++++++++++++++
 drivers/pci/controller/cadence/pcie-cadence.h | 30 +++++++++++++++++++
 3 files changed, 66 insertions(+)

diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c
index 1fdae37843ef..14021d760482 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-ep.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c
@@ -354,8 +354,10 @@ static int cdns_pcie_ep_start(struct pci_epc *epc)
 {
 	struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
 	struct cdns_pcie *pcie = &ep->pcie;
+	struct device *dev = pcie->dev;
 	struct pci_epf *epf;
 	u32 cfg;
+	int ret;
 
 	/*
 	 * BIT(0) is hardwired to 1, hence function 0 is always enabled
@@ -366,6 +368,12 @@ static int cdns_pcie_ep_start(struct pci_epc *epc)
 		cfg |= BIT(epf->func_no);
 	cdns_pcie_writel(pcie, CDNS_PCIE_LM_EP_FUNC_CFG, cfg);
 
+	ret = cdns_pcie_start_link(pcie);
+	if (ret) {
+		dev_err(dev, "Failed to start link\n");
+		return ret;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c
index 465607202bb5..a60b9627cfbf 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -3,6 +3,7 @@
 // Cadence PCIe host controller driver.
 // Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
 
+#include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/of_address.h>
 #include <linux/of_pci.h>
@@ -197,6 +198,23 @@ static int cdns_pcie_host_init(struct device *dev,
 	return err;
 }
 
+static int cdns_pcie_host_wait_for_link(struct cdns_pcie *pcie)
+{
+	struct device *dev = pcie->dev;
+	int retries;
+
+	/* Check if the link is up or not */
+	for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
+		if (cdns_pcie_link_up(pcie)) {
+			dev_info(dev, "Link up\n");
+			return 0;
+		}
+		usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
+	}
+
+	return -ETIMEDOUT;
+}
+
 int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
 {
 	struct device *dev = rc->pcie.dev;
@@ -256,6 +274,16 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
 
 	pcie->mem_res = res;
 
+	ret = cdns_pcie_start_link(pcie);
+	if (ret) {
+		dev_err(dev, "Failed to start link\n");
+		return ret;
+	}
+
+	ret = cdns_pcie_host_wait_for_link(pcie);
+	if (ret)
+		dev_dbg(dev, "PCIe link never came up\n");
+
 	ret = cdns_pcie_host_init(dev, &resources, rc);
 	if (ret)
 		return ret;
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
index 70b6b25153e8..a6c4816b68c0 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -10,6 +10,11 @@
 #include <linux/pci.h>
 #include <linux/phy/phy.h>
 
+/* Parameters for the waiting for link up routine */
+#define LINK_WAIT_MAX_RETRIES	10
+#define LINK_WAIT_USLEEP_MIN	90000
+#define LINK_WAIT_USLEEP_MAX	100000
+
 /*
  * Local Management Registers
  */
@@ -226,6 +231,9 @@ enum cdns_pcie_msg_routing {
 struct cdns_pcie_ops {
 	u32	(*read)(void __iomem *addr, int size);
 	void	(*write)(void __iomem *addr, int size, u32 value);
+	int	(*start_link)(struct cdns_pcie *pcie);
+	void	(*stop_link)(struct cdns_pcie *pcie);
+	bool	(*link_up)(struct cdns_pcie *pcie);
 };
 
 /**
@@ -445,6 +453,28 @@ static inline u32 cdns_pcie_ep_fn_readl(struct cdns_pcie *pcie, u8 fn, u32 reg)
 	return readl(addr);
 }
 
+static inline int cdns_pcie_start_link(struct cdns_pcie *pcie)
+{
+	if (pcie->ops->start_link)
+		return pcie->ops->start_link(pcie);
+
+	return 0;
+}
+
+static inline void cdns_pcie_stop_link(struct cdns_pcie *pcie)
+{
+	if (pcie->ops->stop_link)
+		pcie->ops->stop_link(pcie);
+}
+
+static inline bool cdns_pcie_link_up(struct cdns_pcie *pcie)
+{
+	if (pcie->ops->link_up)
+		return pcie->ops->link_up(pcie);
+
+	return true;
+}
+
 #ifdef CONFIG_PCIE_CADENCE_HOST
 int cdns_pcie_host_setup(struct cdns_pcie_rc *rc);
 #else
-- 
2.17.1


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

* [PATCH v3 04/14] PCI: cadence: Add support to start link and verify link status
@ 2020-04-17 12:57   ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: devicetree, Arnd Bergmann, Greg Kroah-Hartman, linux-kernel,
	linux-pci, linux-arm-kernel

Add cdns_pcie_ops to start link and verify link status. The registers
to start link and to check link status is in Platform specific PCIe
wrapper. Add support for platform specific drivers to add callback
functions for the PCIe Cadence core to start link and verify link status.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 .../pci/controller/cadence/pcie-cadence-ep.c  |  8 +++++
 .../controller/cadence/pcie-cadence-host.c    | 28 +++++++++++++++++
 drivers/pci/controller/cadence/pcie-cadence.h | 30 +++++++++++++++++++
 3 files changed, 66 insertions(+)

diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c
index 1fdae37843ef..14021d760482 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-ep.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c
@@ -354,8 +354,10 @@ static int cdns_pcie_ep_start(struct pci_epc *epc)
 {
 	struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
 	struct cdns_pcie *pcie = &ep->pcie;
+	struct device *dev = pcie->dev;
 	struct pci_epf *epf;
 	u32 cfg;
+	int ret;
 
 	/*
 	 * BIT(0) is hardwired to 1, hence function 0 is always enabled
@@ -366,6 +368,12 @@ static int cdns_pcie_ep_start(struct pci_epc *epc)
 		cfg |= BIT(epf->func_no);
 	cdns_pcie_writel(pcie, CDNS_PCIE_LM_EP_FUNC_CFG, cfg);
 
+	ret = cdns_pcie_start_link(pcie);
+	if (ret) {
+		dev_err(dev, "Failed to start link\n");
+		return ret;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c
index 465607202bb5..a60b9627cfbf 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -3,6 +3,7 @@
 // Cadence PCIe host controller driver.
 // Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
 
+#include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/of_address.h>
 #include <linux/of_pci.h>
@@ -197,6 +198,23 @@ static int cdns_pcie_host_init(struct device *dev,
 	return err;
 }
 
+static int cdns_pcie_host_wait_for_link(struct cdns_pcie *pcie)
+{
+	struct device *dev = pcie->dev;
+	int retries;
+
+	/* Check if the link is up or not */
+	for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
+		if (cdns_pcie_link_up(pcie)) {
+			dev_info(dev, "Link up\n");
+			return 0;
+		}
+		usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
+	}
+
+	return -ETIMEDOUT;
+}
+
 int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
 {
 	struct device *dev = rc->pcie.dev;
@@ -256,6 +274,16 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
 
 	pcie->mem_res = res;
 
+	ret = cdns_pcie_start_link(pcie);
+	if (ret) {
+		dev_err(dev, "Failed to start link\n");
+		return ret;
+	}
+
+	ret = cdns_pcie_host_wait_for_link(pcie);
+	if (ret)
+		dev_dbg(dev, "PCIe link never came up\n");
+
 	ret = cdns_pcie_host_init(dev, &resources, rc);
 	if (ret)
 		return ret;
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
index 70b6b25153e8..a6c4816b68c0 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -10,6 +10,11 @@
 #include <linux/pci.h>
 #include <linux/phy/phy.h>
 
+/* Parameters for the waiting for link up routine */
+#define LINK_WAIT_MAX_RETRIES	10
+#define LINK_WAIT_USLEEP_MIN	90000
+#define LINK_WAIT_USLEEP_MAX	100000
+
 /*
  * Local Management Registers
  */
@@ -226,6 +231,9 @@ enum cdns_pcie_msg_routing {
 struct cdns_pcie_ops {
 	u32	(*read)(void __iomem *addr, int size);
 	void	(*write)(void __iomem *addr, int size, u32 value);
+	int	(*start_link)(struct cdns_pcie *pcie);
+	void	(*stop_link)(struct cdns_pcie *pcie);
+	bool	(*link_up)(struct cdns_pcie *pcie);
 };
 
 /**
@@ -445,6 +453,28 @@ static inline u32 cdns_pcie_ep_fn_readl(struct cdns_pcie *pcie, u8 fn, u32 reg)
 	return readl(addr);
 }
 
+static inline int cdns_pcie_start_link(struct cdns_pcie *pcie)
+{
+	if (pcie->ops->start_link)
+		return pcie->ops->start_link(pcie);
+
+	return 0;
+}
+
+static inline void cdns_pcie_stop_link(struct cdns_pcie *pcie)
+{
+	if (pcie->ops->stop_link)
+		pcie->ops->stop_link(pcie);
+}
+
+static inline bool cdns_pcie_link_up(struct cdns_pcie *pcie)
+{
+	if (pcie->ops->link_up)
+		return pcie->ops->link_up(pcie);
+
+	return true;
+}
+
 #ifdef CONFIG_PCIE_CADENCE_HOST
 int cdns_pcie_host_setup(struct cdns_pcie_rc *rc);
 #else
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v3 05/14] PCI: cadence: Add read/write accessors to perform only 32-bit accesses
  2020-04-17 12:57 ` Kishon Vijay Abraham I
@ 2020-04-17 12:57   ` Kishon Vijay Abraham I
  -1 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: Arnd Bergmann, Greg Kroah-Hartman, linux-arm-kernel, linux-pci,
	devicetree, linux-kernel

Certain platforms like TI's J721E allow only 32-bit register accesses.
Add read and write accessors to perform only 32-bit accesses in order to
support platforms like TI's J721E.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/pci/controller/cadence/pcie-cadence.c | 40 +++++++++++++++++++
 drivers/pci/controller/cadence/pcie-cadence.h |  2 +
 2 files changed, 42 insertions(+)

diff --git a/drivers/pci/controller/cadence/pcie-cadence.c b/drivers/pci/controller/cadence/pcie-cadence.c
index cd795f6fc1e2..874b7fa93577 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.c
+++ b/drivers/pci/controller/cadence/pcie-cadence.c
@@ -7,6 +7,46 @@
 
 #include "pcie-cadence.h"
 
+u32 cdns_platform_pcie_read32(void __iomem *addr, int size)
+{
+	void __iomem *aligned_addr = PTR_ALIGN_DOWN(addr, 0x4);
+	unsigned int offset = (unsigned long)addr & 0x3;
+	u32 val = readl(aligned_addr);
+
+	if (!IS_ALIGNED((uintptr_t)addr, size)) {
+		WARN(1, "Address %p and size %d are not aligned\n", addr, size);
+		return 0;
+	}
+
+	if (size > 2)
+		return val;
+
+	return (val >> (8 * offset)) & ((1 << (size * 8)) - 1);
+}
+
+void cdns_platform_pcie_write32(void __iomem *addr, int size, u32 value)
+{
+	void __iomem *aligned_addr = PTR_ALIGN_DOWN(addr, 0x4);
+	unsigned int offset = (unsigned long)addr & 0x3;
+	u32 mask;
+	u32 val;
+
+	if (!IS_ALIGNED((uintptr_t)addr, size)) {
+		WARN(1, "Address %p and size %d are not aligned\n", addr, size);
+		return;
+	}
+
+	if (size > 2) {
+		writel(value, addr);
+		return;
+	}
+
+	mask = ~(((1 << (size * 8)) - 1) << (offset * 8));
+	val = readl(aligned_addr) & mask;
+	val |= value << (offset * 8);
+	writel(val, aligned_addr);
+}
+
 void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 fn,
 				   u32 r, bool is_io,
 				   u64 cpu_addr, u64 pci_addr, size_t size)
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
index a6c4816b68c0..03c21ce4c9e9 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -503,6 +503,8 @@ void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r);
 void cdns_pcie_disable_phy(struct cdns_pcie *pcie);
 int cdns_pcie_enable_phy(struct cdns_pcie *pcie);
 int cdns_pcie_init_phy(struct device *dev, struct cdns_pcie *pcie);
+u32 cdns_platform_pcie_read32(void __iomem *addr, int size);
+void cdns_platform_pcie_write32(void __iomem *addr, int size, u32 value);
 extern const struct dev_pm_ops cdns_pcie_pm_ops;
 
 #endif /* _PCIE_CADENCE_H */
-- 
2.17.1


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

* [PATCH v3 05/14] PCI: cadence: Add read/write accessors to perform only 32-bit accesses
@ 2020-04-17 12:57   ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: devicetree, Arnd Bergmann, Greg Kroah-Hartman, linux-kernel,
	linux-pci, linux-arm-kernel

Certain platforms like TI's J721E allow only 32-bit register accesses.
Add read and write accessors to perform only 32-bit accesses in order to
support platforms like TI's J721E.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/pci/controller/cadence/pcie-cadence.c | 40 +++++++++++++++++++
 drivers/pci/controller/cadence/pcie-cadence.h |  2 +
 2 files changed, 42 insertions(+)

diff --git a/drivers/pci/controller/cadence/pcie-cadence.c b/drivers/pci/controller/cadence/pcie-cadence.c
index cd795f6fc1e2..874b7fa93577 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.c
+++ b/drivers/pci/controller/cadence/pcie-cadence.c
@@ -7,6 +7,46 @@
 
 #include "pcie-cadence.h"
 
+u32 cdns_platform_pcie_read32(void __iomem *addr, int size)
+{
+	void __iomem *aligned_addr = PTR_ALIGN_DOWN(addr, 0x4);
+	unsigned int offset = (unsigned long)addr & 0x3;
+	u32 val = readl(aligned_addr);
+
+	if (!IS_ALIGNED((uintptr_t)addr, size)) {
+		WARN(1, "Address %p and size %d are not aligned\n", addr, size);
+		return 0;
+	}
+
+	if (size > 2)
+		return val;
+
+	return (val >> (8 * offset)) & ((1 << (size * 8)) - 1);
+}
+
+void cdns_platform_pcie_write32(void __iomem *addr, int size, u32 value)
+{
+	void __iomem *aligned_addr = PTR_ALIGN_DOWN(addr, 0x4);
+	unsigned int offset = (unsigned long)addr & 0x3;
+	u32 mask;
+	u32 val;
+
+	if (!IS_ALIGNED((uintptr_t)addr, size)) {
+		WARN(1, "Address %p and size %d are not aligned\n", addr, size);
+		return;
+	}
+
+	if (size > 2) {
+		writel(value, addr);
+		return;
+	}
+
+	mask = ~(((1 << (size * 8)) - 1) << (offset * 8));
+	val = readl(aligned_addr) & mask;
+	val |= value << (offset * 8);
+	writel(val, aligned_addr);
+}
+
 void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 fn,
 				   u32 r, bool is_io,
 				   u64 cpu_addr, u64 pci_addr, size_t size)
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
index a6c4816b68c0..03c21ce4c9e9 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -503,6 +503,8 @@ void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r);
 void cdns_pcie_disable_phy(struct cdns_pcie *pcie);
 int cdns_pcie_enable_phy(struct cdns_pcie *pcie);
 int cdns_pcie_init_phy(struct device *dev, struct cdns_pcie *pcie);
+u32 cdns_platform_pcie_read32(void __iomem *addr, int size);
+void cdns_platform_pcie_write32(void __iomem *addr, int size, u32 value);
 extern const struct dev_pm_ops cdns_pcie_pm_ops;
 
 #endif /* _PCIE_CADENCE_H */
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v3 06/14] PCI: cadence: Allow pci_host_bridge to have custom pci_ops
  2020-04-17 12:57 ` Kishon Vijay Abraham I
@ 2020-04-17 12:57   ` Kishon Vijay Abraham I
  -1 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: Arnd Bergmann, Greg Kroah-Hartman, linux-arm-kernel, linux-pci,
	devicetree, linux-kernel

Certain platforms like TI's J721E allows only 32-bit configuration
space access. In such cases pci_generic_config_read and
pci_generic_config_write cannot be used. Add support in Cadence core
to let pci_host_bridge have custom pci_ops.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/pci/controller/cadence/pcie-cadence-host.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c
index a60b9627cfbf..6c84520318a7 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -291,7 +291,8 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
 	list_splice_init(&resources, &bridge->windows);
 	bridge->dev.parent = dev;
 	bridge->busnr = pcie->bus;
-	bridge->ops = &cdns_pcie_host_ops;
+	if (!bridge->ops)
+		bridge->ops = &cdns_pcie_host_ops;
 	bridge->map_irq = of_irq_parse_and_map_pci;
 	bridge->swizzle_irq = pci_common_swizzle;
 
-- 
2.17.1


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

* [PATCH v3 06/14] PCI: cadence: Allow pci_host_bridge to have custom pci_ops
@ 2020-04-17 12:57   ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: devicetree, Arnd Bergmann, Greg Kroah-Hartman, linux-kernel,
	linux-pci, linux-arm-kernel

Certain platforms like TI's J721E allows only 32-bit configuration
space access. In such cases pci_generic_config_read and
pci_generic_config_write cannot be used. Add support in Cadence core
to let pci_host_bridge have custom pci_ops.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/pci/controller/cadence/pcie-cadence-host.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c
index a60b9627cfbf..6c84520318a7 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -291,7 +291,8 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
 	list_splice_init(&resources, &bridge->windows);
 	bridge->dev.parent = dev;
 	bridge->busnr = pcie->bus;
-	bridge->ops = &cdns_pcie_host_ops;
+	if (!bridge->ops)
+		bridge->ops = &cdns_pcie_host_ops;
 	bridge->map_irq = of_irq_parse_and_map_pci;
 	bridge->swizzle_irq = pci_common_swizzle;
 
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v3 07/14] PCI: cadence: Add new *ops* for CPU addr fixup
  2020-04-17 12:57 ` Kishon Vijay Abraham I
@ 2020-04-17 12:57   ` Kishon Vijay Abraham I
  -1 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: Arnd Bergmann, Greg Kroah-Hartman, linux-arm-kernel, linux-pci,
	devicetree, linux-kernel

Cadence driver uses "mem" memory resource to obtain the offset of
configuration space address region, memory space address region and
message space address region. The obtained offset is used to program
the Address Translation Unit (ATU). However certain platforms like TI's
J721E SoC require the absolute address to be programmed in the ATU and not
just the offset.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 .../pci/controller/cadence/pcie-cadence-host.c    | 15 ++++-----------
 .../pci/controller/cadence/pcie-cadence-plat.c    | 13 +++++++++++++
 drivers/pci/controller/cadence/pcie-cadence.c     |  8 ++++++--
 drivers/pci/controller/cadence/pcie-cadence.h     |  1 +
 4 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c
index 6c84520318a7..7c220671e66f 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -104,15 +104,14 @@ static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
 static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
 {
 	struct cdns_pcie *pcie = &rc->pcie;
-	struct resource *mem_res = pcie->mem_res;
 	struct resource *bus_range = rc->bus_range;
 	struct resource *cfg_res = rc->cfg_res;
 	struct device *dev = pcie->dev;
 	struct device_node *np = dev->of_node;
 	struct of_pci_range_parser parser;
+	u64 cpu_addr = cfg_res->start;
 	struct of_pci_range range;
 	u32 addr0, addr1, desc1;
-	u64 cpu_addr;
 	int r, err;
 
 	/*
@@ -125,7 +124,9 @@ static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
 	cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(0), addr1);
 	cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(0), desc1);
 
-	cpu_addr = cfg_res->start - mem_res->start;
+	if (pcie->ops->cpu_addr_fixup)
+		cpu_addr = pcie->ops->cpu_addr_fixup(pcie, cpu_addr);
+
 	addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(12) |
 		(lower_32_bits(cpu_addr) & GENMASK(31, 8));
 	addr1 = upper_32_bits(cpu_addr);
@@ -266,14 +267,6 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
 	}
 	rc->cfg_res = res;
 
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem");
-	if (!res) {
-		dev_err(dev, "missing \"mem\"\n");
-		return -EINVAL;
-	}
-
-	pcie->mem_res = res;
-
 	ret = cdns_pcie_start_link(pcie);
 	if (ret) {
 		dev_err(dev, "Failed to start link\n");
diff --git a/drivers/pci/controller/cadence/pcie-cadence-plat.c b/drivers/pci/controller/cadence/pcie-cadence-plat.c
index f5c6bf6dfcb8..6f5f07b3eed1 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-plat.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-plat.c
@@ -13,6 +13,8 @@
 #include <linux/of_device.h>
 #include "pcie-cadence.h"
 
+#define CDNS_PLAT_CPU_TO_BUS_ADDR	0x0FFFFFFF
+
 /**
  * struct cdns_plat_pcie - private data for this PCIe platform driver
  * @pcie: Cadence PCIe controller
@@ -30,6 +32,15 @@ struct cdns_plat_pcie_of_data {
 
 static const struct of_device_id cdns_plat_pcie_of_match[];
 
+static u64 cdns_plat_cpu_addr_fixup(struct cdns_pcie *pcie, u64 cpu_addr)
+{
+	return cpu_addr & CDNS_PLAT_CPU_TO_BUS_ADDR;
+}
+
+static const struct cdns_pcie_ops cdns_plat_ops = {
+	.cpu_addr_fixup = cdns_plat_cpu_addr_fixup,
+};
+
 static int cdns_plat_pcie_probe(struct platform_device *pdev)
 {
 	const struct cdns_plat_pcie_of_data *data;
@@ -66,6 +77,7 @@ static int cdns_plat_pcie_probe(struct platform_device *pdev)
 
 		rc = pci_host_bridge_priv(bridge);
 		rc->pcie.dev = dev;
+		rc->pcie.ops = &cdns_plat_ops;
 		cdns_plat_pcie->pcie = &rc->pcie;
 		cdns_plat_pcie->is_rc = is_rc;
 
@@ -93,6 +105,7 @@ static int cdns_plat_pcie_probe(struct platform_device *pdev)
 			return -ENOMEM;
 
 		ep->pcie.dev = dev;
+		ep->pcie.ops = &cdns_plat_ops;
 		cdns_plat_pcie->pcie = &ep->pcie;
 		cdns_plat_pcie->is_rc = is_rc;
 
diff --git a/drivers/pci/controller/cadence/pcie-cadence.c b/drivers/pci/controller/cadence/pcie-cadence.c
index 874b7fa93577..29d32019145c 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.c
+++ b/drivers/pci/controller/cadence/pcie-cadence.c
@@ -113,7 +113,9 @@ void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 fn,
 	cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), desc1);
 
 	/* Set the CPU address */
-	cpu_addr -= pcie->mem_res->start;
+	if (pcie->ops->cpu_addr_fixup)
+		cpu_addr = pcie->ops->cpu_addr_fixup(pcie, cpu_addr);
+
 	addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) |
 		(lower_32_bits(cpu_addr) & GENMASK(31, 8));
 	addr1 = upper_32_bits(cpu_addr);
@@ -140,7 +142,9 @@ void cdns_pcie_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie, u8 fn,
 	}
 
 	/* Set the CPU address */
-	cpu_addr -= pcie->mem_res->start;
+	if (pcie->ops->cpu_addr_fixup)
+		cpu_addr = pcie->ops->cpu_addr_fixup(pcie, cpu_addr);
+
 	addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(17) |
 		(lower_32_bits(cpu_addr) & GENMASK(31, 8));
 	addr1 = upper_32_bits(cpu_addr);
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
index 03c21ce4c9e9..16a6b0ee547c 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -234,6 +234,7 @@ struct cdns_pcie_ops {
 	int	(*start_link)(struct cdns_pcie *pcie);
 	void	(*stop_link)(struct cdns_pcie *pcie);
 	bool	(*link_up)(struct cdns_pcie *pcie);
+	u64     (*cpu_addr_fixup)(struct cdns_pcie *pcie, u64 cpu_addr);
 };
 
 /**
-- 
2.17.1


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

* [PATCH v3 07/14] PCI: cadence: Add new *ops* for CPU addr fixup
@ 2020-04-17 12:57   ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: devicetree, Arnd Bergmann, Greg Kroah-Hartman, linux-kernel,
	linux-pci, linux-arm-kernel

Cadence driver uses "mem" memory resource to obtain the offset of
configuration space address region, memory space address region and
message space address region. The obtained offset is used to program
the Address Translation Unit (ATU). However certain platforms like TI's
J721E SoC require the absolute address to be programmed in the ATU and not
just the offset.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 .../pci/controller/cadence/pcie-cadence-host.c    | 15 ++++-----------
 .../pci/controller/cadence/pcie-cadence-plat.c    | 13 +++++++++++++
 drivers/pci/controller/cadence/pcie-cadence.c     |  8 ++++++--
 drivers/pci/controller/cadence/pcie-cadence.h     |  1 +
 4 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c
index 6c84520318a7..7c220671e66f 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -104,15 +104,14 @@ static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
 static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
 {
 	struct cdns_pcie *pcie = &rc->pcie;
-	struct resource *mem_res = pcie->mem_res;
 	struct resource *bus_range = rc->bus_range;
 	struct resource *cfg_res = rc->cfg_res;
 	struct device *dev = pcie->dev;
 	struct device_node *np = dev->of_node;
 	struct of_pci_range_parser parser;
+	u64 cpu_addr = cfg_res->start;
 	struct of_pci_range range;
 	u32 addr0, addr1, desc1;
-	u64 cpu_addr;
 	int r, err;
 
 	/*
@@ -125,7 +124,9 @@ static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
 	cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(0), addr1);
 	cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(0), desc1);
 
-	cpu_addr = cfg_res->start - mem_res->start;
+	if (pcie->ops->cpu_addr_fixup)
+		cpu_addr = pcie->ops->cpu_addr_fixup(pcie, cpu_addr);
+
 	addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(12) |
 		(lower_32_bits(cpu_addr) & GENMASK(31, 8));
 	addr1 = upper_32_bits(cpu_addr);
@@ -266,14 +267,6 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
 	}
 	rc->cfg_res = res;
 
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem");
-	if (!res) {
-		dev_err(dev, "missing \"mem\"\n");
-		return -EINVAL;
-	}
-
-	pcie->mem_res = res;
-
 	ret = cdns_pcie_start_link(pcie);
 	if (ret) {
 		dev_err(dev, "Failed to start link\n");
diff --git a/drivers/pci/controller/cadence/pcie-cadence-plat.c b/drivers/pci/controller/cadence/pcie-cadence-plat.c
index f5c6bf6dfcb8..6f5f07b3eed1 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-plat.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-plat.c
@@ -13,6 +13,8 @@
 #include <linux/of_device.h>
 #include "pcie-cadence.h"
 
+#define CDNS_PLAT_CPU_TO_BUS_ADDR	0x0FFFFFFF
+
 /**
  * struct cdns_plat_pcie - private data for this PCIe platform driver
  * @pcie: Cadence PCIe controller
@@ -30,6 +32,15 @@ struct cdns_plat_pcie_of_data {
 
 static const struct of_device_id cdns_plat_pcie_of_match[];
 
+static u64 cdns_plat_cpu_addr_fixup(struct cdns_pcie *pcie, u64 cpu_addr)
+{
+	return cpu_addr & CDNS_PLAT_CPU_TO_BUS_ADDR;
+}
+
+static const struct cdns_pcie_ops cdns_plat_ops = {
+	.cpu_addr_fixup = cdns_plat_cpu_addr_fixup,
+};
+
 static int cdns_plat_pcie_probe(struct platform_device *pdev)
 {
 	const struct cdns_plat_pcie_of_data *data;
@@ -66,6 +77,7 @@ static int cdns_plat_pcie_probe(struct platform_device *pdev)
 
 		rc = pci_host_bridge_priv(bridge);
 		rc->pcie.dev = dev;
+		rc->pcie.ops = &cdns_plat_ops;
 		cdns_plat_pcie->pcie = &rc->pcie;
 		cdns_plat_pcie->is_rc = is_rc;
 
@@ -93,6 +105,7 @@ static int cdns_plat_pcie_probe(struct platform_device *pdev)
 			return -ENOMEM;
 
 		ep->pcie.dev = dev;
+		ep->pcie.ops = &cdns_plat_ops;
 		cdns_plat_pcie->pcie = &ep->pcie;
 		cdns_plat_pcie->is_rc = is_rc;
 
diff --git a/drivers/pci/controller/cadence/pcie-cadence.c b/drivers/pci/controller/cadence/pcie-cadence.c
index 874b7fa93577..29d32019145c 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.c
+++ b/drivers/pci/controller/cadence/pcie-cadence.c
@@ -113,7 +113,9 @@ void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 fn,
 	cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), desc1);
 
 	/* Set the CPU address */
-	cpu_addr -= pcie->mem_res->start;
+	if (pcie->ops->cpu_addr_fixup)
+		cpu_addr = pcie->ops->cpu_addr_fixup(pcie, cpu_addr);
+
 	addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) |
 		(lower_32_bits(cpu_addr) & GENMASK(31, 8));
 	addr1 = upper_32_bits(cpu_addr);
@@ -140,7 +142,9 @@ void cdns_pcie_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie, u8 fn,
 	}
 
 	/* Set the CPU address */
-	cpu_addr -= pcie->mem_res->start;
+	if (pcie->ops->cpu_addr_fixup)
+		cpu_addr = pcie->ops->cpu_addr_fixup(pcie, cpu_addr);
+
 	addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(17) |
 		(lower_32_bits(cpu_addr) & GENMASK(31, 8));
 	addr1 = upper_32_bits(cpu_addr);
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
index 03c21ce4c9e9..16a6b0ee547c 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -234,6 +234,7 @@ struct cdns_pcie_ops {
 	int	(*start_link)(struct cdns_pcie *pcie);
 	void	(*stop_link)(struct cdns_pcie *pcie);
 	bool	(*link_up)(struct cdns_pcie *pcie);
+	u64     (*cpu_addr_fixup)(struct cdns_pcie *pcie, u64 cpu_addr);
 };
 
 /**
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v3 08/14] PCI: cadence: Fix updating Vendor ID and Subsystem Vendor ID register
  2020-04-17 12:57 ` Kishon Vijay Abraham I
@ 2020-04-17 12:57   ` Kishon Vijay Abraham I
  -1 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: Arnd Bergmann, Greg Kroah-Hartman, linux-arm-kernel, linux-pci,
	devicetree, linux-kernel

Commit 1b79c5284439 ("PCI: cadence: Add host driver for Cadence PCIe
controller") in order to update Vendor ID, directly wrote to
PCI_VENDOR_ID register. However PCI_VENDOR_ID in root port configuration
space is read-only register and writing to it will have no effect.
Use local management register to configure Vendor ID and Subsystem Vendor
ID.

Fixes: 1b79c5284439 ("PCI: cadence: Add host driver for Cadence PCIe controller")
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/pci/controller/cadence/pcie-cadence-host.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c
index 7c220671e66f..c7dc7be0da40 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -70,6 +70,7 @@ static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
 {
 	struct cdns_pcie *pcie = &rc->pcie;
 	u32 value, ctrl;
+	u32 id;
 
 	/*
 	 * Set the root complex BAR configuration register:
@@ -89,8 +90,12 @@ static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
 	cdns_pcie_writel(pcie, CDNS_PCIE_LM_RC_BAR_CFG, value);
 
 	/* Set root port configuration space */
-	if (rc->vendor_id != 0xffff)
-		cdns_pcie_rp_writew(pcie, PCI_VENDOR_ID, rc->vendor_id);
+	if (rc->vendor_id != 0xffff) {
+		id = CDNS_PCIE_LM_ID_VENDOR(rc->vendor_id) |
+			CDNS_PCIE_LM_ID_SUBSYS(rc->vendor_id);
+		cdns_pcie_writel(pcie, CDNS_PCIE_LM_ID, id);
+	}
+
 	if (rc->device_id != 0xffff)
 		cdns_pcie_rp_writew(pcie, PCI_DEVICE_ID, rc->device_id);
 
-- 
2.17.1


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

* [PATCH v3 08/14] PCI: cadence: Fix updating Vendor ID and Subsystem Vendor ID register
@ 2020-04-17 12:57   ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: devicetree, Arnd Bergmann, Greg Kroah-Hartman, linux-kernel,
	linux-pci, linux-arm-kernel

Commit 1b79c5284439 ("PCI: cadence: Add host driver for Cadence PCIe
controller") in order to update Vendor ID, directly wrote to
PCI_VENDOR_ID register. However PCI_VENDOR_ID in root port configuration
space is read-only register and writing to it will have no effect.
Use local management register to configure Vendor ID and Subsystem Vendor
ID.

Fixes: 1b79c5284439 ("PCI: cadence: Add host driver for Cadence PCIe controller")
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/pci/controller/cadence/pcie-cadence-host.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c
index 7c220671e66f..c7dc7be0da40 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -70,6 +70,7 @@ static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
 {
 	struct cdns_pcie *pcie = &rc->pcie;
 	u32 value, ctrl;
+	u32 id;
 
 	/*
 	 * Set the root complex BAR configuration register:
@@ -89,8 +90,12 @@ static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
 	cdns_pcie_writel(pcie, CDNS_PCIE_LM_RC_BAR_CFG, value);
 
 	/* Set root port configuration space */
-	if (rc->vendor_id != 0xffff)
-		cdns_pcie_rp_writew(pcie, PCI_VENDOR_ID, rc->vendor_id);
+	if (rc->vendor_id != 0xffff) {
+		id = CDNS_PCIE_LM_ID_VENDOR(rc->vendor_id) |
+			CDNS_PCIE_LM_ID_SUBSYS(rc->vendor_id);
+		cdns_pcie_writel(pcie, CDNS_PCIE_LM_ID, id);
+	}
+
 	if (rc->device_id != 0xffff)
 		cdns_pcie_rp_writew(pcie, PCI_DEVICE_ID, rc->device_id);
 
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v3 09/14] PCI: cadence: Add MSI-X support to Endpoint driver
  2020-04-17 12:57 ` Kishon Vijay Abraham I
@ 2020-04-17 12:57   ` Kishon Vijay Abraham I
  -1 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: Arnd Bergmann, Greg Kroah-Hartman, linux-arm-kernel, linux-pci,
	devicetree, linux-kernel

From: Alan Douglas <adouglas@cadence.com>

Implement ->set_msix() and ->get_msix() callback functions in order
to configure MSIX capability in the PCIe endpoint controller.

Add cdns_pcie_ep_send_msix_irq() to send MSIX interrupts to Host.
cdns_pcie_ep_send_msix_irq() gets the MSIX table address (virtual
address) from "struct cdns_pcie_epf" that gets initialized in
->set_bar() call back function.

[kishon@ti.com: Re-implement MSIX support in accordance with the
 re-designed core MSI-X interfaces]
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Signed-off-by: Alan Douglas <adouglas@cadence.com>
---
 .../pci/controller/cadence/pcie-cadence-ep.c  | 112 +++++++++++++++++-
 drivers/pci/controller/cadence/pcie-cadence.h |  10 ++
 2 files changed, 121 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c
index 14021d760482..c43340ca0630 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-ep.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c
@@ -51,6 +51,7 @@ static int cdns_pcie_ep_set_bar(struct pci_epc *epc, u8 fn,
 				struct pci_epf_bar *epf_bar)
 {
 	struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+	struct cdns_pcie_epf *epf = &ep->epf[fn];
 	struct cdns_pcie *pcie = &ep->pcie;
 	dma_addr_t bar_phys = epf_bar->phys_addr;
 	enum pci_barno bar = epf_bar->barno;
@@ -111,6 +112,8 @@ static int cdns_pcie_ep_set_bar(struct pci_epc *epc, u8 fn,
 		CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl));
 	cdns_pcie_writel(pcie, reg, cfg);
 
+	epf->epf_bar[bar] = epf_bar;
+
 	return 0;
 }
 
@@ -118,6 +121,7 @@ static void cdns_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn,
 				   struct pci_epf_bar *epf_bar)
 {
 	struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+	struct cdns_pcie_epf *epf = &ep->epf[fn];
 	struct cdns_pcie *pcie = &ep->pcie;
 	enum pci_barno bar = epf_bar->barno;
 	u32 reg, cfg, b, ctrl;
@@ -139,6 +143,8 @@ static void cdns_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn,
 
 	cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar), 0);
 	cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar), 0);
+
+	epf->epf_bar[bar] = NULL;
 }
 
 static int cdns_pcie_ep_map_addr(struct pci_epc *epc, u8 fn, phys_addr_t addr,
@@ -224,6 +230,50 @@ static int cdns_pcie_ep_get_msi(struct pci_epc *epc, u8 fn)
 	return mme;
 }
 
+static int cdns_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no)
+{
+	struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+	struct cdns_pcie *pcie = &ep->pcie;
+	u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
+	u32 val, reg;
+
+	reg = cap + PCI_MSIX_FLAGS;
+	val = cdns_pcie_ep_fn_readw(pcie, func_no, reg);
+	if (!(val & PCI_MSIX_FLAGS_ENABLE))
+		return -EINVAL;
+
+	val &= PCI_MSIX_FLAGS_QSIZE;
+
+	return val;
+}
+
+static int cdns_pcie_ep_set_msix(struct pci_epc *epc, u8 fn, u16 interrupts,
+				 enum pci_barno bir, u32 offset)
+{
+	struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+	struct cdns_pcie *pcie = &ep->pcie;
+	u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
+	u32 val, reg;
+
+	reg = cap + PCI_MSIX_FLAGS;
+	val = cdns_pcie_ep_fn_readw(pcie, fn, reg);
+	val &= ~PCI_MSIX_FLAGS_QSIZE;
+	val |= interrupts;
+	cdns_pcie_ep_fn_writew(pcie, fn, reg, val);
+
+	/* Set MSIX BAR and offset */
+	reg = cap + PCI_MSIX_TABLE;
+	val = offset | bir;
+	cdns_pcie_ep_fn_writel(pcie, fn, reg, val);
+
+	/* Set PBA BAR and offset.  BAR must match MSIX BAR */
+	reg = cap + PCI_MSIX_PBA;
+	val = (offset + (interrupts * PCI_MSIX_ENTRY_SIZE)) | bir;
+	cdns_pcie_ep_fn_writel(pcie, fn, reg, val);
+
+	return 0;
+}
+
 static void cdns_pcie_ep_assert_intx(struct cdns_pcie_ep *ep, u8 fn,
 				     u8 intx, bool is_asserted)
 {
@@ -330,6 +380,56 @@ static int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn,
 	return 0;
 }
 
+static int cdns_pcie_ep_send_msix_irq(struct cdns_pcie_ep *ep, u8 fn,
+				      u16 interrupt_num)
+{
+	u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
+	u32 tbl_offset, msg_data, reg, vec_ctrl;
+	struct cdns_pcie *pcie = &ep->pcie;
+	struct pci_epf_msix_tbl *msix_tbl;
+	struct pci_epf_bar *epf_bar;
+	struct cdns_pcie_epf *epf;
+	u64 pci_addr_mask = 0xff;
+	u64 msg_addr;
+	u16 flags;
+	u8 bir;
+
+	/* Check whether the MSI-X feature has been enabled by the PCI host. */
+	flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSIX_FLAGS);
+	if (!(flags & PCI_MSIX_FLAGS_ENABLE))
+		return -EINVAL;
+
+	reg = cap + PCI_MSIX_TABLE;
+	tbl_offset = cdns_pcie_ep_fn_readl(pcie, fn, reg);
+	bir = tbl_offset & PCI_MSIX_TABLE_BIR;
+	tbl_offset &= PCI_MSIX_TABLE_OFFSET;
+
+	epf = &ep->epf[fn];
+	epf_bar = epf->epf_bar[bir];
+	msix_tbl = epf_bar->addr;
+	msix_tbl = (struct pci_epf_msix_tbl *)((char *)msix_tbl + tbl_offset);
+
+	msg_addr = msix_tbl[(interrupt_num - 1)].msg_addr;
+	msg_data = msix_tbl[(interrupt_num - 1)].msg_data;
+	vec_ctrl = msix_tbl[(interrupt_num - 1)].vector_ctrl;
+
+	/* Set the outbound region if needed. */
+	if (ep->irq_pci_addr != (msg_addr & ~pci_addr_mask) ||
+	    ep->irq_pci_fn != fn) {
+		/* First region was reserved for IRQ writes. */
+		cdns_pcie_set_outbound_region(pcie, fn, 0,
+					      false,
+					      ep->irq_phys_addr,
+					      msg_addr & ~pci_addr_mask,
+					      pci_addr_mask + 1);
+		ep->irq_pci_addr = (msg_addr & ~pci_addr_mask);
+		ep->irq_pci_fn = fn;
+	}
+	writel(msg_data, ep->irq_cpu_addr + (msg_addr & pci_addr_mask));
+
+	return 0;
+}
+
 static int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn,
 				  enum pci_epc_irq_type type,
 				  u16 interrupt_num)
@@ -343,6 +443,9 @@ static int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn,
 	case PCI_EPC_IRQ_MSI:
 		return cdns_pcie_ep_send_msi_irq(ep, fn, interrupt_num);
 
+	case PCI_EPC_IRQ_MSIX:
+		return cdns_pcie_ep_send_msix_irq(ep, fn, interrupt_num);
+
 	default:
 		break;
 	}
@@ -380,7 +483,7 @@ static int cdns_pcie_ep_start(struct pci_epc *epc)
 static const struct pci_epc_features cdns_pcie_epc_features = {
 	.linkup_notifier = false,
 	.msi_capable = true,
-	.msix_capable = false,
+	.msix_capable = true,
 };
 
 static const struct pci_epc_features*
@@ -397,6 +500,8 @@ static const struct pci_epc_ops cdns_pcie_epc_ops = {
 	.unmap_addr	= cdns_pcie_ep_unmap_addr,
 	.set_msi	= cdns_pcie_ep_set_msi,
 	.get_msi	= cdns_pcie_ep_get_msi,
+	.set_msix	= cdns_pcie_ep_set_msix,
+	.get_msix	= cdns_pcie_ep_get_msix,
 	.raise_irq	= cdns_pcie_ep_raise_irq,
 	.start		= cdns_pcie_ep_start,
 	.get_features	= cdns_pcie_ep_get_features,
@@ -455,6 +560,11 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
 	if (of_property_read_u8(np, "max-functions", &epc->max_functions) < 0)
 		epc->max_functions = 1;
 
+	ep->epf = devm_kcalloc(dev, epc->max_functions, sizeof(*ep->epf),
+			       GFP_KERNEL);
+	if (!ep->epf)
+		return -ENOMEM;
+
 	ret = pci_epc_mem_init(epc, pcie->mem_res->start,
 			       resource_size(pcie->mem_res));
 	if (ret < 0) {
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
index 16a6b0ee547c..ea850290a602 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -99,6 +99,7 @@
 #define CDNS_PCIE_EP_FUNC_BASE(fn)	(((fn) << 12) & GENMASK(19, 12))
 
 #define CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET	0x90
+#define CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET	0xb0
 
 /*
  * Root Port Registers (PCI configuration space for the root port function)
@@ -280,6 +281,14 @@ struct cdns_pcie_rc {
 	u32			device_id;
 };
 
+/**
+ * struct cdns_pcie_epf - Structure to hold info about endpoint function
+ * @epf_bar: reference to the pci_epf_bar for the six Base Address Registers
+ */
+struct cdns_pcie_epf {
+	struct pci_epf_bar *epf_bar[PCI_STD_NUM_BARS];
+};
+
 /**
  * struct cdns_pcie_ep - private data for this PCIe endpoint controller driver
  * @pcie: Cadence PCIe controller
@@ -307,6 +316,7 @@ struct cdns_pcie_ep {
 	u64			irq_pci_addr;
 	u8			irq_pci_fn;
 	u8			irq_pending;
+	struct cdns_pcie_epf	*epf;
 };
 
 
-- 
2.17.1


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

* [PATCH v3 09/14] PCI: cadence: Add MSI-X support to Endpoint driver
@ 2020-04-17 12:57   ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: devicetree, Arnd Bergmann, Greg Kroah-Hartman, linux-kernel,
	linux-pci, linux-arm-kernel

From: Alan Douglas <adouglas@cadence.com>

Implement ->set_msix() and ->get_msix() callback functions in order
to configure MSIX capability in the PCIe endpoint controller.

Add cdns_pcie_ep_send_msix_irq() to send MSIX interrupts to Host.
cdns_pcie_ep_send_msix_irq() gets the MSIX table address (virtual
address) from "struct cdns_pcie_epf" that gets initialized in
->set_bar() call back function.

[kishon@ti.com: Re-implement MSIX support in accordance with the
 re-designed core MSI-X interfaces]
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Signed-off-by: Alan Douglas <adouglas@cadence.com>
---
 .../pci/controller/cadence/pcie-cadence-ep.c  | 112 +++++++++++++++++-
 drivers/pci/controller/cadence/pcie-cadence.h |  10 ++
 2 files changed, 121 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c
index 14021d760482..c43340ca0630 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-ep.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c
@@ -51,6 +51,7 @@ static int cdns_pcie_ep_set_bar(struct pci_epc *epc, u8 fn,
 				struct pci_epf_bar *epf_bar)
 {
 	struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+	struct cdns_pcie_epf *epf = &ep->epf[fn];
 	struct cdns_pcie *pcie = &ep->pcie;
 	dma_addr_t bar_phys = epf_bar->phys_addr;
 	enum pci_barno bar = epf_bar->barno;
@@ -111,6 +112,8 @@ static int cdns_pcie_ep_set_bar(struct pci_epc *epc, u8 fn,
 		CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl));
 	cdns_pcie_writel(pcie, reg, cfg);
 
+	epf->epf_bar[bar] = epf_bar;
+
 	return 0;
 }
 
@@ -118,6 +121,7 @@ static void cdns_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn,
 				   struct pci_epf_bar *epf_bar)
 {
 	struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+	struct cdns_pcie_epf *epf = &ep->epf[fn];
 	struct cdns_pcie *pcie = &ep->pcie;
 	enum pci_barno bar = epf_bar->barno;
 	u32 reg, cfg, b, ctrl;
@@ -139,6 +143,8 @@ static void cdns_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn,
 
 	cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar), 0);
 	cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar), 0);
+
+	epf->epf_bar[bar] = NULL;
 }
 
 static int cdns_pcie_ep_map_addr(struct pci_epc *epc, u8 fn, phys_addr_t addr,
@@ -224,6 +230,50 @@ static int cdns_pcie_ep_get_msi(struct pci_epc *epc, u8 fn)
 	return mme;
 }
 
+static int cdns_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no)
+{
+	struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+	struct cdns_pcie *pcie = &ep->pcie;
+	u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
+	u32 val, reg;
+
+	reg = cap + PCI_MSIX_FLAGS;
+	val = cdns_pcie_ep_fn_readw(pcie, func_no, reg);
+	if (!(val & PCI_MSIX_FLAGS_ENABLE))
+		return -EINVAL;
+
+	val &= PCI_MSIX_FLAGS_QSIZE;
+
+	return val;
+}
+
+static int cdns_pcie_ep_set_msix(struct pci_epc *epc, u8 fn, u16 interrupts,
+				 enum pci_barno bir, u32 offset)
+{
+	struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+	struct cdns_pcie *pcie = &ep->pcie;
+	u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
+	u32 val, reg;
+
+	reg = cap + PCI_MSIX_FLAGS;
+	val = cdns_pcie_ep_fn_readw(pcie, fn, reg);
+	val &= ~PCI_MSIX_FLAGS_QSIZE;
+	val |= interrupts;
+	cdns_pcie_ep_fn_writew(pcie, fn, reg, val);
+
+	/* Set MSIX BAR and offset */
+	reg = cap + PCI_MSIX_TABLE;
+	val = offset | bir;
+	cdns_pcie_ep_fn_writel(pcie, fn, reg, val);
+
+	/* Set PBA BAR and offset.  BAR must match MSIX BAR */
+	reg = cap + PCI_MSIX_PBA;
+	val = (offset + (interrupts * PCI_MSIX_ENTRY_SIZE)) | bir;
+	cdns_pcie_ep_fn_writel(pcie, fn, reg, val);
+
+	return 0;
+}
+
 static void cdns_pcie_ep_assert_intx(struct cdns_pcie_ep *ep, u8 fn,
 				     u8 intx, bool is_asserted)
 {
@@ -330,6 +380,56 @@ static int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn,
 	return 0;
 }
 
+static int cdns_pcie_ep_send_msix_irq(struct cdns_pcie_ep *ep, u8 fn,
+				      u16 interrupt_num)
+{
+	u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
+	u32 tbl_offset, msg_data, reg, vec_ctrl;
+	struct cdns_pcie *pcie = &ep->pcie;
+	struct pci_epf_msix_tbl *msix_tbl;
+	struct pci_epf_bar *epf_bar;
+	struct cdns_pcie_epf *epf;
+	u64 pci_addr_mask = 0xff;
+	u64 msg_addr;
+	u16 flags;
+	u8 bir;
+
+	/* Check whether the MSI-X feature has been enabled by the PCI host. */
+	flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSIX_FLAGS);
+	if (!(flags & PCI_MSIX_FLAGS_ENABLE))
+		return -EINVAL;
+
+	reg = cap + PCI_MSIX_TABLE;
+	tbl_offset = cdns_pcie_ep_fn_readl(pcie, fn, reg);
+	bir = tbl_offset & PCI_MSIX_TABLE_BIR;
+	tbl_offset &= PCI_MSIX_TABLE_OFFSET;
+
+	epf = &ep->epf[fn];
+	epf_bar = epf->epf_bar[bir];
+	msix_tbl = epf_bar->addr;
+	msix_tbl = (struct pci_epf_msix_tbl *)((char *)msix_tbl + tbl_offset);
+
+	msg_addr = msix_tbl[(interrupt_num - 1)].msg_addr;
+	msg_data = msix_tbl[(interrupt_num - 1)].msg_data;
+	vec_ctrl = msix_tbl[(interrupt_num - 1)].vector_ctrl;
+
+	/* Set the outbound region if needed. */
+	if (ep->irq_pci_addr != (msg_addr & ~pci_addr_mask) ||
+	    ep->irq_pci_fn != fn) {
+		/* First region was reserved for IRQ writes. */
+		cdns_pcie_set_outbound_region(pcie, fn, 0,
+					      false,
+					      ep->irq_phys_addr,
+					      msg_addr & ~pci_addr_mask,
+					      pci_addr_mask + 1);
+		ep->irq_pci_addr = (msg_addr & ~pci_addr_mask);
+		ep->irq_pci_fn = fn;
+	}
+	writel(msg_data, ep->irq_cpu_addr + (msg_addr & pci_addr_mask));
+
+	return 0;
+}
+
 static int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn,
 				  enum pci_epc_irq_type type,
 				  u16 interrupt_num)
@@ -343,6 +443,9 @@ static int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn,
 	case PCI_EPC_IRQ_MSI:
 		return cdns_pcie_ep_send_msi_irq(ep, fn, interrupt_num);
 
+	case PCI_EPC_IRQ_MSIX:
+		return cdns_pcie_ep_send_msix_irq(ep, fn, interrupt_num);
+
 	default:
 		break;
 	}
@@ -380,7 +483,7 @@ static int cdns_pcie_ep_start(struct pci_epc *epc)
 static const struct pci_epc_features cdns_pcie_epc_features = {
 	.linkup_notifier = false,
 	.msi_capable = true,
-	.msix_capable = false,
+	.msix_capable = true,
 };
 
 static const struct pci_epc_features*
@@ -397,6 +500,8 @@ static const struct pci_epc_ops cdns_pcie_epc_ops = {
 	.unmap_addr	= cdns_pcie_ep_unmap_addr,
 	.set_msi	= cdns_pcie_ep_set_msi,
 	.get_msi	= cdns_pcie_ep_get_msi,
+	.set_msix	= cdns_pcie_ep_set_msix,
+	.get_msix	= cdns_pcie_ep_get_msix,
 	.raise_irq	= cdns_pcie_ep_raise_irq,
 	.start		= cdns_pcie_ep_start,
 	.get_features	= cdns_pcie_ep_get_features,
@@ -455,6 +560,11 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
 	if (of_property_read_u8(np, "max-functions", &epc->max_functions) < 0)
 		epc->max_functions = 1;
 
+	ep->epf = devm_kcalloc(dev, epc->max_functions, sizeof(*ep->epf),
+			       GFP_KERNEL);
+	if (!ep->epf)
+		return -ENOMEM;
+
 	ret = pci_epc_mem_init(epc, pcie->mem_res->start,
 			       resource_size(pcie->mem_res));
 	if (ret < 0) {
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
index 16a6b0ee547c..ea850290a602 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -99,6 +99,7 @@
 #define CDNS_PCIE_EP_FUNC_BASE(fn)	(((fn) << 12) & GENMASK(19, 12))
 
 #define CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET	0x90
+#define CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET	0xb0
 
 /*
  * Root Port Registers (PCI configuration space for the root port function)
@@ -280,6 +281,14 @@ struct cdns_pcie_rc {
 	u32			device_id;
 };
 
+/**
+ * struct cdns_pcie_epf - Structure to hold info about endpoint function
+ * @epf_bar: reference to the pci_epf_bar for the six Base Address Registers
+ */
+struct cdns_pcie_epf {
+	struct pci_epf_bar *epf_bar[PCI_STD_NUM_BARS];
+};
+
 /**
  * struct cdns_pcie_ep - private data for this PCIe endpoint controller driver
  * @pcie: Cadence PCIe controller
@@ -307,6 +316,7 @@ struct cdns_pcie_ep {
 	u64			irq_pci_addr;
 	u8			irq_pci_fn;
 	u8			irq_pending;
+	struct cdns_pcie_epf	*epf;
 };
 
 
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v3 10/14] dt-bindings: PCI: Add host mode dt-bindings for TI's J721E SoC
  2020-04-17 12:57 ` Kishon Vijay Abraham I
@ 2020-04-17 12:57   ` Kishon Vijay Abraham I
  -1 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: Arnd Bergmann, Greg Kroah-Hartman, linux-arm-kernel, linux-pci,
	devicetree, linux-kernel

Add host mode dt-bindings for TI's J721E SoC.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 .../bindings/pci/ti,j721e-pci-host.yaml       | 113 ++++++++++++++++++
 1 file changed, 113 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml

diff --git a/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml b/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml
new file mode 100644
index 000000000000..d8d3011fd578
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml
@@ -0,0 +1,113 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/pci/ti,j721e-pci-host.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: TI J721E PCI Host (PCIe Wrapper)
+
+maintainers:
+  - Kishon Vijay Abraham I <kishon@ti.com>
+
+allOf:
+  - $ref: "cdns-pcie-host.yaml#"
+
+properties:
+  compatible:
+      enum:
+        - ti,j721e-pcie-host
+
+  reg:
+    maxItems: 4
+
+  reg-names:
+    items:
+      - const: intd_cfg
+      - const: user_cfg
+      - const: reg
+      - const: cfg
+
+  ti,syscon-pcie-ctrl:
+    description: Phandle to the SYSCON entry required for configuring PCIe mode
+      and link speed.
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/phandle
+
+  power-domains:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+    description: clock-specifier to represent input to the PCIe
+
+  clock-names:
+    items:
+      - const: fck
+
+  vendor-id:
+    const: 0x104c
+
+  device-id:
+    const: 0xb00d
+
+  msi-map: true
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - ti,syscon-pcie-ctrl
+  - max-link-speed
+  - num-lanes
+  - power-domains
+  - clocks
+  - clock-names
+  - vendor-id
+  - device-id
+  - msi-map
+  - dma-coherent
+  - dma-ranges
+  - ranges
+  - reset-gpios
+  - phys
+  - phy-names
+
+examples:
+  - |
+    #include <dt-bindings/soc/ti,sci_pm_domain.h>
+    #include <dt-bindings/gpio/gpio.h>
+
+    bus {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        pcie0_rc: pcie@2900000 {
+            compatible = "ti,j721e-pcie-host";
+            reg = <0x00 0x02900000 0x00 0x1000>,
+                  <0x00 0x02907000 0x00 0x400>,
+                  <0x00 0x0d000000 0x00 0x00800000>,
+                  <0x00 0x10000000 0x00 0x00001000>;
+            reg-names = "intd_cfg", "user_cfg", "reg", "cfg";
+            ti,syscon-pcie-ctrl = <&pcie0_ctrl>;
+            max-link-speed = <3>;
+            num-lanes = <2>;
+            power-domains = <&k3_pds 239 TI_SCI_PD_EXCLUSIVE>;
+            clocks = <&k3_clks 239 1>;
+            clock-names = "fck";
+            device_type = "pci";
+            #address-cells = <3>;
+            #size-cells = <2>;
+            bus-range = <0x0 0xf>;
+            vendor-id = <0x104c>;
+            device-id = <0xb00d>;
+            msi-map = <0x0 &gic_its 0x0 0x10000>;
+            dma-coherent;
+            reset-gpios = <&exp1 6 GPIO_ACTIVE_HIGH>;
+            phys = <&serdes0_pcie_link>;
+            phy-names = "pcie-phy";
+            ranges = <0x01000000 0x0 0x10001000  0x00 0x10001000  0x0 0x0010000>,
+                     <0x02000000 0x0 0x10011000  0x00 0x10011000  0x0 0x7fef000>;
+            dma-ranges = <0x02000000 0x0 0x0 0x0 0x0 0x10000 0x0>;
+        };
+    };
-- 
2.17.1


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

* [PATCH v3 10/14] dt-bindings: PCI: Add host mode dt-bindings for TI's J721E SoC
@ 2020-04-17 12:57   ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: devicetree, Arnd Bergmann, Greg Kroah-Hartman, linux-kernel,
	linux-pci, linux-arm-kernel

Add host mode dt-bindings for TI's J721E SoC.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 .../bindings/pci/ti,j721e-pci-host.yaml       | 113 ++++++++++++++++++
 1 file changed, 113 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml

diff --git a/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml b/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml
new file mode 100644
index 000000000000..d8d3011fd578
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml
@@ -0,0 +1,113 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/pci/ti,j721e-pci-host.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: TI J721E PCI Host (PCIe Wrapper)
+
+maintainers:
+  - Kishon Vijay Abraham I <kishon@ti.com>
+
+allOf:
+  - $ref: "cdns-pcie-host.yaml#"
+
+properties:
+  compatible:
+      enum:
+        - ti,j721e-pcie-host
+
+  reg:
+    maxItems: 4
+
+  reg-names:
+    items:
+      - const: intd_cfg
+      - const: user_cfg
+      - const: reg
+      - const: cfg
+
+  ti,syscon-pcie-ctrl:
+    description: Phandle to the SYSCON entry required for configuring PCIe mode
+      and link speed.
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/phandle
+
+  power-domains:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+    description: clock-specifier to represent input to the PCIe
+
+  clock-names:
+    items:
+      - const: fck
+
+  vendor-id:
+    const: 0x104c
+
+  device-id:
+    const: 0xb00d
+
+  msi-map: true
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - ti,syscon-pcie-ctrl
+  - max-link-speed
+  - num-lanes
+  - power-domains
+  - clocks
+  - clock-names
+  - vendor-id
+  - device-id
+  - msi-map
+  - dma-coherent
+  - dma-ranges
+  - ranges
+  - reset-gpios
+  - phys
+  - phy-names
+
+examples:
+  - |
+    #include <dt-bindings/soc/ti,sci_pm_domain.h>
+    #include <dt-bindings/gpio/gpio.h>
+
+    bus {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        pcie0_rc: pcie@2900000 {
+            compatible = "ti,j721e-pcie-host";
+            reg = <0x00 0x02900000 0x00 0x1000>,
+                  <0x00 0x02907000 0x00 0x400>,
+                  <0x00 0x0d000000 0x00 0x00800000>,
+                  <0x00 0x10000000 0x00 0x00001000>;
+            reg-names = "intd_cfg", "user_cfg", "reg", "cfg";
+            ti,syscon-pcie-ctrl = <&pcie0_ctrl>;
+            max-link-speed = <3>;
+            num-lanes = <2>;
+            power-domains = <&k3_pds 239 TI_SCI_PD_EXCLUSIVE>;
+            clocks = <&k3_clks 239 1>;
+            clock-names = "fck";
+            device_type = "pci";
+            #address-cells = <3>;
+            #size-cells = <2>;
+            bus-range = <0x0 0xf>;
+            vendor-id = <0x104c>;
+            device-id = <0xb00d>;
+            msi-map = <0x0 &gic_its 0x0 0x10000>;
+            dma-coherent;
+            reset-gpios = <&exp1 6 GPIO_ACTIVE_HIGH>;
+            phys = <&serdes0_pcie_link>;
+            phy-names = "pcie-phy";
+            ranges = <0x01000000 0x0 0x10001000  0x00 0x10001000  0x0 0x0010000>,
+                     <0x02000000 0x0 0x10011000  0x00 0x10011000  0x0 0x7fef000>;
+            dma-ranges = <0x02000000 0x0 0x0 0x0 0x0 0x10000 0x0>;
+        };
+    };
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v3 11/14] dt-bindings: PCI: Add EP mode dt-bindings for TI's J721E SoC
  2020-04-17 12:57 ` Kishon Vijay Abraham I
@ 2020-04-17 12:57   ` Kishon Vijay Abraham I
  -1 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: Arnd Bergmann, Greg Kroah-Hartman, linux-arm-kernel, linux-pci,
	devicetree, linux-kernel

Add PCIe EP mode dt-bindings for TI's J721E SoC.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 .../bindings/pci/ti,j721e-pci-ep.yaml         | 89 +++++++++++++++++++
 1 file changed, 89 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml

diff --git a/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml b/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml
new file mode 100644
index 000000000000..cb25c45d5a96
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml
@@ -0,0 +1,89 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/pci/ti,j721e-pci-ep.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: TI J721E PCI EP (PCIe Wrapper)
+
+maintainers:
+  - Kishon Vijay Abraham I <kishon@ti.com>
+
+allOf:
+  - $ref: "cdns-pcie-ep.yaml#"
+
+properties:
+  compatible:
+      enum:
+          - ti,j721e-pcie-ep
+
+  reg:
+    maxItems: 4
+
+  reg-names:
+    items:
+      - const: intd_cfg
+      - const: user_cfg
+      - const: reg
+      - const: mem
+
+  ti,syscon-pcie-ctrl:
+    description: Phandle to the SYSCON entry required for configuring PCIe mode
+                 and link speed.
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/phandle
+
+  power-domains:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+    description: clock-specifier to represent input to the PCIe
+
+  clock-names:
+    items:
+      - const: fck
+
+  dma-coherent:
+    description: Indicates that the PCIe IP block can ensure the coherency
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - ti,syscon-pcie-ctrl
+  - max-link-speed
+  - num-lanes
+  - power-domains
+  - clocks
+  - clock-names
+  - cdns,max-outbound-regions
+  - dma-coherent
+  - max-functions
+  - phys
+  - phy-names
+
+examples:
+  - |
+    #include <dt-bindings/soc/ti,sci_pm_domain.h>
+
+     pcie0_ep: pcie-ep@d000000 {
+            compatible = "ti,j721e-pcie-ep";
+            reg = <0x00 0x02900000 0x00 0x1000>,
+                  <0x00 0x02907000 0x00 0x400>,
+                  <0x00 0x0d000000 0x00 0x00800000>,
+                  <0x00 0x10000000 0x00 0x08000000>;
+            reg-names = "intd_cfg", "user_cfg", "reg", "mem";
+            ti,syscon-pcie-ctrl = <&pcie0_ctrl>;
+            max-link-speed = <3>;
+            num-lanes = <2>;
+            power-domains = <&k3_pds 239 TI_SCI_PD_EXCLUSIVE>;
+            clocks = <&k3_clks 239 1>;
+            clock-names = "fck";
+            cdns,max-outbound-regions = <16>;
+            max-functions = /bits/ 8 <6>;
+            dma-coherent;
+            phys = <&serdes0_pcie_link>;
+            phy-names = "pcie-phy";
+    };
-- 
2.17.1


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

* [PATCH v3 11/14] dt-bindings: PCI: Add EP mode dt-bindings for TI's J721E SoC
@ 2020-04-17 12:57   ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: devicetree, Arnd Bergmann, Greg Kroah-Hartman, linux-kernel,
	linux-pci, linux-arm-kernel

Add PCIe EP mode dt-bindings for TI's J721E SoC.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 .../bindings/pci/ti,j721e-pci-ep.yaml         | 89 +++++++++++++++++++
 1 file changed, 89 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml

diff --git a/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml b/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml
new file mode 100644
index 000000000000..cb25c45d5a96
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml
@@ -0,0 +1,89 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/pci/ti,j721e-pci-ep.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: TI J721E PCI EP (PCIe Wrapper)
+
+maintainers:
+  - Kishon Vijay Abraham I <kishon@ti.com>
+
+allOf:
+  - $ref: "cdns-pcie-ep.yaml#"
+
+properties:
+  compatible:
+      enum:
+          - ti,j721e-pcie-ep
+
+  reg:
+    maxItems: 4
+
+  reg-names:
+    items:
+      - const: intd_cfg
+      - const: user_cfg
+      - const: reg
+      - const: mem
+
+  ti,syscon-pcie-ctrl:
+    description: Phandle to the SYSCON entry required for configuring PCIe mode
+                 and link speed.
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/phandle
+
+  power-domains:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+    description: clock-specifier to represent input to the PCIe
+
+  clock-names:
+    items:
+      - const: fck
+
+  dma-coherent:
+    description: Indicates that the PCIe IP block can ensure the coherency
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - ti,syscon-pcie-ctrl
+  - max-link-speed
+  - num-lanes
+  - power-domains
+  - clocks
+  - clock-names
+  - cdns,max-outbound-regions
+  - dma-coherent
+  - max-functions
+  - phys
+  - phy-names
+
+examples:
+  - |
+    #include <dt-bindings/soc/ti,sci_pm_domain.h>
+
+     pcie0_ep: pcie-ep@d000000 {
+            compatible = "ti,j721e-pcie-ep";
+            reg = <0x00 0x02900000 0x00 0x1000>,
+                  <0x00 0x02907000 0x00 0x400>,
+                  <0x00 0x0d000000 0x00 0x00800000>,
+                  <0x00 0x10000000 0x00 0x08000000>;
+            reg-names = "intd_cfg", "user_cfg", "reg", "mem";
+            ti,syscon-pcie-ctrl = <&pcie0_ctrl>;
+            max-link-speed = <3>;
+            num-lanes = <2>;
+            power-domains = <&k3_pds 239 TI_SCI_PD_EXCLUSIVE>;
+            clocks = <&k3_clks 239 1>;
+            clock-names = "fck";
+            cdns,max-outbound-regions = <16>;
+            max-functions = /bits/ 8 <6>;
+            dma-coherent;
+            phys = <&serdes0_pcie_link>;
+            phy-names = "pcie-phy";
+    };
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v3 12/14] PCI: j721e: Add TI J721E PCIe driver
  2020-04-17 12:57 ` Kishon Vijay Abraham I
@ 2020-04-17 12:57   ` Kishon Vijay Abraham I
  -1 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: Arnd Bergmann, Greg Kroah-Hartman, linux-arm-kernel, linux-pci,
	devicetree, linux-kernel

Add support for PCIe controller in J721E SoC. The controller uses the
Cadence PCIe core programmed by pcie-cadence*.c. The PCIe controller
will work in both host mode and device mode.
Some of the features of the controller are:
  *) Supports both RC mode and EP mode
  *) Supports MSI and MSI-X support
  *) Supports upto GEN3 speed mode
  *) Supports SR-IOV capability
  *) Ability to route all transactions via SMMU (support will be added
     in a later patch).

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/pci/controller/cadence/Kconfig        |  23 +
 drivers/pci/controller/cadence/Makefile       |   1 +
 drivers/pci/controller/cadence/pci-j721e.c    | 500 ++++++++++++++++++
 .../controller/cadence/pcie-cadence-host.c    |   4 +-
 drivers/pci/controller/cadence/pcie-cadence.h |   8 +
 5 files changed, 534 insertions(+), 2 deletions(-)
 create mode 100644 drivers/pci/controller/cadence/pci-j721e.c

diff --git a/drivers/pci/controller/cadence/Kconfig b/drivers/pci/controller/cadence/Kconfig
index b76b3cf55ce5..5d30564190e1 100644
--- a/drivers/pci/controller/cadence/Kconfig
+++ b/drivers/pci/controller/cadence/Kconfig
@@ -42,4 +42,27 @@ config PCIE_CADENCE_PLAT_EP
 	  endpoint mode. This PCIe controller may be embedded into many
 	  different vendors SoCs.
 
+config PCI_J721E
+	bool
+
+config PCI_J721E_HOST
+	bool "TI J721E PCIe platform host controller"
+	depends on OF
+	select PCIE_CADENCE_HOST
+	select PCI_J721E
+	help
+	  Say Y here if you want to support the TI J721E PCIe platform
+	  controller in host mode. TI J721E PCIe controller uses Cadence PCIe
+	  core.
+
+config PCI_J721E_EP
+	bool "TI J721E PCIe platform endpoint controller"
+	depends on OF
+	depends on PCI_ENDPOINT
+	select PCIE_CADENCE_EP
+	select PCI_J721E
+	help
+	  Say Y here if you want to support the TI J721E PCIe platform
+	  controller in endpoint mode. TI J721E PCIe controller uses Cadence PCIe
+	  core.
 endmenu
diff --git a/drivers/pci/controller/cadence/Makefile b/drivers/pci/controller/cadence/Makefile
index 232a3f20876a..9bac5fb2f13d 100644
--- a/drivers/pci/controller/cadence/Makefile
+++ b/drivers/pci/controller/cadence/Makefile
@@ -3,3 +3,4 @@ obj-$(CONFIG_PCIE_CADENCE) += pcie-cadence.o
 obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o
 obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep.o
 obj-$(CONFIG_PCIE_CADENCE_PLAT) += pcie-cadence-plat.o
+obj-$(CONFIG_PCI_J721E) += pci-j721e.o
diff --git a/drivers/pci/controller/cadence/pci-j721e.c b/drivers/pci/controller/cadence/pci-j721e.c
new file mode 100644
index 000000000000..eee619c6ffae
--- /dev/null
+++ b/drivers/pci/controller/cadence/pci-j721e.c
@@ -0,0 +1,500 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * pci-j721e - PCIe controller driver for TI's J721E SoCs
+ *
+ * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/io.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/pci.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include "../../pci.h"
+#include "pcie-cadence.h"
+
+#define ENABLE_REG_SYS_2	0x108
+#define STATUS_REG_SYS_2	0x508
+#define STATUS_CLR_REG_SYS_2	0x708
+#define LINK_DOWN		BIT(1)
+
+#define J721E_PCIE_USER_CMD_STATUS	0x4
+#define LINK_TRAINING_ENABLE		BIT(0)
+
+#define J721E_PCIE_USER_LINKSTATUS	0x14
+#define LINK_STATUS			GENMASK(1, 0)
+
+enum link_status {
+	NO_RECEIVERS_DETECTED,
+	LINK_TRAINING_IN_PROGRESS,
+	LINK_UP_DL_IN_PROGRESS,
+	LINK_UP_DL_COMPLETED,
+};
+
+#define J721E_MODE_RC			BIT(7)
+#define LANE_COUNT_MASK			BIT(8)
+#define LANE_COUNT(n)			((n) << 8)
+
+#define GENERATION_SEL_MASK		GENMASK(1, 0)
+
+#define MAX_LANES			2
+
+struct j721e_pcie {
+	struct device		*dev;
+	struct device_node	*node;
+	u32			mode;
+	u32			num_lanes;
+	struct cdns_pcie	*cdns_pcie;
+	void __iomem		*user_cfg_base;
+	void __iomem		*intd_cfg_base;
+};
+
+enum j721e_pcie_mode {
+	PCI_MODE_RC,
+	PCI_MODE_EP,
+};
+
+struct j721e_pcie_data {
+	enum j721e_pcie_mode	mode;
+};
+
+static inline u32 j721e_pcie_user_readl(struct j721e_pcie *pcie, u32 offset)
+{
+	return readl(pcie->user_cfg_base + offset);
+}
+
+static inline void j721e_pcie_user_writel(struct j721e_pcie *pcie, u32 offset,
+					  u32 value)
+{
+	writel(value, pcie->user_cfg_base + offset);
+}
+
+static inline u32 j721e_pcie_intd_readl(struct j721e_pcie *pcie, u32 offset)
+{
+	return readl(pcie->intd_cfg_base + offset);
+}
+
+static inline void j721e_pcie_intd_writel(struct j721e_pcie *pcie, u32 offset,
+					  u32 value)
+{
+	writel(value, pcie->intd_cfg_base + offset);
+}
+
+static irqreturn_t j721e_pcie_link_irq_handler(int irq, void *priv)
+{
+	struct j721e_pcie *pcie = priv;
+	struct device *dev = pcie->dev;
+	u32 reg;
+
+	reg = j721e_pcie_intd_readl(pcie, STATUS_REG_SYS_2);
+	if (!(reg & LINK_DOWN))
+		return IRQ_NONE;
+
+	dev_err(dev, "LINK DOWN!\n");
+
+	j721e_pcie_intd_writel(pcie, STATUS_CLR_REG_SYS_2, LINK_DOWN);
+	return IRQ_HANDLED;
+}
+
+static void j721e_pcie_config_link_irq(struct j721e_pcie *pcie)
+{
+	u32 reg;
+
+	reg = j721e_pcie_intd_readl(pcie, ENABLE_REG_SYS_2);
+	reg |= LINK_DOWN;
+	j721e_pcie_intd_writel(pcie, ENABLE_REG_SYS_2, reg);
+}
+
+static int j721e_pcie_start_link(struct cdns_pcie *cdns_pcie)
+{
+	struct j721e_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
+	u32 reg;
+
+	reg = j721e_pcie_user_readl(pcie, J721E_PCIE_USER_CMD_STATUS);
+	reg |= LINK_TRAINING_ENABLE;
+	j721e_pcie_user_writel(pcie, J721E_PCIE_USER_CMD_STATUS, reg);
+
+	return 0;
+}
+
+static void j721e_pcie_stop_link(struct cdns_pcie *cdns_pcie)
+{
+	struct j721e_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
+	u32 reg;
+
+	reg = j721e_pcie_user_readl(pcie, J721E_PCIE_USER_CMD_STATUS);
+	reg &= ~LINK_TRAINING_ENABLE;
+	j721e_pcie_user_writel(pcie, J721E_PCIE_USER_CMD_STATUS, reg);
+}
+
+static bool j721e_pcie_link_up(struct cdns_pcie *cdns_pcie)
+{
+	struct j721e_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
+	u32 reg;
+
+	reg = j721e_pcie_user_readl(pcie, J721E_PCIE_USER_LINKSTATUS);
+	reg &= LINK_STATUS;
+	if (reg == LINK_UP_DL_COMPLETED)
+		return true;
+
+	return false;
+}
+
+static const struct cdns_pcie_ops j721e_ops_ops = {
+	.read = cdns_platform_pcie_read32,
+	.write = cdns_platform_pcie_write32,
+	.start_link = j721e_pcie_start_link,
+	.stop_link = j721e_pcie_stop_link,
+	.link_up = j721e_pcie_link_up,
+};
+
+static int j721e_pcie_set_mode(struct j721e_pcie *pcie, struct regmap *syscon)
+{
+	struct device *dev = pcie->dev;
+	u32 mask = J721E_MODE_RC;
+	u32 mode = pcie->mode;
+	u32 val = 0;
+	int ret = 0;
+
+	if (mode == PCI_MODE_RC)
+		val = J721E_MODE_RC;
+
+	ret = regmap_update_bits(syscon, 0, mask, val);
+	if (ret)
+		dev_err(dev, "failed to set pcie mode\n");
+
+	return ret;
+}
+
+static int j721e_pcie_set_link_speed(struct j721e_pcie *pcie,
+				     struct regmap *syscon)
+{
+	struct device *dev = pcie->dev;
+	struct device_node *np = dev->of_node;
+	int link_speed;
+	u32 val = 0;
+	int ret;
+
+	link_speed = of_pci_get_max_link_speed(np);
+	if (link_speed < 2)
+		link_speed = 2;
+
+	val = link_speed - 1;
+	ret = regmap_update_bits(syscon, 0, GENERATION_SEL_MASK, val);
+	if (ret)
+		dev_err(dev, "failed to set link speed\n");
+
+	return ret;
+}
+
+static int j721e_pcie_set_lane_count(struct j721e_pcie *pcie,
+				     struct regmap *syscon)
+{
+	struct device *dev = pcie->dev;
+	u32 lanes = pcie->num_lanes;
+	u32 val = 0;
+	int ret;
+
+	val = LANE_COUNT(lanes - 1);
+	ret = regmap_update_bits(syscon, 0, LANE_COUNT_MASK, val);
+	if (ret)
+		dev_err(dev, "failed to set link count\n");
+
+	return ret;
+}
+
+static int j721e_pcie_ctrl_init(struct j721e_pcie *pcie)
+{
+	struct device *dev = pcie->dev;
+	struct device_node *node = dev->of_node;
+	struct regmap *syscon;
+	int ret;
+
+	syscon = syscon_regmap_lookup_by_phandle(node, "ti,syscon-pcie-ctrl");
+	if (IS_ERR(syscon)) {
+		dev_err(dev, "Unable to get ti,syscon-pcie-ctrl regmap\n");
+		return PTR_ERR(syscon);
+	}
+
+	ret = j721e_pcie_set_mode(pcie, syscon);
+	if (ret < 0) {
+		dev_err(dev, "Failed to set pci mode\n");
+		return ret;
+	}
+
+	ret = j721e_pcie_set_link_speed(pcie, syscon);
+	if (ret < 0) {
+		dev_err(dev, "Failed to set link speed\n");
+		return ret;
+	}
+
+	ret = j721e_pcie_set_lane_count(pcie, syscon);
+	if (ret < 0) {
+		dev_err(dev, "Failed to set num-lanes\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int cdns_ti_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
+				    int where, int size, u32 *value)
+{
+	struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
+	struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge);
+	unsigned int busn = bus->number;
+
+	if (busn == rc->bus_range->start)
+		return pci_generic_config_read32(bus, devfn, where, size,
+						 value);
+
+	return pci_generic_config_read(bus, devfn, where, size, value);
+}
+
+static int cdns_ti_pcie_config_write(struct pci_bus *bus, unsigned int devfn,
+				     int where, int size, u32 value)
+{
+	struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
+	struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge);
+	unsigned int busn = bus->number;
+
+	if (busn == rc->bus_range->start)
+		return pci_generic_config_write32(bus, devfn, where, size,
+						  value);
+
+	return pci_generic_config_write(bus, devfn, where, size, value);
+}
+
+static struct pci_ops cdns_ti_pcie_host_ops = {
+	.map_bus	= cdns_pci_map_bus,
+	.read		= cdns_ti_pcie_config_read,
+	.write		= cdns_ti_pcie_config_write,
+};
+
+static const struct j721e_pcie_data j721e_pcie_rc_data = {
+	.mode = PCI_MODE_RC,
+};
+
+static const struct j721e_pcie_data j721e_pcie_ep_data = {
+	.mode = PCI_MODE_EP,
+};
+
+static const struct of_device_id of_j721e_pcie_match[] = {
+	{
+		.compatible = "ti,j721e-pcie-host",
+		.data = &j721e_pcie_rc_data,
+	},
+	{
+		.compatible = "ti,j721e-pcie-ep",
+		.data = &j721e_pcie_ep_data,
+	},
+	{},
+};
+
+static int j721e_pcie_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *node = dev->of_node;
+	const struct of_device_id *match;
+	struct pci_host_bridge *bridge;
+	struct j721e_pcie_data *data;
+	struct cdns_pcie *cdns_pcie;
+	struct j721e_pcie *pcie;
+	struct cdns_pcie_rc *rc;
+	struct cdns_pcie_ep *ep;
+	struct gpio_desc *gpiod;
+	struct resource *res;
+	void __iomem *base;
+	u32 num_lanes;
+	u32 mode;
+	int ret;
+	int irq;
+
+	match = of_match_device(of_match_ptr(of_j721e_pcie_match), dev);
+	if (!match)
+		return -EINVAL;
+
+	data = (struct j721e_pcie_data *)match->data;
+	mode = (u32)data->mode;
+
+	pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
+	if (!pcie)
+		return -ENOMEM;
+
+	pcie->dev = dev;
+	pcie->node = node;
+	pcie->mode = mode;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intd_cfg");
+	base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+	pcie->intd_cfg_base = base;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "user_cfg");
+	base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+	pcie->user_cfg_base = base;
+
+	ret = of_property_read_u32(node, "num-lanes", &num_lanes);
+	if (ret || num_lanes > MAX_LANES)
+		num_lanes = 1;
+	pcie->num_lanes = num_lanes;
+
+	irq = platform_get_irq_byname(pdev, "link_state");
+	if (irq < 0)
+		return irq;
+
+	dev_set_drvdata(dev, pcie);
+	pm_runtime_enable(dev);
+	ret = pm_runtime_get_sync(dev);
+	if (ret < 0) {
+		dev_err(dev, "pm_runtime_get_sync failed\n");
+		goto err_get_sync;
+	}
+
+	ret = j721e_pcie_ctrl_init(pcie);
+	if (ret < 0) {
+		dev_err(dev, "pm_runtime_get_sync failed\n");
+		goto err_get_sync;
+	}
+
+	ret = devm_request_irq(dev, irq, j721e_pcie_link_irq_handler,
+			       IRQF_SHARED, "j721e-pcie-link_state-irq", pcie);
+	if (ret < 0) {
+		dev_err(dev, "failed to request link state IRQ %d\n", irq);
+		goto err_get_sync;
+	}
+
+	j721e_pcie_config_link_irq(pcie);
+
+	switch (mode) {
+	case PCI_MODE_RC:
+		if (!IS_ENABLED(CONFIG_PCIE_CADENCE_HOST)) {
+			ret = -ENODEV;
+			goto err_get_sync;
+		}
+
+		bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
+		if (!bridge) {
+			ret = -ENOMEM;
+			goto err_get_sync;
+		}
+
+		bridge->ops = &cdns_ti_pcie_host_ops;
+		rc = pci_host_bridge_priv(bridge);
+
+		cdns_pcie = &rc->pcie;
+		cdns_pcie->dev = dev;
+		cdns_pcie->ops = &j721e_ops_ops;
+		pcie->cdns_pcie = cdns_pcie;
+
+		gpiod = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+		if (IS_ERR(gpiod)) {
+			ret = PTR_ERR(gpiod);
+			if (ret != -EPROBE_DEFER)
+				dev_err(dev, "Failed to get reset GPIO\n");
+			goto err_get_sync;
+		}
+
+		ret = cdns_pcie_init_phy(dev, cdns_pcie);
+		if (ret) {
+			dev_err(dev, "Failed to init phy\n");
+			goto err_get_sync;
+		}
+
+		/*
+		 * "Power Sequencing and Reset Signal Timings" table in
+		 * PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 3.0
+		 * indicates PERST# should be deasserted after minimum of 100us
+		 * once REFCLK is stable. The REFCLK to the connector in RC
+		 * mode is selected while enabling the PHY. So deassert PERST#
+		 * after 100 us.
+		 */
+		if (gpiod) {
+			usleep_range(100, 200);
+			gpiod_set_value_cansleep(gpiod, 1);
+		}
+
+		ret = cdns_pcie_host_setup(rc);
+		if (ret < 0)
+			goto err_pcie_setup;
+
+		break;
+	case PCI_MODE_EP:
+		if (!IS_ENABLED(CONFIG_PCIE_CADENCE_EP)) {
+			ret = -ENODEV;
+			goto err_get_sync;
+		}
+
+		ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
+		if (!ep) {
+			ret = -ENOMEM;
+			goto err_get_sync;
+		}
+
+		cdns_pcie = &ep->pcie;
+		cdns_pcie->dev = dev;
+		cdns_pcie->ops = &j721e_ops_ops;
+		pcie->cdns_pcie = cdns_pcie;
+
+		ret = cdns_pcie_init_phy(dev, cdns_pcie);
+		if (ret) {
+			dev_err(dev, "Failed to init phy\n");
+			goto err_get_sync;
+		}
+
+		ret = cdns_pcie_ep_setup(ep);
+		if (ret < 0)
+			goto err_pcie_setup;
+
+		break;
+	default:
+		dev_err(dev, "INVALID device type %d\n", mode);
+	}
+
+	return 0;
+
+err_pcie_setup:
+	cdns_pcie_disable_phy(cdns_pcie);
+
+err_get_sync:
+	pm_runtime_put(dev);
+	pm_runtime_disable(dev);
+
+	return ret;
+}
+
+static int j721e_pcie_remove(struct platform_device *pdev)
+{
+	struct j721e_pcie *pcie = platform_get_drvdata(pdev);
+	struct cdns_pcie *cdns_pcie = pcie->cdns_pcie;
+	struct device *dev = &pdev->dev;
+
+	cdns_pcie_disable_phy(cdns_pcie);
+	pm_runtime_put(dev);
+	pm_runtime_disable(dev);
+	of_platform_depopulate(dev);
+
+	return 0;
+}
+
+static struct platform_driver j721e_pcie_driver = {
+	.probe  = j721e_pcie_probe,
+	.remove = j721e_pcie_remove,
+	.driver = {
+		.name	= "j721e-pcie",
+		.of_match_table = of_j721e_pcie_match,
+		.suppress_bind_attrs = true,
+	},
+};
+builtin_platform_driver(j721e_pcie_driver);
diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c
index c7dc7be0da40..d7cc7ea4fba3 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -11,8 +11,8 @@
 
 #include "pcie-cadence.h"
 
-static void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
-				      int where)
+void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
+			       int where)
 {
 	struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
 	struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge);
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
index ea850290a602..f349f5828a58 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -488,11 +488,19 @@ static inline bool cdns_pcie_link_up(struct cdns_pcie *pcie)
 
 #ifdef CONFIG_PCIE_CADENCE_HOST
 int cdns_pcie_host_setup(struct cdns_pcie_rc *rc);
+void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
+			       int where);
 #else
 static inline int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
 {
 	return 0;
 }
+
+static void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
+				      int where)
+{
+	return NULL;
+}
 #endif
 
 #ifdef CONFIG_PCIE_CADENCE_EP
-- 
2.17.1


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

* [PATCH v3 12/14] PCI: j721e: Add TI J721E PCIe driver
@ 2020-04-17 12:57   ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: devicetree, Arnd Bergmann, Greg Kroah-Hartman, linux-kernel,
	linux-pci, linux-arm-kernel

Add support for PCIe controller in J721E SoC. The controller uses the
Cadence PCIe core programmed by pcie-cadence*.c. The PCIe controller
will work in both host mode and device mode.
Some of the features of the controller are:
  *) Supports both RC mode and EP mode
  *) Supports MSI and MSI-X support
  *) Supports upto GEN3 speed mode
  *) Supports SR-IOV capability
  *) Ability to route all transactions via SMMU (support will be added
     in a later patch).

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/pci/controller/cadence/Kconfig        |  23 +
 drivers/pci/controller/cadence/Makefile       |   1 +
 drivers/pci/controller/cadence/pci-j721e.c    | 500 ++++++++++++++++++
 .../controller/cadence/pcie-cadence-host.c    |   4 +-
 drivers/pci/controller/cadence/pcie-cadence.h |   8 +
 5 files changed, 534 insertions(+), 2 deletions(-)
 create mode 100644 drivers/pci/controller/cadence/pci-j721e.c

diff --git a/drivers/pci/controller/cadence/Kconfig b/drivers/pci/controller/cadence/Kconfig
index b76b3cf55ce5..5d30564190e1 100644
--- a/drivers/pci/controller/cadence/Kconfig
+++ b/drivers/pci/controller/cadence/Kconfig
@@ -42,4 +42,27 @@ config PCIE_CADENCE_PLAT_EP
 	  endpoint mode. This PCIe controller may be embedded into many
 	  different vendors SoCs.
 
+config PCI_J721E
+	bool
+
+config PCI_J721E_HOST
+	bool "TI J721E PCIe platform host controller"
+	depends on OF
+	select PCIE_CADENCE_HOST
+	select PCI_J721E
+	help
+	  Say Y here if you want to support the TI J721E PCIe platform
+	  controller in host mode. TI J721E PCIe controller uses Cadence PCIe
+	  core.
+
+config PCI_J721E_EP
+	bool "TI J721E PCIe platform endpoint controller"
+	depends on OF
+	depends on PCI_ENDPOINT
+	select PCIE_CADENCE_EP
+	select PCI_J721E
+	help
+	  Say Y here if you want to support the TI J721E PCIe platform
+	  controller in endpoint mode. TI J721E PCIe controller uses Cadence PCIe
+	  core.
 endmenu
diff --git a/drivers/pci/controller/cadence/Makefile b/drivers/pci/controller/cadence/Makefile
index 232a3f20876a..9bac5fb2f13d 100644
--- a/drivers/pci/controller/cadence/Makefile
+++ b/drivers/pci/controller/cadence/Makefile
@@ -3,3 +3,4 @@ obj-$(CONFIG_PCIE_CADENCE) += pcie-cadence.o
 obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o
 obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep.o
 obj-$(CONFIG_PCIE_CADENCE_PLAT) += pcie-cadence-plat.o
+obj-$(CONFIG_PCI_J721E) += pci-j721e.o
diff --git a/drivers/pci/controller/cadence/pci-j721e.c b/drivers/pci/controller/cadence/pci-j721e.c
new file mode 100644
index 000000000000..eee619c6ffae
--- /dev/null
+++ b/drivers/pci/controller/cadence/pci-j721e.c
@@ -0,0 +1,500 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * pci-j721e - PCIe controller driver for TI's J721E SoCs
+ *
+ * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/io.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/pci.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include "../../pci.h"
+#include "pcie-cadence.h"
+
+#define ENABLE_REG_SYS_2	0x108
+#define STATUS_REG_SYS_2	0x508
+#define STATUS_CLR_REG_SYS_2	0x708
+#define LINK_DOWN		BIT(1)
+
+#define J721E_PCIE_USER_CMD_STATUS	0x4
+#define LINK_TRAINING_ENABLE		BIT(0)
+
+#define J721E_PCIE_USER_LINKSTATUS	0x14
+#define LINK_STATUS			GENMASK(1, 0)
+
+enum link_status {
+	NO_RECEIVERS_DETECTED,
+	LINK_TRAINING_IN_PROGRESS,
+	LINK_UP_DL_IN_PROGRESS,
+	LINK_UP_DL_COMPLETED,
+};
+
+#define J721E_MODE_RC			BIT(7)
+#define LANE_COUNT_MASK			BIT(8)
+#define LANE_COUNT(n)			((n) << 8)
+
+#define GENERATION_SEL_MASK		GENMASK(1, 0)
+
+#define MAX_LANES			2
+
+struct j721e_pcie {
+	struct device		*dev;
+	struct device_node	*node;
+	u32			mode;
+	u32			num_lanes;
+	struct cdns_pcie	*cdns_pcie;
+	void __iomem		*user_cfg_base;
+	void __iomem		*intd_cfg_base;
+};
+
+enum j721e_pcie_mode {
+	PCI_MODE_RC,
+	PCI_MODE_EP,
+};
+
+struct j721e_pcie_data {
+	enum j721e_pcie_mode	mode;
+};
+
+static inline u32 j721e_pcie_user_readl(struct j721e_pcie *pcie, u32 offset)
+{
+	return readl(pcie->user_cfg_base + offset);
+}
+
+static inline void j721e_pcie_user_writel(struct j721e_pcie *pcie, u32 offset,
+					  u32 value)
+{
+	writel(value, pcie->user_cfg_base + offset);
+}
+
+static inline u32 j721e_pcie_intd_readl(struct j721e_pcie *pcie, u32 offset)
+{
+	return readl(pcie->intd_cfg_base + offset);
+}
+
+static inline void j721e_pcie_intd_writel(struct j721e_pcie *pcie, u32 offset,
+					  u32 value)
+{
+	writel(value, pcie->intd_cfg_base + offset);
+}
+
+static irqreturn_t j721e_pcie_link_irq_handler(int irq, void *priv)
+{
+	struct j721e_pcie *pcie = priv;
+	struct device *dev = pcie->dev;
+	u32 reg;
+
+	reg = j721e_pcie_intd_readl(pcie, STATUS_REG_SYS_2);
+	if (!(reg & LINK_DOWN))
+		return IRQ_NONE;
+
+	dev_err(dev, "LINK DOWN!\n");
+
+	j721e_pcie_intd_writel(pcie, STATUS_CLR_REG_SYS_2, LINK_DOWN);
+	return IRQ_HANDLED;
+}
+
+static void j721e_pcie_config_link_irq(struct j721e_pcie *pcie)
+{
+	u32 reg;
+
+	reg = j721e_pcie_intd_readl(pcie, ENABLE_REG_SYS_2);
+	reg |= LINK_DOWN;
+	j721e_pcie_intd_writel(pcie, ENABLE_REG_SYS_2, reg);
+}
+
+static int j721e_pcie_start_link(struct cdns_pcie *cdns_pcie)
+{
+	struct j721e_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
+	u32 reg;
+
+	reg = j721e_pcie_user_readl(pcie, J721E_PCIE_USER_CMD_STATUS);
+	reg |= LINK_TRAINING_ENABLE;
+	j721e_pcie_user_writel(pcie, J721E_PCIE_USER_CMD_STATUS, reg);
+
+	return 0;
+}
+
+static void j721e_pcie_stop_link(struct cdns_pcie *cdns_pcie)
+{
+	struct j721e_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
+	u32 reg;
+
+	reg = j721e_pcie_user_readl(pcie, J721E_PCIE_USER_CMD_STATUS);
+	reg &= ~LINK_TRAINING_ENABLE;
+	j721e_pcie_user_writel(pcie, J721E_PCIE_USER_CMD_STATUS, reg);
+}
+
+static bool j721e_pcie_link_up(struct cdns_pcie *cdns_pcie)
+{
+	struct j721e_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
+	u32 reg;
+
+	reg = j721e_pcie_user_readl(pcie, J721E_PCIE_USER_LINKSTATUS);
+	reg &= LINK_STATUS;
+	if (reg == LINK_UP_DL_COMPLETED)
+		return true;
+
+	return false;
+}
+
+static const struct cdns_pcie_ops j721e_ops_ops = {
+	.read = cdns_platform_pcie_read32,
+	.write = cdns_platform_pcie_write32,
+	.start_link = j721e_pcie_start_link,
+	.stop_link = j721e_pcie_stop_link,
+	.link_up = j721e_pcie_link_up,
+};
+
+static int j721e_pcie_set_mode(struct j721e_pcie *pcie, struct regmap *syscon)
+{
+	struct device *dev = pcie->dev;
+	u32 mask = J721E_MODE_RC;
+	u32 mode = pcie->mode;
+	u32 val = 0;
+	int ret = 0;
+
+	if (mode == PCI_MODE_RC)
+		val = J721E_MODE_RC;
+
+	ret = regmap_update_bits(syscon, 0, mask, val);
+	if (ret)
+		dev_err(dev, "failed to set pcie mode\n");
+
+	return ret;
+}
+
+static int j721e_pcie_set_link_speed(struct j721e_pcie *pcie,
+				     struct regmap *syscon)
+{
+	struct device *dev = pcie->dev;
+	struct device_node *np = dev->of_node;
+	int link_speed;
+	u32 val = 0;
+	int ret;
+
+	link_speed = of_pci_get_max_link_speed(np);
+	if (link_speed < 2)
+		link_speed = 2;
+
+	val = link_speed - 1;
+	ret = regmap_update_bits(syscon, 0, GENERATION_SEL_MASK, val);
+	if (ret)
+		dev_err(dev, "failed to set link speed\n");
+
+	return ret;
+}
+
+static int j721e_pcie_set_lane_count(struct j721e_pcie *pcie,
+				     struct regmap *syscon)
+{
+	struct device *dev = pcie->dev;
+	u32 lanes = pcie->num_lanes;
+	u32 val = 0;
+	int ret;
+
+	val = LANE_COUNT(lanes - 1);
+	ret = regmap_update_bits(syscon, 0, LANE_COUNT_MASK, val);
+	if (ret)
+		dev_err(dev, "failed to set link count\n");
+
+	return ret;
+}
+
+static int j721e_pcie_ctrl_init(struct j721e_pcie *pcie)
+{
+	struct device *dev = pcie->dev;
+	struct device_node *node = dev->of_node;
+	struct regmap *syscon;
+	int ret;
+
+	syscon = syscon_regmap_lookup_by_phandle(node, "ti,syscon-pcie-ctrl");
+	if (IS_ERR(syscon)) {
+		dev_err(dev, "Unable to get ti,syscon-pcie-ctrl regmap\n");
+		return PTR_ERR(syscon);
+	}
+
+	ret = j721e_pcie_set_mode(pcie, syscon);
+	if (ret < 0) {
+		dev_err(dev, "Failed to set pci mode\n");
+		return ret;
+	}
+
+	ret = j721e_pcie_set_link_speed(pcie, syscon);
+	if (ret < 0) {
+		dev_err(dev, "Failed to set link speed\n");
+		return ret;
+	}
+
+	ret = j721e_pcie_set_lane_count(pcie, syscon);
+	if (ret < 0) {
+		dev_err(dev, "Failed to set num-lanes\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int cdns_ti_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
+				    int where, int size, u32 *value)
+{
+	struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
+	struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge);
+	unsigned int busn = bus->number;
+
+	if (busn == rc->bus_range->start)
+		return pci_generic_config_read32(bus, devfn, where, size,
+						 value);
+
+	return pci_generic_config_read(bus, devfn, where, size, value);
+}
+
+static int cdns_ti_pcie_config_write(struct pci_bus *bus, unsigned int devfn,
+				     int where, int size, u32 value)
+{
+	struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
+	struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge);
+	unsigned int busn = bus->number;
+
+	if (busn == rc->bus_range->start)
+		return pci_generic_config_write32(bus, devfn, where, size,
+						  value);
+
+	return pci_generic_config_write(bus, devfn, where, size, value);
+}
+
+static struct pci_ops cdns_ti_pcie_host_ops = {
+	.map_bus	= cdns_pci_map_bus,
+	.read		= cdns_ti_pcie_config_read,
+	.write		= cdns_ti_pcie_config_write,
+};
+
+static const struct j721e_pcie_data j721e_pcie_rc_data = {
+	.mode = PCI_MODE_RC,
+};
+
+static const struct j721e_pcie_data j721e_pcie_ep_data = {
+	.mode = PCI_MODE_EP,
+};
+
+static const struct of_device_id of_j721e_pcie_match[] = {
+	{
+		.compatible = "ti,j721e-pcie-host",
+		.data = &j721e_pcie_rc_data,
+	},
+	{
+		.compatible = "ti,j721e-pcie-ep",
+		.data = &j721e_pcie_ep_data,
+	},
+	{},
+};
+
+static int j721e_pcie_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *node = dev->of_node;
+	const struct of_device_id *match;
+	struct pci_host_bridge *bridge;
+	struct j721e_pcie_data *data;
+	struct cdns_pcie *cdns_pcie;
+	struct j721e_pcie *pcie;
+	struct cdns_pcie_rc *rc;
+	struct cdns_pcie_ep *ep;
+	struct gpio_desc *gpiod;
+	struct resource *res;
+	void __iomem *base;
+	u32 num_lanes;
+	u32 mode;
+	int ret;
+	int irq;
+
+	match = of_match_device(of_match_ptr(of_j721e_pcie_match), dev);
+	if (!match)
+		return -EINVAL;
+
+	data = (struct j721e_pcie_data *)match->data;
+	mode = (u32)data->mode;
+
+	pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
+	if (!pcie)
+		return -ENOMEM;
+
+	pcie->dev = dev;
+	pcie->node = node;
+	pcie->mode = mode;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intd_cfg");
+	base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+	pcie->intd_cfg_base = base;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "user_cfg");
+	base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+	pcie->user_cfg_base = base;
+
+	ret = of_property_read_u32(node, "num-lanes", &num_lanes);
+	if (ret || num_lanes > MAX_LANES)
+		num_lanes = 1;
+	pcie->num_lanes = num_lanes;
+
+	irq = platform_get_irq_byname(pdev, "link_state");
+	if (irq < 0)
+		return irq;
+
+	dev_set_drvdata(dev, pcie);
+	pm_runtime_enable(dev);
+	ret = pm_runtime_get_sync(dev);
+	if (ret < 0) {
+		dev_err(dev, "pm_runtime_get_sync failed\n");
+		goto err_get_sync;
+	}
+
+	ret = j721e_pcie_ctrl_init(pcie);
+	if (ret < 0) {
+		dev_err(dev, "pm_runtime_get_sync failed\n");
+		goto err_get_sync;
+	}
+
+	ret = devm_request_irq(dev, irq, j721e_pcie_link_irq_handler,
+			       IRQF_SHARED, "j721e-pcie-link_state-irq", pcie);
+	if (ret < 0) {
+		dev_err(dev, "failed to request link state IRQ %d\n", irq);
+		goto err_get_sync;
+	}
+
+	j721e_pcie_config_link_irq(pcie);
+
+	switch (mode) {
+	case PCI_MODE_RC:
+		if (!IS_ENABLED(CONFIG_PCIE_CADENCE_HOST)) {
+			ret = -ENODEV;
+			goto err_get_sync;
+		}
+
+		bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
+		if (!bridge) {
+			ret = -ENOMEM;
+			goto err_get_sync;
+		}
+
+		bridge->ops = &cdns_ti_pcie_host_ops;
+		rc = pci_host_bridge_priv(bridge);
+
+		cdns_pcie = &rc->pcie;
+		cdns_pcie->dev = dev;
+		cdns_pcie->ops = &j721e_ops_ops;
+		pcie->cdns_pcie = cdns_pcie;
+
+		gpiod = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+		if (IS_ERR(gpiod)) {
+			ret = PTR_ERR(gpiod);
+			if (ret != -EPROBE_DEFER)
+				dev_err(dev, "Failed to get reset GPIO\n");
+			goto err_get_sync;
+		}
+
+		ret = cdns_pcie_init_phy(dev, cdns_pcie);
+		if (ret) {
+			dev_err(dev, "Failed to init phy\n");
+			goto err_get_sync;
+		}
+
+		/*
+		 * "Power Sequencing and Reset Signal Timings" table in
+		 * PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 3.0
+		 * indicates PERST# should be deasserted after minimum of 100us
+		 * once REFCLK is stable. The REFCLK to the connector in RC
+		 * mode is selected while enabling the PHY. So deassert PERST#
+		 * after 100 us.
+		 */
+		if (gpiod) {
+			usleep_range(100, 200);
+			gpiod_set_value_cansleep(gpiod, 1);
+		}
+
+		ret = cdns_pcie_host_setup(rc);
+		if (ret < 0)
+			goto err_pcie_setup;
+
+		break;
+	case PCI_MODE_EP:
+		if (!IS_ENABLED(CONFIG_PCIE_CADENCE_EP)) {
+			ret = -ENODEV;
+			goto err_get_sync;
+		}
+
+		ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
+		if (!ep) {
+			ret = -ENOMEM;
+			goto err_get_sync;
+		}
+
+		cdns_pcie = &ep->pcie;
+		cdns_pcie->dev = dev;
+		cdns_pcie->ops = &j721e_ops_ops;
+		pcie->cdns_pcie = cdns_pcie;
+
+		ret = cdns_pcie_init_phy(dev, cdns_pcie);
+		if (ret) {
+			dev_err(dev, "Failed to init phy\n");
+			goto err_get_sync;
+		}
+
+		ret = cdns_pcie_ep_setup(ep);
+		if (ret < 0)
+			goto err_pcie_setup;
+
+		break;
+	default:
+		dev_err(dev, "INVALID device type %d\n", mode);
+	}
+
+	return 0;
+
+err_pcie_setup:
+	cdns_pcie_disable_phy(cdns_pcie);
+
+err_get_sync:
+	pm_runtime_put(dev);
+	pm_runtime_disable(dev);
+
+	return ret;
+}
+
+static int j721e_pcie_remove(struct platform_device *pdev)
+{
+	struct j721e_pcie *pcie = platform_get_drvdata(pdev);
+	struct cdns_pcie *cdns_pcie = pcie->cdns_pcie;
+	struct device *dev = &pdev->dev;
+
+	cdns_pcie_disable_phy(cdns_pcie);
+	pm_runtime_put(dev);
+	pm_runtime_disable(dev);
+	of_platform_depopulate(dev);
+
+	return 0;
+}
+
+static struct platform_driver j721e_pcie_driver = {
+	.probe  = j721e_pcie_probe,
+	.remove = j721e_pcie_remove,
+	.driver = {
+		.name	= "j721e-pcie",
+		.of_match_table = of_j721e_pcie_match,
+		.suppress_bind_attrs = true,
+	},
+};
+builtin_platform_driver(j721e_pcie_driver);
diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c
index c7dc7be0da40..d7cc7ea4fba3 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -11,8 +11,8 @@
 
 #include "pcie-cadence.h"
 
-static void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
-				      int where)
+void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
+			       int where)
 {
 	struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
 	struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge);
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
index ea850290a602..f349f5828a58 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -488,11 +488,19 @@ static inline bool cdns_pcie_link_up(struct cdns_pcie *pcie)
 
 #ifdef CONFIG_PCIE_CADENCE_HOST
 int cdns_pcie_host_setup(struct cdns_pcie_rc *rc);
+void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
+			       int where);
 #else
 static inline int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
 {
 	return 0;
 }
+
+static void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
+				      int where)
+{
+	return NULL;
+}
 #endif
 
 #ifdef CONFIG_PCIE_CADENCE_EP
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v3 13/14] misc: pci_endpoint_test: Add J721E in pci_device_id table
  2020-04-17 12:57 ` Kishon Vijay Abraham I
@ 2020-04-17 12:57   ` Kishon Vijay Abraham I
  -1 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: Arnd Bergmann, Greg Kroah-Hartman, linux-arm-kernel, linux-pci,
	devicetree, linux-kernel

Add J721E in pci_device_id table so that pci-epf-test can be used
for testing PCIe EP in J721E.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/misc/pci_endpoint_test.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index ef5a1af6bab7..a70b17e5dd9a 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -68,6 +68,7 @@
 #define PCI_ENDPOINT_TEST_FLAGS			0x2c
 #define FLAG_USE_DMA				BIT(0)
 
+#define PCI_DEVICE_ID_TI_J721E			0xb00d
 #define PCI_DEVICE_ID_TI_AM654			0xb00c
 
 #define is_am654_pci_dev(pdev)		\
@@ -930,6 +931,11 @@ static const struct pci_endpoint_test_data am654_data = {
 	.irq_type = IRQ_TYPE_MSI,
 };
 
+static const struct pci_endpoint_test_data j721e_data = {
+	.alignment = 256,
+	.irq_type = IRQ_TYPE_MSI,
+};
+
 static const struct pci_device_id pci_endpoint_test_tbl[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x),
 	  .driver_data = (kernel_ulong_t)&default_data,
@@ -942,6 +948,9 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM654),
 	  .driver_data = (kernel_ulong_t)&am654_data
 	},
+	{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721E),
+	  .driver_data = (kernel_ulong_t)&j721e_data,
+	},
 	{ }
 };
 MODULE_DEVICE_TABLE(pci, pci_endpoint_test_tbl);
-- 
2.17.1


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

* [PATCH v3 13/14] misc: pci_endpoint_test: Add J721E in pci_device_id table
@ 2020-04-17 12:57   ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: devicetree, Arnd Bergmann, Greg Kroah-Hartman, linux-kernel,
	linux-pci, linux-arm-kernel

Add J721E in pci_device_id table so that pci-epf-test can be used
for testing PCIe EP in J721E.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/misc/pci_endpoint_test.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index ef5a1af6bab7..a70b17e5dd9a 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -68,6 +68,7 @@
 #define PCI_ENDPOINT_TEST_FLAGS			0x2c
 #define FLAG_USE_DMA				BIT(0)
 
+#define PCI_DEVICE_ID_TI_J721E			0xb00d
 #define PCI_DEVICE_ID_TI_AM654			0xb00c
 
 #define is_am654_pci_dev(pdev)		\
@@ -930,6 +931,11 @@ static const struct pci_endpoint_test_data am654_data = {
 	.irq_type = IRQ_TYPE_MSI,
 };
 
+static const struct pci_endpoint_test_data j721e_data = {
+	.alignment = 256,
+	.irq_type = IRQ_TYPE_MSI,
+};
+
 static const struct pci_device_id pci_endpoint_test_tbl[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x),
 	  .driver_data = (kernel_ulong_t)&default_data,
@@ -942,6 +948,9 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM654),
 	  .driver_data = (kernel_ulong_t)&am654_data
 	},
+	{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721E),
+	  .driver_data = (kernel_ulong_t)&j721e_data,
+	},
 	{ }
 };
 MODULE_DEVICE_TABLE(pci, pci_endpoint_test_tbl);
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v3 14/14] MAINTAINERS: Add Kishon Vijay Abraham I for TI J721E SoC PCIe
  2020-04-17 12:57 ` Kishon Vijay Abraham I
@ 2020-04-17 12:57   ` Kishon Vijay Abraham I
  -1 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: Arnd Bergmann, Greg Kroah-Hartman, linux-arm-kernel, linux-pci,
	devicetree, linux-kernel

Add Kishon Vijay Abraham I as MAINTAINER for TI J721E SoC PCIe.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 MAINTAINERS | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 6851ef7cf1bd..ffcd023d1cba 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12968,13 +12968,15 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/pci/designware-pcie.txt
 F:	drivers/pci/controller/dwc/*designware*
 
-PCI DRIVER FOR TI DRA7XX
+PCI DRIVER FOR TI DRA7XX/J721E
 M:	Kishon Vijay Abraham I <kishon@ti.com>
 L:	linux-omap@vger.kernel.org
 L:	linux-pci@vger.kernel.org
+L:	linux-arm-kernel@lists.infradead.org
 S:	Supported
 F:	Documentation/devicetree/bindings/pci/ti-pci.txt
 F:	drivers/pci/controller/dwc/pci-dra7xx.c
+F:	drivers/pci/controller/cadence/pci-j721e.c
 
 PCI DRIVER FOR TI KEYSTONE
 M:	Murali Karicheri <m-karicheri2@ti.com>
-- 
2.17.1


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

* [PATCH v3 14/14] MAINTAINERS: Add Kishon Vijay Abraham I for TI J721E SoC PCIe
@ 2020-04-17 12:57   ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-04-17 12:57 UTC (permalink / raw)
  To: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi, Andrew Murray
  Cc: devicetree, Arnd Bergmann, Greg Kroah-Hartman, linux-kernel,
	linux-pci, linux-arm-kernel

Add Kishon Vijay Abraham I as MAINTAINER for TI J721E SoC PCIe.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 MAINTAINERS | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 6851ef7cf1bd..ffcd023d1cba 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12968,13 +12968,15 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/pci/designware-pcie.txt
 F:	drivers/pci/controller/dwc/*designware*
 
-PCI DRIVER FOR TI DRA7XX
+PCI DRIVER FOR TI DRA7XX/J721E
 M:	Kishon Vijay Abraham I <kishon@ti.com>
 L:	linux-omap@vger.kernel.org
 L:	linux-pci@vger.kernel.org
+L:	linux-arm-kernel@lists.infradead.org
 S:	Supported
 F:	Documentation/devicetree/bindings/pci/ti-pci.txt
 F:	drivers/pci/controller/dwc/pci-dra7xx.c
+F:	drivers/pci/controller/cadence/pci-j721e.c
 
 PCI DRIVER FOR TI KEYSTONE
 M:	Murali Karicheri <m-karicheri2@ti.com>
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v3 14/14] MAINTAINERS: Add Kishon Vijay Abraham I for TI J721E SoC PCIe
  2020-04-17 12:57   ` Kishon Vijay Abraham I
@ 2020-04-17 15:19     ` Joe Perches
  -1 siblings, 0 replies; 46+ messages in thread
From: Joe Perches @ 2020-04-17 15:19 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Tom Joseph, Bjorn Helgaas, Rob Herring,
	Lorenzo Pieralisi, Andrew Murray
  Cc: Arnd Bergmann, Greg Kroah-Hartman, linux-arm-kernel, linux-pci,
	devicetree, linux-kernel

On Fri, 2020-04-17 at 18:27 +0530, Kishon Vijay Abraham I wrote:
> Add Kishon Vijay Abraham I as MAINTAINER for TI J721E SoC PCIe.
[]
> diff --git a/MAINTAINERS b/MAINTAINERS
[]
> @@ -12968,13 +12968,15 @@ S:	Maintained
>  F:	Documentation/devicetree/bindings/pci/designware-pcie.txt
>  F:	drivers/pci/controller/dwc/*designware*
>  
> -PCI DRIVER FOR TI DRA7XX
> +PCI DRIVER FOR TI DRA7XX/J721E
>  M:	Kishon Vijay Abraham I <kishon@ti.com>
>  L:	linux-omap@vger.kernel.org
>  L:	linux-pci@vger.kernel.org
> +L:	linux-arm-kernel@lists.infradead.org
>  S:	Supported
>  F:	Documentation/devicetree/bindings/pci/ti-pci.txt
>  F:	drivers/pci/controller/dwc/pci-dra7xx.c
> +F:	drivers/pci/controller/cadence/pci-j721e.c

Please keep file patterns in alphabetic order by
moving this new cadence line up one line above dwc.




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

* Re: [PATCH v3 14/14] MAINTAINERS: Add Kishon Vijay Abraham I for TI J721E SoC PCIe
@ 2020-04-17 15:19     ` Joe Perches
  0 siblings, 0 replies; 46+ messages in thread
From: Joe Perches @ 2020-04-17 15:19 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Tom Joseph, Bjorn Helgaas, Rob Herring,
	Lorenzo Pieralisi, Andrew Murray
  Cc: devicetree, Arnd Bergmann, Greg Kroah-Hartman, linux-kernel,
	linux-pci, linux-arm-kernel

On Fri, 2020-04-17 at 18:27 +0530, Kishon Vijay Abraham I wrote:
> Add Kishon Vijay Abraham I as MAINTAINER for TI J721E SoC PCIe.
[]
> diff --git a/MAINTAINERS b/MAINTAINERS
[]
> @@ -12968,13 +12968,15 @@ S:	Maintained
>  F:	Documentation/devicetree/bindings/pci/designware-pcie.txt
>  F:	drivers/pci/controller/dwc/*designware*
>  
> -PCI DRIVER FOR TI DRA7XX
> +PCI DRIVER FOR TI DRA7XX/J721E
>  M:	Kishon Vijay Abraham I <kishon@ti.com>
>  L:	linux-omap@vger.kernel.org
>  L:	linux-pci@vger.kernel.org
> +L:	linux-arm-kernel@lists.infradead.org
>  S:	Supported
>  F:	Documentation/devicetree/bindings/pci/ti-pci.txt
>  F:	drivers/pci/controller/dwc/pci-dra7xx.c
> +F:	drivers/pci/controller/cadence/pci-j721e.c

Please keep file patterns in alphabetic order by
moving this new cadence line up one line above dwc.




_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v3 09/14] PCI: cadence: Add MSI-X support to Endpoint driver
  2020-04-17 12:57   ` Kishon Vijay Abraham I
@ 2020-04-30  1:55     ` Rob Herring
  -1 siblings, 0 replies; 46+ messages in thread
From: Rob Herring @ 2020-04-30  1:55 UTC (permalink / raw)
  To: Kishon Vijay Abraham I
  Cc: Tom Joseph, Bjorn Helgaas, Lorenzo Pieralisi, Andrew Murray,
	Arnd Bergmann, Greg Kroah-Hartman, linux-arm-kernel, linux-pci,
	devicetree, linux-kernel

On Fri, Apr 17, 2020 at 06:27:48PM +0530, Kishon Vijay Abraham I wrote:
> From: Alan Douglas <adouglas@cadence.com>
> 
> Implement ->set_msix() and ->get_msix() callback functions in order
> to configure MSIX capability in the PCIe endpoint controller.
> 
> Add cdns_pcie_ep_send_msix_irq() to send MSIX interrupts to Host.
> cdns_pcie_ep_send_msix_irq() gets the MSIX table address (virtual
> address) from "struct cdns_pcie_epf" that gets initialized in
> ->set_bar() call back function.
> 
> [kishon@ti.com: Re-implement MSIX support in accordance with the
>  re-designed core MSI-X interfaces]
> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
> Signed-off-by: Alan Douglas <adouglas@cadence.com>

Your Sob should be last.

> ---
>  .../pci/controller/cadence/pcie-cadence-ep.c  | 112 +++++++++++++++++-
>  drivers/pci/controller/cadence/pcie-cadence.h |  10 ++
>  2 files changed, 121 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c
> index 14021d760482..c43340ca0630 100644
> --- a/drivers/pci/controller/cadence/pcie-cadence-ep.c
> +++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c
> @@ -51,6 +51,7 @@ static int cdns_pcie_ep_set_bar(struct pci_epc *epc, u8 fn,
>  				struct pci_epf_bar *epf_bar)
>  {
>  	struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
> +	struct cdns_pcie_epf *epf = &ep->epf[fn];
>  	struct cdns_pcie *pcie = &ep->pcie;
>  	dma_addr_t bar_phys = epf_bar->phys_addr;
>  	enum pci_barno bar = epf_bar->barno;
> @@ -111,6 +112,8 @@ static int cdns_pcie_ep_set_bar(struct pci_epc *epc, u8 fn,
>  		CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl));
>  	cdns_pcie_writel(pcie, reg, cfg);
>  
> +	epf->epf_bar[bar] = epf_bar;
> +
>  	return 0;
>  }
>  
> @@ -118,6 +121,7 @@ static void cdns_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn,
>  				   struct pci_epf_bar *epf_bar)
>  {
>  	struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
> +	struct cdns_pcie_epf *epf = &ep->epf[fn];
>  	struct cdns_pcie *pcie = &ep->pcie;
>  	enum pci_barno bar = epf_bar->barno;
>  	u32 reg, cfg, b, ctrl;
> @@ -139,6 +143,8 @@ static void cdns_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn,
>  
>  	cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar), 0);
>  	cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar), 0);
> +
> +	epf->epf_bar[bar] = NULL;
>  }
>  
>  static int cdns_pcie_ep_map_addr(struct pci_epc *epc, u8 fn, phys_addr_t addr,
> @@ -224,6 +230,50 @@ static int cdns_pcie_ep_get_msi(struct pci_epc *epc, u8 fn)
>  	return mme;
>  }
>  
> +static int cdns_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no)
> +{
> +	struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
> +	struct cdns_pcie *pcie = &ep->pcie;
> +	u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
> +	u32 val, reg;
> +
> +	reg = cap + PCI_MSIX_FLAGS;
> +	val = cdns_pcie_ep_fn_readw(pcie, func_no, reg);
> +	if (!(val & PCI_MSIX_FLAGS_ENABLE))
> +		return -EINVAL;
> +
> +	val &= PCI_MSIX_FLAGS_QSIZE;
> +
> +	return val;
> +}
> +
> +static int cdns_pcie_ep_set_msix(struct pci_epc *epc, u8 fn, u16 interrupts,
> +				 enum pci_barno bir, u32 offset)
> +{
> +	struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
> +	struct cdns_pcie *pcie = &ep->pcie;
> +	u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
> +	u32 val, reg;
> +
> +	reg = cap + PCI_MSIX_FLAGS;
> +	val = cdns_pcie_ep_fn_readw(pcie, fn, reg);
> +	val &= ~PCI_MSIX_FLAGS_QSIZE;
> +	val |= interrupts;
> +	cdns_pcie_ep_fn_writew(pcie, fn, reg, val);
> +
> +	/* Set MSIX BAR and offset */
> +	reg = cap + PCI_MSIX_TABLE;
> +	val = offset | bir;
> +	cdns_pcie_ep_fn_writel(pcie, fn, reg, val);
> +
> +	/* Set PBA BAR and offset.  BAR must match MSIX BAR */
> +	reg = cap + PCI_MSIX_PBA;
> +	val = (offset + (interrupts * PCI_MSIX_ENTRY_SIZE)) | bir;
> +	cdns_pcie_ep_fn_writel(pcie, fn, reg, val);
> +
> +	return 0;
> +}
> +
>  static void cdns_pcie_ep_assert_intx(struct cdns_pcie_ep *ep, u8 fn,
>  				     u8 intx, bool is_asserted)
>  {
> @@ -330,6 +380,56 @@ static int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn,
>  	return 0;
>  }
>  
> +static int cdns_pcie_ep_send_msix_irq(struct cdns_pcie_ep *ep, u8 fn,
> +				      u16 interrupt_num)
> +{
> +	u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
> +	u32 tbl_offset, msg_data, reg, vec_ctrl;
> +	struct cdns_pcie *pcie = &ep->pcie;
> +	struct pci_epf_msix_tbl *msix_tbl;
> +	struct pci_epf_bar *epf_bar;
> +	struct cdns_pcie_epf *epf;
> +	u64 pci_addr_mask = 0xff;
> +	u64 msg_addr;
> +	u16 flags;
> +	u8 bir;
> +
> +	/* Check whether the MSI-X feature has been enabled by the PCI host. */
> +	flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSIX_FLAGS);
> +	if (!(flags & PCI_MSIX_FLAGS_ENABLE))
> +		return -EINVAL;
> +
> +	reg = cap + PCI_MSIX_TABLE;
> +	tbl_offset = cdns_pcie_ep_fn_readl(pcie, fn, reg);
> +	bir = tbl_offset & PCI_MSIX_TABLE_BIR;
> +	tbl_offset &= PCI_MSIX_TABLE_OFFSET;
> +
> +	epf = &ep->epf[fn];
> +	epf_bar = epf->epf_bar[bir];
> +	msix_tbl = epf_bar->addr;
> +	msix_tbl = (struct pci_epf_msix_tbl *)((char *)msix_tbl + tbl_offset);
> +
> +	msg_addr = msix_tbl[(interrupt_num - 1)].msg_addr;
> +	msg_data = msix_tbl[(interrupt_num - 1)].msg_data;
> +	vec_ctrl = msix_tbl[(interrupt_num - 1)].vector_ctrl;
> +
> +	/* Set the outbound region if needed. */
> +	if (ep->irq_pci_addr != (msg_addr & ~pci_addr_mask) ||
> +	    ep->irq_pci_fn != fn) {
> +		/* First region was reserved for IRQ writes. */
> +		cdns_pcie_set_outbound_region(pcie, fn, 0,
> +					      false,
> +					      ep->irq_phys_addr,
> +					      msg_addr & ~pci_addr_mask,
> +					      pci_addr_mask + 1);
> +		ep->irq_pci_addr = (msg_addr & ~pci_addr_mask);
> +		ep->irq_pci_fn = fn;
> +	}
> +	writel(msg_data, ep->irq_cpu_addr + (msg_addr & pci_addr_mask));
> +
> +	return 0;
> +}
> +
>  static int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn,
>  				  enum pci_epc_irq_type type,
>  				  u16 interrupt_num)
> @@ -343,6 +443,9 @@ static int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn,
>  	case PCI_EPC_IRQ_MSI:
>  		return cdns_pcie_ep_send_msi_irq(ep, fn, interrupt_num);
>  
> +	case PCI_EPC_IRQ_MSIX:
> +		return cdns_pcie_ep_send_msix_irq(ep, fn, interrupt_num);
> +
>  	default:
>  		break;
>  	}
> @@ -380,7 +483,7 @@ static int cdns_pcie_ep_start(struct pci_epc *epc)
>  static const struct pci_epc_features cdns_pcie_epc_features = {
>  	.linkup_notifier = false,
>  	.msi_capable = true,
> -	.msix_capable = false,
> +	.msix_capable = true,
>  };
>  
>  static const struct pci_epc_features*
> @@ -397,6 +500,8 @@ static const struct pci_epc_ops cdns_pcie_epc_ops = {
>  	.unmap_addr	= cdns_pcie_ep_unmap_addr,
>  	.set_msi	= cdns_pcie_ep_set_msi,
>  	.get_msi	= cdns_pcie_ep_get_msi,
> +	.set_msix	= cdns_pcie_ep_set_msix,
> +	.get_msix	= cdns_pcie_ep_get_msix,
>  	.raise_irq	= cdns_pcie_ep_raise_irq,
>  	.start		= cdns_pcie_ep_start,
>  	.get_features	= cdns_pcie_ep_get_features,
> @@ -455,6 +560,11 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
>  	if (of_property_read_u8(np, "max-functions", &epc->max_functions) < 0)
>  		epc->max_functions = 1;
>  
> +	ep->epf = devm_kcalloc(dev, epc->max_functions, sizeof(*ep->epf),
> +			       GFP_KERNEL);
> +	if (!ep->epf)
> +		return -ENOMEM;
> +
>  	ret = pci_epc_mem_init(epc, pcie->mem_res->start,
>  			       resource_size(pcie->mem_res));
>  	if (ret < 0) {
> diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
> index 16a6b0ee547c..ea850290a602 100644
> --- a/drivers/pci/controller/cadence/pcie-cadence.h
> +++ b/drivers/pci/controller/cadence/pcie-cadence.h
> @@ -99,6 +99,7 @@
>  #define CDNS_PCIE_EP_FUNC_BASE(fn)	(((fn) << 12) & GENMASK(19, 12))
>  
>  #define CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET	0x90
> +#define CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET	0xb0
>  
>  /*
>   * Root Port Registers (PCI configuration space for the root port function)
> @@ -280,6 +281,14 @@ struct cdns_pcie_rc {
>  	u32			device_id;
>  };
>  
> +/**
> + * struct cdns_pcie_epf - Structure to hold info about endpoint function
> + * @epf_bar: reference to the pci_epf_bar for the six Base Address Registers
> + */
> +struct cdns_pcie_epf {
> +	struct pci_epf_bar *epf_bar[PCI_STD_NUM_BARS];
> +};
> +
>  /**
>   * struct cdns_pcie_ep - private data for this PCIe endpoint controller driver
>   * @pcie: Cadence PCIe controller
> @@ -307,6 +316,7 @@ struct cdns_pcie_ep {
>  	u64			irq_pci_addr;
>  	u8			irq_pci_fn;
>  	u8			irq_pending;
> +	struct cdns_pcie_epf	*epf;
>  };
>  
>  
> -- 
> 2.17.1
> 

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

* Re: [PATCH v3 09/14] PCI: cadence: Add MSI-X support to Endpoint driver
@ 2020-04-30  1:55     ` Rob Herring
  0 siblings, 0 replies; 46+ messages in thread
From: Rob Herring @ 2020-04-30  1:55 UTC (permalink / raw)
  To: Kishon Vijay Abraham I
  Cc: devicetree, Lorenzo Pieralisi, Arnd Bergmann, Greg Kroah-Hartman,
	linux-kernel, Tom Joseph, linux-pci, Bjorn Helgaas,
	linux-arm-kernel, Andrew Murray

On Fri, Apr 17, 2020 at 06:27:48PM +0530, Kishon Vijay Abraham I wrote:
> From: Alan Douglas <adouglas@cadence.com>
> 
> Implement ->set_msix() and ->get_msix() callback functions in order
> to configure MSIX capability in the PCIe endpoint controller.
> 
> Add cdns_pcie_ep_send_msix_irq() to send MSIX interrupts to Host.
> cdns_pcie_ep_send_msix_irq() gets the MSIX table address (virtual
> address) from "struct cdns_pcie_epf" that gets initialized in
> ->set_bar() call back function.
> 
> [kishon@ti.com: Re-implement MSIX support in accordance with the
>  re-designed core MSI-X interfaces]
> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
> Signed-off-by: Alan Douglas <adouglas@cadence.com>

Your Sob should be last.

> ---
>  .../pci/controller/cadence/pcie-cadence-ep.c  | 112 +++++++++++++++++-
>  drivers/pci/controller/cadence/pcie-cadence.h |  10 ++
>  2 files changed, 121 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c
> index 14021d760482..c43340ca0630 100644
> --- a/drivers/pci/controller/cadence/pcie-cadence-ep.c
> +++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c
> @@ -51,6 +51,7 @@ static int cdns_pcie_ep_set_bar(struct pci_epc *epc, u8 fn,
>  				struct pci_epf_bar *epf_bar)
>  {
>  	struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
> +	struct cdns_pcie_epf *epf = &ep->epf[fn];
>  	struct cdns_pcie *pcie = &ep->pcie;
>  	dma_addr_t bar_phys = epf_bar->phys_addr;
>  	enum pci_barno bar = epf_bar->barno;
> @@ -111,6 +112,8 @@ static int cdns_pcie_ep_set_bar(struct pci_epc *epc, u8 fn,
>  		CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl));
>  	cdns_pcie_writel(pcie, reg, cfg);
>  
> +	epf->epf_bar[bar] = epf_bar;
> +
>  	return 0;
>  }
>  
> @@ -118,6 +121,7 @@ static void cdns_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn,
>  				   struct pci_epf_bar *epf_bar)
>  {
>  	struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
> +	struct cdns_pcie_epf *epf = &ep->epf[fn];
>  	struct cdns_pcie *pcie = &ep->pcie;
>  	enum pci_barno bar = epf_bar->barno;
>  	u32 reg, cfg, b, ctrl;
> @@ -139,6 +143,8 @@ static void cdns_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn,
>  
>  	cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar), 0);
>  	cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar), 0);
> +
> +	epf->epf_bar[bar] = NULL;
>  }
>  
>  static int cdns_pcie_ep_map_addr(struct pci_epc *epc, u8 fn, phys_addr_t addr,
> @@ -224,6 +230,50 @@ static int cdns_pcie_ep_get_msi(struct pci_epc *epc, u8 fn)
>  	return mme;
>  }
>  
> +static int cdns_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no)
> +{
> +	struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
> +	struct cdns_pcie *pcie = &ep->pcie;
> +	u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
> +	u32 val, reg;
> +
> +	reg = cap + PCI_MSIX_FLAGS;
> +	val = cdns_pcie_ep_fn_readw(pcie, func_no, reg);
> +	if (!(val & PCI_MSIX_FLAGS_ENABLE))
> +		return -EINVAL;
> +
> +	val &= PCI_MSIX_FLAGS_QSIZE;
> +
> +	return val;
> +}
> +
> +static int cdns_pcie_ep_set_msix(struct pci_epc *epc, u8 fn, u16 interrupts,
> +				 enum pci_barno bir, u32 offset)
> +{
> +	struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
> +	struct cdns_pcie *pcie = &ep->pcie;
> +	u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
> +	u32 val, reg;
> +
> +	reg = cap + PCI_MSIX_FLAGS;
> +	val = cdns_pcie_ep_fn_readw(pcie, fn, reg);
> +	val &= ~PCI_MSIX_FLAGS_QSIZE;
> +	val |= interrupts;
> +	cdns_pcie_ep_fn_writew(pcie, fn, reg, val);
> +
> +	/* Set MSIX BAR and offset */
> +	reg = cap + PCI_MSIX_TABLE;
> +	val = offset | bir;
> +	cdns_pcie_ep_fn_writel(pcie, fn, reg, val);
> +
> +	/* Set PBA BAR and offset.  BAR must match MSIX BAR */
> +	reg = cap + PCI_MSIX_PBA;
> +	val = (offset + (interrupts * PCI_MSIX_ENTRY_SIZE)) | bir;
> +	cdns_pcie_ep_fn_writel(pcie, fn, reg, val);
> +
> +	return 0;
> +}
> +
>  static void cdns_pcie_ep_assert_intx(struct cdns_pcie_ep *ep, u8 fn,
>  				     u8 intx, bool is_asserted)
>  {
> @@ -330,6 +380,56 @@ static int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn,
>  	return 0;
>  }
>  
> +static int cdns_pcie_ep_send_msix_irq(struct cdns_pcie_ep *ep, u8 fn,
> +				      u16 interrupt_num)
> +{
> +	u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
> +	u32 tbl_offset, msg_data, reg, vec_ctrl;
> +	struct cdns_pcie *pcie = &ep->pcie;
> +	struct pci_epf_msix_tbl *msix_tbl;
> +	struct pci_epf_bar *epf_bar;
> +	struct cdns_pcie_epf *epf;
> +	u64 pci_addr_mask = 0xff;
> +	u64 msg_addr;
> +	u16 flags;
> +	u8 bir;
> +
> +	/* Check whether the MSI-X feature has been enabled by the PCI host. */
> +	flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSIX_FLAGS);
> +	if (!(flags & PCI_MSIX_FLAGS_ENABLE))
> +		return -EINVAL;
> +
> +	reg = cap + PCI_MSIX_TABLE;
> +	tbl_offset = cdns_pcie_ep_fn_readl(pcie, fn, reg);
> +	bir = tbl_offset & PCI_MSIX_TABLE_BIR;
> +	tbl_offset &= PCI_MSIX_TABLE_OFFSET;
> +
> +	epf = &ep->epf[fn];
> +	epf_bar = epf->epf_bar[bir];
> +	msix_tbl = epf_bar->addr;
> +	msix_tbl = (struct pci_epf_msix_tbl *)((char *)msix_tbl + tbl_offset);
> +
> +	msg_addr = msix_tbl[(interrupt_num - 1)].msg_addr;
> +	msg_data = msix_tbl[(interrupt_num - 1)].msg_data;
> +	vec_ctrl = msix_tbl[(interrupt_num - 1)].vector_ctrl;
> +
> +	/* Set the outbound region if needed. */
> +	if (ep->irq_pci_addr != (msg_addr & ~pci_addr_mask) ||
> +	    ep->irq_pci_fn != fn) {
> +		/* First region was reserved for IRQ writes. */
> +		cdns_pcie_set_outbound_region(pcie, fn, 0,
> +					      false,
> +					      ep->irq_phys_addr,
> +					      msg_addr & ~pci_addr_mask,
> +					      pci_addr_mask + 1);
> +		ep->irq_pci_addr = (msg_addr & ~pci_addr_mask);
> +		ep->irq_pci_fn = fn;
> +	}
> +	writel(msg_data, ep->irq_cpu_addr + (msg_addr & pci_addr_mask));
> +
> +	return 0;
> +}
> +
>  static int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn,
>  				  enum pci_epc_irq_type type,
>  				  u16 interrupt_num)
> @@ -343,6 +443,9 @@ static int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn,
>  	case PCI_EPC_IRQ_MSI:
>  		return cdns_pcie_ep_send_msi_irq(ep, fn, interrupt_num);
>  
> +	case PCI_EPC_IRQ_MSIX:
> +		return cdns_pcie_ep_send_msix_irq(ep, fn, interrupt_num);
> +
>  	default:
>  		break;
>  	}
> @@ -380,7 +483,7 @@ static int cdns_pcie_ep_start(struct pci_epc *epc)
>  static const struct pci_epc_features cdns_pcie_epc_features = {
>  	.linkup_notifier = false,
>  	.msi_capable = true,
> -	.msix_capable = false,
> +	.msix_capable = true,
>  };
>  
>  static const struct pci_epc_features*
> @@ -397,6 +500,8 @@ static const struct pci_epc_ops cdns_pcie_epc_ops = {
>  	.unmap_addr	= cdns_pcie_ep_unmap_addr,
>  	.set_msi	= cdns_pcie_ep_set_msi,
>  	.get_msi	= cdns_pcie_ep_get_msi,
> +	.set_msix	= cdns_pcie_ep_set_msix,
> +	.get_msix	= cdns_pcie_ep_get_msix,
>  	.raise_irq	= cdns_pcie_ep_raise_irq,
>  	.start		= cdns_pcie_ep_start,
>  	.get_features	= cdns_pcie_ep_get_features,
> @@ -455,6 +560,11 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
>  	if (of_property_read_u8(np, "max-functions", &epc->max_functions) < 0)
>  		epc->max_functions = 1;
>  
> +	ep->epf = devm_kcalloc(dev, epc->max_functions, sizeof(*ep->epf),
> +			       GFP_KERNEL);
> +	if (!ep->epf)
> +		return -ENOMEM;
> +
>  	ret = pci_epc_mem_init(epc, pcie->mem_res->start,
>  			       resource_size(pcie->mem_res));
>  	if (ret < 0) {
> diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
> index 16a6b0ee547c..ea850290a602 100644
> --- a/drivers/pci/controller/cadence/pcie-cadence.h
> +++ b/drivers/pci/controller/cadence/pcie-cadence.h
> @@ -99,6 +99,7 @@
>  #define CDNS_PCIE_EP_FUNC_BASE(fn)	(((fn) << 12) & GENMASK(19, 12))
>  
>  #define CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET	0x90
> +#define CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET	0xb0
>  
>  /*
>   * Root Port Registers (PCI configuration space for the root port function)
> @@ -280,6 +281,14 @@ struct cdns_pcie_rc {
>  	u32			device_id;
>  };
>  
> +/**
> + * struct cdns_pcie_epf - Structure to hold info about endpoint function
> + * @epf_bar: reference to the pci_epf_bar for the six Base Address Registers
> + */
> +struct cdns_pcie_epf {
> +	struct pci_epf_bar *epf_bar[PCI_STD_NUM_BARS];
> +};
> +
>  /**
>   * struct cdns_pcie_ep - private data for this PCIe endpoint controller driver
>   * @pcie: Cadence PCIe controller
> @@ -307,6 +316,7 @@ struct cdns_pcie_ep {
>  	u64			irq_pci_addr;
>  	u8			irq_pci_fn;
>  	u8			irq_pending;
> +	struct cdns_pcie_epf	*epf;
>  };
>  
>  
> -- 
> 2.17.1
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v3 12/14] PCI: j721e: Add TI J721E PCIe driver
  2020-04-17 12:57   ` Kishon Vijay Abraham I
@ 2020-04-30  2:11     ` Rob Herring
  -1 siblings, 0 replies; 46+ messages in thread
From: Rob Herring @ 2020-04-30  2:11 UTC (permalink / raw)
  To: Kishon Vijay Abraham I
  Cc: Tom Joseph, Bjorn Helgaas, Lorenzo Pieralisi, Andrew Murray,
	Arnd Bergmann, Greg Kroah-Hartman, linux-arm-kernel, linux-pci,
	devicetree, linux-kernel

On Fri, Apr 17, 2020 at 06:27:51PM +0530, Kishon Vijay Abraham I wrote:
> Add support for PCIe controller in J721E SoC. The controller uses the
> Cadence PCIe core programmed by pcie-cadence*.c. The PCIe controller
> will work in both host mode and device mode.
> Some of the features of the controller are:
>   *) Supports both RC mode and EP mode
>   *) Supports MSI and MSI-X support
>   *) Supports upto GEN3 speed mode
>   *) Supports SR-IOV capability
>   *) Ability to route all transactions via SMMU (support will be added
>      in a later patch).
> 
> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
> ---
>  drivers/pci/controller/cadence/Kconfig        |  23 +
>  drivers/pci/controller/cadence/Makefile       |   1 +
>  drivers/pci/controller/cadence/pci-j721e.c    | 500 ++++++++++++++++++
>  .../controller/cadence/pcie-cadence-host.c    |   4 +-
>  drivers/pci/controller/cadence/pcie-cadence.h |   8 +
>  5 files changed, 534 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/pci/controller/cadence/pci-j721e.c
> 
> diff --git a/drivers/pci/controller/cadence/Kconfig b/drivers/pci/controller/cadence/Kconfig
> index b76b3cf55ce5..5d30564190e1 100644
> --- a/drivers/pci/controller/cadence/Kconfig
> +++ b/drivers/pci/controller/cadence/Kconfig
> @@ -42,4 +42,27 @@ config PCIE_CADENCE_PLAT_EP
>  	  endpoint mode. This PCIe controller may be embedded into many
>  	  different vendors SoCs.
>  
> +config PCI_J721E
> +	bool
> +
> +config PCI_J721E_HOST
> +	bool "TI J721E PCIe platform host controller"
> +	depends on OF
> +	select PCIE_CADENCE_HOST
> +	select PCI_J721E
> +	help
> +	  Say Y here if you want to support the TI J721E PCIe platform
> +	  controller in host mode. TI J721E PCIe controller uses Cadence PCIe
> +	  core.
> +
> +config PCI_J721E_EP
> +	bool "TI J721E PCIe platform endpoint controller"
> +	depends on OF
> +	depends on PCI_ENDPOINT
> +	select PCIE_CADENCE_EP
> +	select PCI_J721E
> +	help
> +	  Say Y here if you want to support the TI J721E PCIe platform
> +	  controller in endpoint mode. TI J721E PCIe controller uses Cadence PCIe
> +	  core.
>  endmenu
> diff --git a/drivers/pci/controller/cadence/Makefile b/drivers/pci/controller/cadence/Makefile
> index 232a3f20876a..9bac5fb2f13d 100644
> --- a/drivers/pci/controller/cadence/Makefile
> +++ b/drivers/pci/controller/cadence/Makefile
> @@ -3,3 +3,4 @@ obj-$(CONFIG_PCIE_CADENCE) += pcie-cadence.o
>  obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o
>  obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep.o
>  obj-$(CONFIG_PCIE_CADENCE_PLAT) += pcie-cadence-plat.o
> +obj-$(CONFIG_PCI_J721E) += pci-j721e.o
> diff --git a/drivers/pci/controller/cadence/pci-j721e.c b/drivers/pci/controller/cadence/pci-j721e.c
> new file mode 100644
> index 000000000000..eee619c6ffae
> --- /dev/null
> +++ b/drivers/pci/controller/cadence/pci-j721e.c
> @@ -0,0 +1,500 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/**
> + * pci-j721e - PCIe controller driver for TI's J721E SoCs
> + *
> + * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com
> + * Author: Kishon Vijay Abraham I <kishon@ti.com>
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/io.h>
> +#include <linux/irqchip/chained_irq.h>
> +#include <linux/irqdomain.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/of_device.h>
> +#include <linux/of_irq.h>
> +#include <linux/pci.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regmap.h>
> +
> +#include "../../pci.h"
> +#include "pcie-cadence.h"
> +
> +#define ENABLE_REG_SYS_2	0x108
> +#define STATUS_REG_SYS_2	0x508
> +#define STATUS_CLR_REG_SYS_2	0x708
> +#define LINK_DOWN		BIT(1)
> +
> +#define J721E_PCIE_USER_CMD_STATUS	0x4
> +#define LINK_TRAINING_ENABLE		BIT(0)
> +
> +#define J721E_PCIE_USER_LINKSTATUS	0x14
> +#define LINK_STATUS			GENMASK(1, 0)
> +
> +enum link_status {
> +	NO_RECEIVERS_DETECTED,
> +	LINK_TRAINING_IN_PROGRESS,
> +	LINK_UP_DL_IN_PROGRESS,
> +	LINK_UP_DL_COMPLETED,
> +};
> +
> +#define J721E_MODE_RC			BIT(7)
> +#define LANE_COUNT_MASK			BIT(8)
> +#define LANE_COUNT(n)			((n) << 8)
> +
> +#define GENERATION_SEL_MASK		GENMASK(1, 0)
> +
> +#define MAX_LANES			2
> +
> +struct j721e_pcie {
> +	struct device		*dev;
> +	struct device_node	*node;
> +	u32			mode;
> +	u32			num_lanes;
> +	struct cdns_pcie	*cdns_pcie;
> +	void __iomem		*user_cfg_base;
> +	void __iomem		*intd_cfg_base;
> +};
> +
> +enum j721e_pcie_mode {
> +	PCI_MODE_RC,
> +	PCI_MODE_EP,
> +};
> +
> +struct j721e_pcie_data {
> +	enum j721e_pcie_mode	mode;
> +};
> +
> +static inline u32 j721e_pcie_user_readl(struct j721e_pcie *pcie, u32 offset)
> +{
> +	return readl(pcie->user_cfg_base + offset);
> +}
> +
> +static inline void j721e_pcie_user_writel(struct j721e_pcie *pcie, u32 offset,
> +					  u32 value)
> +{
> +	writel(value, pcie->user_cfg_base + offset);
> +}
> +
> +static inline u32 j721e_pcie_intd_readl(struct j721e_pcie *pcie, u32 offset)
> +{
> +	return readl(pcie->intd_cfg_base + offset);
> +}
> +
> +static inline void j721e_pcie_intd_writel(struct j721e_pcie *pcie, u32 offset,
> +					  u32 value)
> +{
> +	writel(value, pcie->intd_cfg_base + offset);
> +}
> +
> +static irqreturn_t j721e_pcie_link_irq_handler(int irq, void *priv)
> +{
> +	struct j721e_pcie *pcie = priv;
> +	struct device *dev = pcie->dev;
> +	u32 reg;
> +
> +	reg = j721e_pcie_intd_readl(pcie, STATUS_REG_SYS_2);
> +	if (!(reg & LINK_DOWN))
> +		return IRQ_NONE;
> +
> +	dev_err(dev, "LINK DOWN!\n");
> +
> +	j721e_pcie_intd_writel(pcie, STATUS_CLR_REG_SYS_2, LINK_DOWN);
> +	return IRQ_HANDLED;
> +}
> +
> +static void j721e_pcie_config_link_irq(struct j721e_pcie *pcie)
> +{
> +	u32 reg;
> +
> +	reg = j721e_pcie_intd_readl(pcie, ENABLE_REG_SYS_2);
> +	reg |= LINK_DOWN;
> +	j721e_pcie_intd_writel(pcie, ENABLE_REG_SYS_2, reg);
> +}
> +
> +static int j721e_pcie_start_link(struct cdns_pcie *cdns_pcie)
> +{
> +	struct j721e_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
> +	u32 reg;
> +
> +	reg = j721e_pcie_user_readl(pcie, J721E_PCIE_USER_CMD_STATUS);
> +	reg |= LINK_TRAINING_ENABLE;
> +	j721e_pcie_user_writel(pcie, J721E_PCIE_USER_CMD_STATUS, reg);
> +
> +	return 0;
> +}
> +
> +static void j721e_pcie_stop_link(struct cdns_pcie *cdns_pcie)
> +{
> +	struct j721e_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
> +	u32 reg;
> +
> +	reg = j721e_pcie_user_readl(pcie, J721E_PCIE_USER_CMD_STATUS);
> +	reg &= ~LINK_TRAINING_ENABLE;
> +	j721e_pcie_user_writel(pcie, J721E_PCIE_USER_CMD_STATUS, reg);
> +}
> +
> +static bool j721e_pcie_link_up(struct cdns_pcie *cdns_pcie)
> +{
> +	struct j721e_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
> +	u32 reg;
> +
> +	reg = j721e_pcie_user_readl(pcie, J721E_PCIE_USER_LINKSTATUS);
> +	reg &= LINK_STATUS;
> +	if (reg == LINK_UP_DL_COMPLETED)
> +		return true;
> +
> +	return false;
> +}
> +
> +static const struct cdns_pcie_ops j721e_ops_ops = {
> +	.read = cdns_platform_pcie_read32,
> +	.write = cdns_platform_pcie_write32,
> +	.start_link = j721e_pcie_start_link,
> +	.stop_link = j721e_pcie_stop_link,
> +	.link_up = j721e_pcie_link_up,
> +};
> +
> +static int j721e_pcie_set_mode(struct j721e_pcie *pcie, struct regmap *syscon)
> +{
> +	struct device *dev = pcie->dev;
> +	u32 mask = J721E_MODE_RC;
> +	u32 mode = pcie->mode;
> +	u32 val = 0;
> +	int ret = 0;
> +
> +	if (mode == PCI_MODE_RC)
> +		val = J721E_MODE_RC;
> +
> +	ret = regmap_update_bits(syscon, 0, mask, val);
> +	if (ret)
> +		dev_err(dev, "failed to set pcie mode\n");
> +
> +	return ret;
> +}
> +
> +static int j721e_pcie_set_link_speed(struct j721e_pcie *pcie,
> +				     struct regmap *syscon)
> +{
> +	struct device *dev = pcie->dev;
> +	struct device_node *np = dev->of_node;
> +	int link_speed;
> +	u32 val = 0;
> +	int ret;
> +
> +	link_speed = of_pci_get_max_link_speed(np);
> +	if (link_speed < 2)
> +		link_speed = 2;
> +
> +	val = link_speed - 1;
> +	ret = regmap_update_bits(syscon, 0, GENERATION_SEL_MASK, val);
> +	if (ret)
> +		dev_err(dev, "failed to set link speed\n");
> +
> +	return ret;
> +}
> +
> +static int j721e_pcie_set_lane_count(struct j721e_pcie *pcie,
> +				     struct regmap *syscon)
> +{
> +	struct device *dev = pcie->dev;
> +	u32 lanes = pcie->num_lanes;
> +	u32 val = 0;
> +	int ret;
> +
> +	val = LANE_COUNT(lanes - 1);
> +	ret = regmap_update_bits(syscon, 0, LANE_COUNT_MASK, val);
> +	if (ret)
> +		dev_err(dev, "failed to set link count\n");
> +
> +	return ret;
> +}
> +
> +static int j721e_pcie_ctrl_init(struct j721e_pcie *pcie)
> +{
> +	struct device *dev = pcie->dev;
> +	struct device_node *node = dev->of_node;
> +	struct regmap *syscon;
> +	int ret;
> +
> +	syscon = syscon_regmap_lookup_by_phandle(node, "ti,syscon-pcie-ctrl");
> +	if (IS_ERR(syscon)) {
> +		dev_err(dev, "Unable to get ti,syscon-pcie-ctrl regmap\n");
> +		return PTR_ERR(syscon);
> +	}
> +
> +	ret = j721e_pcie_set_mode(pcie, syscon);
> +	if (ret < 0) {
> +		dev_err(dev, "Failed to set pci mode\n");
> +		return ret;
> +	}
> +
> +	ret = j721e_pcie_set_link_speed(pcie, syscon);
> +	if (ret < 0) {
> +		dev_err(dev, "Failed to set link speed\n");
> +		return ret;
> +	}
> +
> +	ret = j721e_pcie_set_lane_count(pcie, syscon);
> +	if (ret < 0) {
> +		dev_err(dev, "Failed to set num-lanes\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int cdns_ti_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
> +				    int where, int size, u32 *value)
> +{
> +	struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
> +	struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge);
> +	unsigned int busn = bus->number;
> +
> +	if (busn == rc->bus_range->start)
> +		return pci_generic_config_read32(bus, devfn, where, size,
> +						 value);
> +
> +	return pci_generic_config_read(bus, devfn, where, size, value);
> +}
> +
> +static int cdns_ti_pcie_config_write(struct pci_bus *bus, unsigned int devfn,
> +				     int where, int size, u32 value)
> +{
> +	struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
> +	struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge);
> +	unsigned int busn = bus->number;
> +
> +	if (busn == rc->bus_range->start)
> +		return pci_generic_config_write32(bus, devfn, where, size,
> +						  value);
> +
> +	return pci_generic_config_write(bus, devfn, where, size, value);
> +}
> +
> +static struct pci_ops cdns_ti_pcie_host_ops = {
> +	.map_bus	= cdns_pci_map_bus,
> +	.read		= cdns_ti_pcie_config_read,
> +	.write		= cdns_ti_pcie_config_write,
> +};
> +
> +static const struct j721e_pcie_data j721e_pcie_rc_data = {
> +	.mode = PCI_MODE_RC,
> +};
> +
> +static const struct j721e_pcie_data j721e_pcie_ep_data = {
> +	.mode = PCI_MODE_EP,
> +};
> +
> +static const struct of_device_id of_j721e_pcie_match[] = {
> +	{
> +		.compatible = "ti,j721e-pcie-host",
> +		.data = &j721e_pcie_rc_data,
> +	},
> +	{
> +		.compatible = "ti,j721e-pcie-ep",
> +		.data = &j721e_pcie_ep_data,
> +	},
> +	{},
> +};
> +
> +static int j721e_pcie_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device_node *node = dev->of_node;
> +	const struct of_device_id *match;
> +	struct pci_host_bridge *bridge;
> +	struct j721e_pcie_data *data;
> +	struct cdns_pcie *cdns_pcie;
> +	struct j721e_pcie *pcie;
> +	struct cdns_pcie_rc *rc;
> +	struct cdns_pcie_ep *ep;
> +	struct gpio_desc *gpiod;
> +	struct resource *res;
> +	void __iomem *base;
> +	u32 num_lanes;
> +	u32 mode;
> +	int ret;
> +	int irq;
> +
> +	match = of_match_device(of_match_ptr(of_j721e_pcie_match), dev);
> +	if (!match)
> +		return -EINVAL;
> +
> +	data = (struct j721e_pcie_data *)match->data;

Use of_device_get_match_data()

> +	mode = (u32)data->mode;
> +
> +	pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
> +	if (!pcie)
> +		return -ENOMEM;
> +
> +	pcie->dev = dev;
> +	pcie->node = node;

The dev has the node, why do you need it twice?

> +	pcie->mode = mode;
> +
> +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intd_cfg");
> +	base = devm_ioremap_resource(dev, res);

devm_platform_ioremap_resource_byname()

> +	if (IS_ERR(base))
> +		return PTR_ERR(base);
> +	pcie->intd_cfg_base = base;
> +
> +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "user_cfg");
> +	base = devm_ioremap_resource(dev, res);

devm_platform_ioremap_resource_byname

> +	if (IS_ERR(base))
> +		return PTR_ERR(base);
> +	pcie->user_cfg_base = base;
> +
> +	ret = of_property_read_u32(node, "num-lanes", &num_lanes);
> +	if (ret || num_lanes > MAX_LANES)
> +		num_lanes = 1;
> +	pcie->num_lanes = num_lanes;
> +
> +	irq = platform_get_irq_byname(pdev, "link_state");
> +	if (irq < 0)
> +		return irq;
> +
> +	dev_set_drvdata(dev, pcie);
> +	pm_runtime_enable(dev);
> +	ret = pm_runtime_get_sync(dev);
> +	if (ret < 0) {
> +		dev_err(dev, "pm_runtime_get_sync failed\n");
> +		goto err_get_sync;
> +	}
> +
> +	ret = j721e_pcie_ctrl_init(pcie);
> +	if (ret < 0) {
> +		dev_err(dev, "pm_runtime_get_sync failed\n");
> +		goto err_get_sync;
> +	}
> +
> +	ret = devm_request_irq(dev, irq, j721e_pcie_link_irq_handler,
> +			       IRQF_SHARED, "j721e-pcie-link_state-irq", pcie);

Really shared?

> +	if (ret < 0) {
> +		dev_err(dev, "failed to request link state IRQ %d\n", irq);
> +		goto err_get_sync;
> +	}
> +
> +	j721e_pcie_config_link_irq(pcie);
> +
> +	switch (mode) {
> +	case PCI_MODE_RC:
> +		if (!IS_ENABLED(CONFIG_PCIE_CADENCE_HOST)) {
> +			ret = -ENODEV;
> +			goto err_get_sync;
> +		}
> +
> +		bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
> +		if (!bridge) {
> +			ret = -ENOMEM;
> +			goto err_get_sync;
> +		}
> +
> +		bridge->ops = &cdns_ti_pcie_host_ops;
> +		rc = pci_host_bridge_priv(bridge);
> +
> +		cdns_pcie = &rc->pcie;
> +		cdns_pcie->dev = dev;
> +		cdns_pcie->ops = &j721e_ops_ops;
> +		pcie->cdns_pcie = cdns_pcie;
> +
> +		gpiod = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
> +		if (IS_ERR(gpiod)) {
> +			ret = PTR_ERR(gpiod);
> +			if (ret != -EPROBE_DEFER)
> +				dev_err(dev, "Failed to get reset GPIO\n");
> +			goto err_get_sync;
> +		}
> +
> +		ret = cdns_pcie_init_phy(dev, cdns_pcie);
> +		if (ret) {
> +			dev_err(dev, "Failed to init phy\n");
> +			goto err_get_sync;
> +		}
> +
> +		/*
> +		 * "Power Sequencing and Reset Signal Timings" table in
> +		 * PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 3.0
> +		 * indicates PERST# should be deasserted after minimum of 100us
> +		 * once REFCLK is stable. The REFCLK to the connector in RC
> +		 * mode is selected while enabling the PHY. So deassert PERST#
> +		 * after 100 us.
> +		 */
> +		if (gpiod) {
> +			usleep_range(100, 200);
> +			gpiod_set_value_cansleep(gpiod, 1);
> +		}
> +
> +		ret = cdns_pcie_host_setup(rc);
> +		if (ret < 0)
> +			goto err_pcie_setup;
> +
> +		break;
> +	case PCI_MODE_EP:
> +		if (!IS_ENABLED(CONFIG_PCIE_CADENCE_EP)) {
> +			ret = -ENODEV;
> +			goto err_get_sync;
> +		}
> +
> +		ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
> +		if (!ep) {
> +			ret = -ENOMEM;
> +			goto err_get_sync;
> +		}
> +
> +		cdns_pcie = &ep->pcie;
> +		cdns_pcie->dev = dev;
> +		cdns_pcie->ops = &j721e_ops_ops;
> +		pcie->cdns_pcie = cdns_pcie;
> +
> +		ret = cdns_pcie_init_phy(dev, cdns_pcie);
> +		if (ret) {
> +			dev_err(dev, "Failed to init phy\n");
> +			goto err_get_sync;
> +		}
> +
> +		ret = cdns_pcie_ep_setup(ep);
> +		if (ret < 0)
> +			goto err_pcie_setup;
> +
> +		break;
> +	default:
> +		dev_err(dev, "INVALID device type %d\n", mode);
> +	}
> +
> +	return 0;
> +
> +err_pcie_setup:
> +	cdns_pcie_disable_phy(cdns_pcie);
> +
> +err_get_sync:
> +	pm_runtime_put(dev);
> +	pm_runtime_disable(dev);
> +
> +	return ret;
> +}
> +
> +static int j721e_pcie_remove(struct platform_device *pdev)
> +{
> +	struct j721e_pcie *pcie = platform_get_drvdata(pdev);
> +	struct cdns_pcie *cdns_pcie = pcie->cdns_pcie;
> +	struct device *dev = &pdev->dev;
> +
> +	cdns_pcie_disable_phy(cdns_pcie);
> +	pm_runtime_put(dev);
> +	pm_runtime_disable(dev);
> +	of_platform_depopulate(dev);

I don't see a populate. Is this supposed to be here?

> +
> +	return 0;
> +}
> +
> +static struct platform_driver j721e_pcie_driver = {
> +	.probe  = j721e_pcie_probe,
> +	.remove = j721e_pcie_remove,
> +	.driver = {
> +		.name	= "j721e-pcie",
> +		.of_match_table = of_j721e_pcie_match,
> +		.suppress_bind_attrs = true,
> +	},
> +};
> +builtin_platform_driver(j721e_pcie_driver);
> diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c
> index c7dc7be0da40..d7cc7ea4fba3 100644
> --- a/drivers/pci/controller/cadence/pcie-cadence-host.c
> +++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
> @@ -11,8 +11,8 @@
>  
>  #include "pcie-cadence.h"
>  
> -static void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
> -				      int where)
> +void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
> +			       int where)
>  {
>  	struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
>  	struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge);
> diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
> index ea850290a602..f349f5828a58 100644
> --- a/drivers/pci/controller/cadence/pcie-cadence.h
> +++ b/drivers/pci/controller/cadence/pcie-cadence.h
> @@ -488,11 +488,19 @@ static inline bool cdns_pcie_link_up(struct cdns_pcie *pcie)
>  
>  #ifdef CONFIG_PCIE_CADENCE_HOST
>  int cdns_pcie_host_setup(struct cdns_pcie_rc *rc);
> +void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
> +			       int where);
>  #else
>  static inline int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
>  {
>  	return 0;
>  }
> +
> +static void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
> +				      int where)
> +{
> +	return NULL;
> +}
>  #endif
>  
>  #ifdef CONFIG_PCIE_CADENCE_EP
> -- 
> 2.17.1
> 

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

* Re: [PATCH v3 12/14] PCI: j721e: Add TI J721E PCIe driver
@ 2020-04-30  2:11     ` Rob Herring
  0 siblings, 0 replies; 46+ messages in thread
From: Rob Herring @ 2020-04-30  2:11 UTC (permalink / raw)
  To: Kishon Vijay Abraham I
  Cc: devicetree, Lorenzo Pieralisi, Arnd Bergmann, Greg Kroah-Hartman,
	linux-kernel, Tom Joseph, linux-pci, Bjorn Helgaas,
	linux-arm-kernel, Andrew Murray

On Fri, Apr 17, 2020 at 06:27:51PM +0530, Kishon Vijay Abraham I wrote:
> Add support for PCIe controller in J721E SoC. The controller uses the
> Cadence PCIe core programmed by pcie-cadence*.c. The PCIe controller
> will work in both host mode and device mode.
> Some of the features of the controller are:
>   *) Supports both RC mode and EP mode
>   *) Supports MSI and MSI-X support
>   *) Supports upto GEN3 speed mode
>   *) Supports SR-IOV capability
>   *) Ability to route all transactions via SMMU (support will be added
>      in a later patch).
> 
> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
> ---
>  drivers/pci/controller/cadence/Kconfig        |  23 +
>  drivers/pci/controller/cadence/Makefile       |   1 +
>  drivers/pci/controller/cadence/pci-j721e.c    | 500 ++++++++++++++++++
>  .../controller/cadence/pcie-cadence-host.c    |   4 +-
>  drivers/pci/controller/cadence/pcie-cadence.h |   8 +
>  5 files changed, 534 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/pci/controller/cadence/pci-j721e.c
> 
> diff --git a/drivers/pci/controller/cadence/Kconfig b/drivers/pci/controller/cadence/Kconfig
> index b76b3cf55ce5..5d30564190e1 100644
> --- a/drivers/pci/controller/cadence/Kconfig
> +++ b/drivers/pci/controller/cadence/Kconfig
> @@ -42,4 +42,27 @@ config PCIE_CADENCE_PLAT_EP
>  	  endpoint mode. This PCIe controller may be embedded into many
>  	  different vendors SoCs.
>  
> +config PCI_J721E
> +	bool
> +
> +config PCI_J721E_HOST
> +	bool "TI J721E PCIe platform host controller"
> +	depends on OF
> +	select PCIE_CADENCE_HOST
> +	select PCI_J721E
> +	help
> +	  Say Y here if you want to support the TI J721E PCIe platform
> +	  controller in host mode. TI J721E PCIe controller uses Cadence PCIe
> +	  core.
> +
> +config PCI_J721E_EP
> +	bool "TI J721E PCIe platform endpoint controller"
> +	depends on OF
> +	depends on PCI_ENDPOINT
> +	select PCIE_CADENCE_EP
> +	select PCI_J721E
> +	help
> +	  Say Y here if you want to support the TI J721E PCIe platform
> +	  controller in endpoint mode. TI J721E PCIe controller uses Cadence PCIe
> +	  core.
>  endmenu
> diff --git a/drivers/pci/controller/cadence/Makefile b/drivers/pci/controller/cadence/Makefile
> index 232a3f20876a..9bac5fb2f13d 100644
> --- a/drivers/pci/controller/cadence/Makefile
> +++ b/drivers/pci/controller/cadence/Makefile
> @@ -3,3 +3,4 @@ obj-$(CONFIG_PCIE_CADENCE) += pcie-cadence.o
>  obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o
>  obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep.o
>  obj-$(CONFIG_PCIE_CADENCE_PLAT) += pcie-cadence-plat.o
> +obj-$(CONFIG_PCI_J721E) += pci-j721e.o
> diff --git a/drivers/pci/controller/cadence/pci-j721e.c b/drivers/pci/controller/cadence/pci-j721e.c
> new file mode 100644
> index 000000000000..eee619c6ffae
> --- /dev/null
> +++ b/drivers/pci/controller/cadence/pci-j721e.c
> @@ -0,0 +1,500 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/**
> + * pci-j721e - PCIe controller driver for TI's J721E SoCs
> + *
> + * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com
> + * Author: Kishon Vijay Abraham I <kishon@ti.com>
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/io.h>
> +#include <linux/irqchip/chained_irq.h>
> +#include <linux/irqdomain.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/of_device.h>
> +#include <linux/of_irq.h>
> +#include <linux/pci.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regmap.h>
> +
> +#include "../../pci.h"
> +#include "pcie-cadence.h"
> +
> +#define ENABLE_REG_SYS_2	0x108
> +#define STATUS_REG_SYS_2	0x508
> +#define STATUS_CLR_REG_SYS_2	0x708
> +#define LINK_DOWN		BIT(1)
> +
> +#define J721E_PCIE_USER_CMD_STATUS	0x4
> +#define LINK_TRAINING_ENABLE		BIT(0)
> +
> +#define J721E_PCIE_USER_LINKSTATUS	0x14
> +#define LINK_STATUS			GENMASK(1, 0)
> +
> +enum link_status {
> +	NO_RECEIVERS_DETECTED,
> +	LINK_TRAINING_IN_PROGRESS,
> +	LINK_UP_DL_IN_PROGRESS,
> +	LINK_UP_DL_COMPLETED,
> +};
> +
> +#define J721E_MODE_RC			BIT(7)
> +#define LANE_COUNT_MASK			BIT(8)
> +#define LANE_COUNT(n)			((n) << 8)
> +
> +#define GENERATION_SEL_MASK		GENMASK(1, 0)
> +
> +#define MAX_LANES			2
> +
> +struct j721e_pcie {
> +	struct device		*dev;
> +	struct device_node	*node;
> +	u32			mode;
> +	u32			num_lanes;
> +	struct cdns_pcie	*cdns_pcie;
> +	void __iomem		*user_cfg_base;
> +	void __iomem		*intd_cfg_base;
> +};
> +
> +enum j721e_pcie_mode {
> +	PCI_MODE_RC,
> +	PCI_MODE_EP,
> +};
> +
> +struct j721e_pcie_data {
> +	enum j721e_pcie_mode	mode;
> +};
> +
> +static inline u32 j721e_pcie_user_readl(struct j721e_pcie *pcie, u32 offset)
> +{
> +	return readl(pcie->user_cfg_base + offset);
> +}
> +
> +static inline void j721e_pcie_user_writel(struct j721e_pcie *pcie, u32 offset,
> +					  u32 value)
> +{
> +	writel(value, pcie->user_cfg_base + offset);
> +}
> +
> +static inline u32 j721e_pcie_intd_readl(struct j721e_pcie *pcie, u32 offset)
> +{
> +	return readl(pcie->intd_cfg_base + offset);
> +}
> +
> +static inline void j721e_pcie_intd_writel(struct j721e_pcie *pcie, u32 offset,
> +					  u32 value)
> +{
> +	writel(value, pcie->intd_cfg_base + offset);
> +}
> +
> +static irqreturn_t j721e_pcie_link_irq_handler(int irq, void *priv)
> +{
> +	struct j721e_pcie *pcie = priv;
> +	struct device *dev = pcie->dev;
> +	u32 reg;
> +
> +	reg = j721e_pcie_intd_readl(pcie, STATUS_REG_SYS_2);
> +	if (!(reg & LINK_DOWN))
> +		return IRQ_NONE;
> +
> +	dev_err(dev, "LINK DOWN!\n");
> +
> +	j721e_pcie_intd_writel(pcie, STATUS_CLR_REG_SYS_2, LINK_DOWN);
> +	return IRQ_HANDLED;
> +}
> +
> +static void j721e_pcie_config_link_irq(struct j721e_pcie *pcie)
> +{
> +	u32 reg;
> +
> +	reg = j721e_pcie_intd_readl(pcie, ENABLE_REG_SYS_2);
> +	reg |= LINK_DOWN;
> +	j721e_pcie_intd_writel(pcie, ENABLE_REG_SYS_2, reg);
> +}
> +
> +static int j721e_pcie_start_link(struct cdns_pcie *cdns_pcie)
> +{
> +	struct j721e_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
> +	u32 reg;
> +
> +	reg = j721e_pcie_user_readl(pcie, J721E_PCIE_USER_CMD_STATUS);
> +	reg |= LINK_TRAINING_ENABLE;
> +	j721e_pcie_user_writel(pcie, J721E_PCIE_USER_CMD_STATUS, reg);
> +
> +	return 0;
> +}
> +
> +static void j721e_pcie_stop_link(struct cdns_pcie *cdns_pcie)
> +{
> +	struct j721e_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
> +	u32 reg;
> +
> +	reg = j721e_pcie_user_readl(pcie, J721E_PCIE_USER_CMD_STATUS);
> +	reg &= ~LINK_TRAINING_ENABLE;
> +	j721e_pcie_user_writel(pcie, J721E_PCIE_USER_CMD_STATUS, reg);
> +}
> +
> +static bool j721e_pcie_link_up(struct cdns_pcie *cdns_pcie)
> +{
> +	struct j721e_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
> +	u32 reg;
> +
> +	reg = j721e_pcie_user_readl(pcie, J721E_PCIE_USER_LINKSTATUS);
> +	reg &= LINK_STATUS;
> +	if (reg == LINK_UP_DL_COMPLETED)
> +		return true;
> +
> +	return false;
> +}
> +
> +static const struct cdns_pcie_ops j721e_ops_ops = {
> +	.read = cdns_platform_pcie_read32,
> +	.write = cdns_platform_pcie_write32,
> +	.start_link = j721e_pcie_start_link,
> +	.stop_link = j721e_pcie_stop_link,
> +	.link_up = j721e_pcie_link_up,
> +};
> +
> +static int j721e_pcie_set_mode(struct j721e_pcie *pcie, struct regmap *syscon)
> +{
> +	struct device *dev = pcie->dev;
> +	u32 mask = J721E_MODE_RC;
> +	u32 mode = pcie->mode;
> +	u32 val = 0;
> +	int ret = 0;
> +
> +	if (mode == PCI_MODE_RC)
> +		val = J721E_MODE_RC;
> +
> +	ret = regmap_update_bits(syscon, 0, mask, val);
> +	if (ret)
> +		dev_err(dev, "failed to set pcie mode\n");
> +
> +	return ret;
> +}
> +
> +static int j721e_pcie_set_link_speed(struct j721e_pcie *pcie,
> +				     struct regmap *syscon)
> +{
> +	struct device *dev = pcie->dev;
> +	struct device_node *np = dev->of_node;
> +	int link_speed;
> +	u32 val = 0;
> +	int ret;
> +
> +	link_speed = of_pci_get_max_link_speed(np);
> +	if (link_speed < 2)
> +		link_speed = 2;
> +
> +	val = link_speed - 1;
> +	ret = regmap_update_bits(syscon, 0, GENERATION_SEL_MASK, val);
> +	if (ret)
> +		dev_err(dev, "failed to set link speed\n");
> +
> +	return ret;
> +}
> +
> +static int j721e_pcie_set_lane_count(struct j721e_pcie *pcie,
> +				     struct regmap *syscon)
> +{
> +	struct device *dev = pcie->dev;
> +	u32 lanes = pcie->num_lanes;
> +	u32 val = 0;
> +	int ret;
> +
> +	val = LANE_COUNT(lanes - 1);
> +	ret = regmap_update_bits(syscon, 0, LANE_COUNT_MASK, val);
> +	if (ret)
> +		dev_err(dev, "failed to set link count\n");
> +
> +	return ret;
> +}
> +
> +static int j721e_pcie_ctrl_init(struct j721e_pcie *pcie)
> +{
> +	struct device *dev = pcie->dev;
> +	struct device_node *node = dev->of_node;
> +	struct regmap *syscon;
> +	int ret;
> +
> +	syscon = syscon_regmap_lookup_by_phandle(node, "ti,syscon-pcie-ctrl");
> +	if (IS_ERR(syscon)) {
> +		dev_err(dev, "Unable to get ti,syscon-pcie-ctrl regmap\n");
> +		return PTR_ERR(syscon);
> +	}
> +
> +	ret = j721e_pcie_set_mode(pcie, syscon);
> +	if (ret < 0) {
> +		dev_err(dev, "Failed to set pci mode\n");
> +		return ret;
> +	}
> +
> +	ret = j721e_pcie_set_link_speed(pcie, syscon);
> +	if (ret < 0) {
> +		dev_err(dev, "Failed to set link speed\n");
> +		return ret;
> +	}
> +
> +	ret = j721e_pcie_set_lane_count(pcie, syscon);
> +	if (ret < 0) {
> +		dev_err(dev, "Failed to set num-lanes\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int cdns_ti_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
> +				    int where, int size, u32 *value)
> +{
> +	struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
> +	struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge);
> +	unsigned int busn = bus->number;
> +
> +	if (busn == rc->bus_range->start)
> +		return pci_generic_config_read32(bus, devfn, where, size,
> +						 value);
> +
> +	return pci_generic_config_read(bus, devfn, where, size, value);
> +}
> +
> +static int cdns_ti_pcie_config_write(struct pci_bus *bus, unsigned int devfn,
> +				     int where, int size, u32 value)
> +{
> +	struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
> +	struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge);
> +	unsigned int busn = bus->number;
> +
> +	if (busn == rc->bus_range->start)
> +		return pci_generic_config_write32(bus, devfn, where, size,
> +						  value);
> +
> +	return pci_generic_config_write(bus, devfn, where, size, value);
> +}
> +
> +static struct pci_ops cdns_ti_pcie_host_ops = {
> +	.map_bus	= cdns_pci_map_bus,
> +	.read		= cdns_ti_pcie_config_read,
> +	.write		= cdns_ti_pcie_config_write,
> +};
> +
> +static const struct j721e_pcie_data j721e_pcie_rc_data = {
> +	.mode = PCI_MODE_RC,
> +};
> +
> +static const struct j721e_pcie_data j721e_pcie_ep_data = {
> +	.mode = PCI_MODE_EP,
> +};
> +
> +static const struct of_device_id of_j721e_pcie_match[] = {
> +	{
> +		.compatible = "ti,j721e-pcie-host",
> +		.data = &j721e_pcie_rc_data,
> +	},
> +	{
> +		.compatible = "ti,j721e-pcie-ep",
> +		.data = &j721e_pcie_ep_data,
> +	},
> +	{},
> +};
> +
> +static int j721e_pcie_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device_node *node = dev->of_node;
> +	const struct of_device_id *match;
> +	struct pci_host_bridge *bridge;
> +	struct j721e_pcie_data *data;
> +	struct cdns_pcie *cdns_pcie;
> +	struct j721e_pcie *pcie;
> +	struct cdns_pcie_rc *rc;
> +	struct cdns_pcie_ep *ep;
> +	struct gpio_desc *gpiod;
> +	struct resource *res;
> +	void __iomem *base;
> +	u32 num_lanes;
> +	u32 mode;
> +	int ret;
> +	int irq;
> +
> +	match = of_match_device(of_match_ptr(of_j721e_pcie_match), dev);
> +	if (!match)
> +		return -EINVAL;
> +
> +	data = (struct j721e_pcie_data *)match->data;

Use of_device_get_match_data()

> +	mode = (u32)data->mode;
> +
> +	pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
> +	if (!pcie)
> +		return -ENOMEM;
> +
> +	pcie->dev = dev;
> +	pcie->node = node;

The dev has the node, why do you need it twice?

> +	pcie->mode = mode;
> +
> +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intd_cfg");
> +	base = devm_ioremap_resource(dev, res);

devm_platform_ioremap_resource_byname()

> +	if (IS_ERR(base))
> +		return PTR_ERR(base);
> +	pcie->intd_cfg_base = base;
> +
> +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "user_cfg");
> +	base = devm_ioremap_resource(dev, res);

devm_platform_ioremap_resource_byname

> +	if (IS_ERR(base))
> +		return PTR_ERR(base);
> +	pcie->user_cfg_base = base;
> +
> +	ret = of_property_read_u32(node, "num-lanes", &num_lanes);
> +	if (ret || num_lanes > MAX_LANES)
> +		num_lanes = 1;
> +	pcie->num_lanes = num_lanes;
> +
> +	irq = platform_get_irq_byname(pdev, "link_state");
> +	if (irq < 0)
> +		return irq;
> +
> +	dev_set_drvdata(dev, pcie);
> +	pm_runtime_enable(dev);
> +	ret = pm_runtime_get_sync(dev);
> +	if (ret < 0) {
> +		dev_err(dev, "pm_runtime_get_sync failed\n");
> +		goto err_get_sync;
> +	}
> +
> +	ret = j721e_pcie_ctrl_init(pcie);
> +	if (ret < 0) {
> +		dev_err(dev, "pm_runtime_get_sync failed\n");
> +		goto err_get_sync;
> +	}
> +
> +	ret = devm_request_irq(dev, irq, j721e_pcie_link_irq_handler,
> +			       IRQF_SHARED, "j721e-pcie-link_state-irq", pcie);

Really shared?

> +	if (ret < 0) {
> +		dev_err(dev, "failed to request link state IRQ %d\n", irq);
> +		goto err_get_sync;
> +	}
> +
> +	j721e_pcie_config_link_irq(pcie);
> +
> +	switch (mode) {
> +	case PCI_MODE_RC:
> +		if (!IS_ENABLED(CONFIG_PCIE_CADENCE_HOST)) {
> +			ret = -ENODEV;
> +			goto err_get_sync;
> +		}
> +
> +		bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
> +		if (!bridge) {
> +			ret = -ENOMEM;
> +			goto err_get_sync;
> +		}
> +
> +		bridge->ops = &cdns_ti_pcie_host_ops;
> +		rc = pci_host_bridge_priv(bridge);
> +
> +		cdns_pcie = &rc->pcie;
> +		cdns_pcie->dev = dev;
> +		cdns_pcie->ops = &j721e_ops_ops;
> +		pcie->cdns_pcie = cdns_pcie;
> +
> +		gpiod = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
> +		if (IS_ERR(gpiod)) {
> +			ret = PTR_ERR(gpiod);
> +			if (ret != -EPROBE_DEFER)
> +				dev_err(dev, "Failed to get reset GPIO\n");
> +			goto err_get_sync;
> +		}
> +
> +		ret = cdns_pcie_init_phy(dev, cdns_pcie);
> +		if (ret) {
> +			dev_err(dev, "Failed to init phy\n");
> +			goto err_get_sync;
> +		}
> +
> +		/*
> +		 * "Power Sequencing and Reset Signal Timings" table in
> +		 * PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 3.0
> +		 * indicates PERST# should be deasserted after minimum of 100us
> +		 * once REFCLK is stable. The REFCLK to the connector in RC
> +		 * mode is selected while enabling the PHY. So deassert PERST#
> +		 * after 100 us.
> +		 */
> +		if (gpiod) {
> +			usleep_range(100, 200);
> +			gpiod_set_value_cansleep(gpiod, 1);
> +		}
> +
> +		ret = cdns_pcie_host_setup(rc);
> +		if (ret < 0)
> +			goto err_pcie_setup;
> +
> +		break;
> +	case PCI_MODE_EP:
> +		if (!IS_ENABLED(CONFIG_PCIE_CADENCE_EP)) {
> +			ret = -ENODEV;
> +			goto err_get_sync;
> +		}
> +
> +		ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
> +		if (!ep) {
> +			ret = -ENOMEM;
> +			goto err_get_sync;
> +		}
> +
> +		cdns_pcie = &ep->pcie;
> +		cdns_pcie->dev = dev;
> +		cdns_pcie->ops = &j721e_ops_ops;
> +		pcie->cdns_pcie = cdns_pcie;
> +
> +		ret = cdns_pcie_init_phy(dev, cdns_pcie);
> +		if (ret) {
> +			dev_err(dev, "Failed to init phy\n");
> +			goto err_get_sync;
> +		}
> +
> +		ret = cdns_pcie_ep_setup(ep);
> +		if (ret < 0)
> +			goto err_pcie_setup;
> +
> +		break;
> +	default:
> +		dev_err(dev, "INVALID device type %d\n", mode);
> +	}
> +
> +	return 0;
> +
> +err_pcie_setup:
> +	cdns_pcie_disable_phy(cdns_pcie);
> +
> +err_get_sync:
> +	pm_runtime_put(dev);
> +	pm_runtime_disable(dev);
> +
> +	return ret;
> +}
> +
> +static int j721e_pcie_remove(struct platform_device *pdev)
> +{
> +	struct j721e_pcie *pcie = platform_get_drvdata(pdev);
> +	struct cdns_pcie *cdns_pcie = pcie->cdns_pcie;
> +	struct device *dev = &pdev->dev;
> +
> +	cdns_pcie_disable_phy(cdns_pcie);
> +	pm_runtime_put(dev);
> +	pm_runtime_disable(dev);
> +	of_platform_depopulate(dev);

I don't see a populate. Is this supposed to be here?

> +
> +	return 0;
> +}
> +
> +static struct platform_driver j721e_pcie_driver = {
> +	.probe  = j721e_pcie_probe,
> +	.remove = j721e_pcie_remove,
> +	.driver = {
> +		.name	= "j721e-pcie",
> +		.of_match_table = of_j721e_pcie_match,
> +		.suppress_bind_attrs = true,
> +	},
> +};
> +builtin_platform_driver(j721e_pcie_driver);
> diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c
> index c7dc7be0da40..d7cc7ea4fba3 100644
> --- a/drivers/pci/controller/cadence/pcie-cadence-host.c
> +++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
> @@ -11,8 +11,8 @@
>  
>  #include "pcie-cadence.h"
>  
> -static void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
> -				      int where)
> +void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
> +			       int where)
>  {
>  	struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
>  	struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge);
> diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
> index ea850290a602..f349f5828a58 100644
> --- a/drivers/pci/controller/cadence/pcie-cadence.h
> +++ b/drivers/pci/controller/cadence/pcie-cadence.h
> @@ -488,11 +488,19 @@ static inline bool cdns_pcie_link_up(struct cdns_pcie *pcie)
>  
>  #ifdef CONFIG_PCIE_CADENCE_HOST
>  int cdns_pcie_host_setup(struct cdns_pcie_rc *rc);
> +void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
> +			       int where);
>  #else
>  static inline int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
>  {
>  	return 0;
>  }
> +
> +static void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
> +				      int where)
> +{
> +	return NULL;
> +}
>  #endif
>  
>  #ifdef CONFIG_PCIE_CADENCE_EP
> -- 
> 2.17.1
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v3 10/14] dt-bindings: PCI: Add host mode dt-bindings for TI's J721E SoC
  2020-04-17 12:57   ` Kishon Vijay Abraham I
@ 2020-04-30  2:11     ` Rob Herring
  -1 siblings, 0 replies; 46+ messages in thread
From: Rob Herring @ 2020-04-30  2:11 UTC (permalink / raw)
  To: Kishon Vijay Abraham I
  Cc: Tom Joseph, Bjorn Helgaas, Rob Herring, Lorenzo Pieralisi,
	Andrew Murray, Arnd Bergmann, Greg Kroah-Hartman,
	linux-arm-kernel, linux-pci, devicetree, linux-kernel

On Fri, 17 Apr 2020 18:27:49 +0530, Kishon Vijay Abraham I wrote:
> Add host mode dt-bindings for TI's J721E SoC.
> 
> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
> ---
>  .../bindings/pci/ti,j721e-pci-host.yaml       | 113 ++++++++++++++++++
>  1 file changed, 113 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml
> 

Reviewed-by: Rob Herring <robh@kernel.org>

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

* Re: [PATCH v3 10/14] dt-bindings: PCI: Add host mode dt-bindings for TI's J721E SoC
@ 2020-04-30  2:11     ` Rob Herring
  0 siblings, 0 replies; 46+ messages in thread
From: Rob Herring @ 2020-04-30  2:11 UTC (permalink / raw)
  To: Kishon Vijay Abraham I
  Cc: devicetree, Lorenzo Pieralisi, Arnd Bergmann, Greg Kroah-Hartman,
	linux-kernel, Tom Joseph, Rob Herring, linux-pci, Bjorn Helgaas,
	linux-arm-kernel, Andrew Murray

On Fri, 17 Apr 2020 18:27:49 +0530, Kishon Vijay Abraham I wrote:
> Add host mode dt-bindings for TI's J721E SoC.
> 
> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
> ---
>  .../bindings/pci/ti,j721e-pci-host.yaml       | 113 ++++++++++++++++++
>  1 file changed, 113 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml
> 

Reviewed-by: Rob Herring <robh@kernel.org>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v3 11/14] dt-bindings: PCI: Add EP mode dt-bindings for TI's J721E SoC
  2020-04-17 12:57   ` Kishon Vijay Abraham I
@ 2020-04-30  2:13     ` Rob Herring
  -1 siblings, 0 replies; 46+ messages in thread
From: Rob Herring @ 2020-04-30  2:13 UTC (permalink / raw)
  To: Kishon Vijay Abraham I
  Cc: Tom Joseph, Bjorn Helgaas, Lorenzo Pieralisi, Andrew Murray,
	Arnd Bergmann, Greg Kroah-Hartman, linux-arm-kernel, linux-pci,
	devicetree, linux-kernel

On Fri, Apr 17, 2020 at 06:27:50PM +0530, Kishon Vijay Abraham I wrote:
> Add PCIe EP mode dt-bindings for TI's J721E SoC.
> 
> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
> ---
>  .../bindings/pci/ti,j721e-pci-ep.yaml         | 89 +++++++++++++++++++
>  1 file changed, 89 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml
> 
> diff --git a/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml b/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml
> new file mode 100644
> index 000000000000..cb25c45d5a96
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml
> @@ -0,0 +1,89 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +# Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/
> +%YAML 1.2
> +---
> +$id: "http://devicetree.org/schemas/pci/ti,j721e-pci-ep.yaml#"
> +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
> +
> +title: TI J721E PCI EP (PCIe Wrapper)
> +
> +maintainers:
> +  - Kishon Vijay Abraham I <kishon@ti.com>
> +
> +allOf:
> +  - $ref: "cdns-pcie-ep.yaml#"
> +
> +properties:
> +  compatible:
> +      enum:
> +          - ti,j721e-pcie-ep

Wrong indentation.

Otherwise,

Reviewed-by: Rob Herring <robh@kernel.org>

> +
> +  reg:
> +    maxItems: 4
> +
> +  reg-names:
> +    items:
> +      - const: intd_cfg
> +      - const: user_cfg
> +      - const: reg
> +      - const: mem
> +
> +  ti,syscon-pcie-ctrl:
> +    description: Phandle to the SYSCON entry required for configuring PCIe mode
> +                 and link speed.
> +    allOf:
> +      - $ref: /schemas/types.yaml#/definitions/phandle
> +
> +  power-domains:
> +    maxItems: 1
> +
> +  clocks:
> +    maxItems: 1
> +    description: clock-specifier to represent input to the PCIe
> +
> +  clock-names:
> +    items:
> +      - const: fck
> +
> +  dma-coherent:
> +    description: Indicates that the PCIe IP block can ensure the coherency
> +
> +required:
> +  - compatible
> +  - reg
> +  - reg-names
> +  - ti,syscon-pcie-ctrl
> +  - max-link-speed
> +  - num-lanes
> +  - power-domains
> +  - clocks
> +  - clock-names
> +  - cdns,max-outbound-regions
> +  - dma-coherent
> +  - max-functions
> +  - phys
> +  - phy-names
> +
> +examples:
> +  - |
> +    #include <dt-bindings/soc/ti,sci_pm_domain.h>
> +
> +     pcie0_ep: pcie-ep@d000000 {
> +            compatible = "ti,j721e-pcie-ep";
> +            reg = <0x00 0x02900000 0x00 0x1000>,
> +                  <0x00 0x02907000 0x00 0x400>,
> +                  <0x00 0x0d000000 0x00 0x00800000>,
> +                  <0x00 0x10000000 0x00 0x08000000>;
> +            reg-names = "intd_cfg", "user_cfg", "reg", "mem";
> +            ti,syscon-pcie-ctrl = <&pcie0_ctrl>;
> +            max-link-speed = <3>;
> +            num-lanes = <2>;
> +            power-domains = <&k3_pds 239 TI_SCI_PD_EXCLUSIVE>;
> +            clocks = <&k3_clks 239 1>;
> +            clock-names = "fck";
> +            cdns,max-outbound-regions = <16>;
> +            max-functions = /bits/ 8 <6>;
> +            dma-coherent;
> +            phys = <&serdes0_pcie_link>;
> +            phy-names = "pcie-phy";
> +    };
> -- 
> 2.17.1
> 

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

* Re: [PATCH v3 11/14] dt-bindings: PCI: Add EP mode dt-bindings for TI's J721E SoC
@ 2020-04-30  2:13     ` Rob Herring
  0 siblings, 0 replies; 46+ messages in thread
From: Rob Herring @ 2020-04-30  2:13 UTC (permalink / raw)
  To: Kishon Vijay Abraham I
  Cc: devicetree, Lorenzo Pieralisi, Arnd Bergmann, Greg Kroah-Hartman,
	linux-kernel, Tom Joseph, linux-pci, Bjorn Helgaas,
	linux-arm-kernel, Andrew Murray

On Fri, Apr 17, 2020 at 06:27:50PM +0530, Kishon Vijay Abraham I wrote:
> Add PCIe EP mode dt-bindings for TI's J721E SoC.
> 
> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
> ---
>  .../bindings/pci/ti,j721e-pci-ep.yaml         | 89 +++++++++++++++++++
>  1 file changed, 89 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml
> 
> diff --git a/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml b/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml
> new file mode 100644
> index 000000000000..cb25c45d5a96
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml
> @@ -0,0 +1,89 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +# Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/
> +%YAML 1.2
> +---
> +$id: "http://devicetree.org/schemas/pci/ti,j721e-pci-ep.yaml#"
> +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
> +
> +title: TI J721E PCI EP (PCIe Wrapper)
> +
> +maintainers:
> +  - Kishon Vijay Abraham I <kishon@ti.com>
> +
> +allOf:
> +  - $ref: "cdns-pcie-ep.yaml#"
> +
> +properties:
> +  compatible:
> +      enum:
> +          - ti,j721e-pcie-ep

Wrong indentation.

Otherwise,

Reviewed-by: Rob Herring <robh@kernel.org>

> +
> +  reg:
> +    maxItems: 4
> +
> +  reg-names:
> +    items:
> +      - const: intd_cfg
> +      - const: user_cfg
> +      - const: reg
> +      - const: mem
> +
> +  ti,syscon-pcie-ctrl:
> +    description: Phandle to the SYSCON entry required for configuring PCIe mode
> +                 and link speed.
> +    allOf:
> +      - $ref: /schemas/types.yaml#/definitions/phandle
> +
> +  power-domains:
> +    maxItems: 1
> +
> +  clocks:
> +    maxItems: 1
> +    description: clock-specifier to represent input to the PCIe
> +
> +  clock-names:
> +    items:
> +      - const: fck
> +
> +  dma-coherent:
> +    description: Indicates that the PCIe IP block can ensure the coherency
> +
> +required:
> +  - compatible
> +  - reg
> +  - reg-names
> +  - ti,syscon-pcie-ctrl
> +  - max-link-speed
> +  - num-lanes
> +  - power-domains
> +  - clocks
> +  - clock-names
> +  - cdns,max-outbound-regions
> +  - dma-coherent
> +  - max-functions
> +  - phys
> +  - phy-names
> +
> +examples:
> +  - |
> +    #include <dt-bindings/soc/ti,sci_pm_domain.h>
> +
> +     pcie0_ep: pcie-ep@d000000 {
> +            compatible = "ti,j721e-pcie-ep";
> +            reg = <0x00 0x02900000 0x00 0x1000>,
> +                  <0x00 0x02907000 0x00 0x400>,
> +                  <0x00 0x0d000000 0x00 0x00800000>,
> +                  <0x00 0x10000000 0x00 0x08000000>;
> +            reg-names = "intd_cfg", "user_cfg", "reg", "mem";
> +            ti,syscon-pcie-ctrl = <&pcie0_ctrl>;
> +            max-link-speed = <3>;
> +            num-lanes = <2>;
> +            power-domains = <&k3_pds 239 TI_SCI_PD_EXCLUSIVE>;
> +            clocks = <&k3_clks 239 1>;
> +            clock-names = "fck";
> +            cdns,max-outbound-regions = <16>;
> +            max-functions = /bits/ 8 <6>;
> +            dma-coherent;
> +            phys = <&serdes0_pcie_link>;
> +            phy-names = "pcie-phy";
> +    };
> -- 
> 2.17.1
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v3 14/14] MAINTAINERS: Add Kishon Vijay Abraham I for TI J721E SoC PCIe
  2020-04-17 15:19     ` Joe Perches
@ 2020-05-06  3:54       ` Kishon Vijay Abraham I
  -1 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-05-06  3:54 UTC (permalink / raw)
  To: Joe Perches, Tom Joseph, Bjorn Helgaas, Rob Herring,
	Lorenzo Pieralisi, Andrew Murray
  Cc: Arnd Bergmann, Greg Kroah-Hartman, linux-arm-kernel, linux-pci,
	devicetree, linux-kernel

Hi Joe,

On 4/17/2020 8:49 PM, Joe Perches wrote:
> On Fri, 2020-04-17 at 18:27 +0530, Kishon Vijay Abraham I wrote:
>> Add Kishon Vijay Abraham I as MAINTAINER for TI J721E SoC PCIe.
> []
>> diff --git a/MAINTAINERS b/MAINTAINERS
> []
>> @@ -12968,13 +12968,15 @@ S:	Maintained
>>  F:	Documentation/devicetree/bindings/pci/designware-pcie.txt
>>  F:	drivers/pci/controller/dwc/*designware*
>>  
>> -PCI DRIVER FOR TI DRA7XX
>> +PCI DRIVER FOR TI DRA7XX/J721E
>>  M:	Kishon Vijay Abraham I <kishon@ti.com>
>>  L:	linux-omap@vger.kernel.org
>>  L:	linux-pci@vger.kernel.org
>> +L:	linux-arm-kernel@lists.infradead.org
>>  S:	Supported
>>  F:	Documentation/devicetree/bindings/pci/ti-pci.txt
>>  F:	drivers/pci/controller/dwc/pci-dra7xx.c
>> +F:	drivers/pci/controller/cadence/pci-j721e.c
> 
> Please keep file patterns in alphabetic order by
> moving this new cadence line up one line above dwc.

Sure, will fix this up in my next revision.

Thanks
Kishon

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

* Re: [PATCH v3 14/14] MAINTAINERS: Add Kishon Vijay Abraham I for TI J721E SoC PCIe
@ 2020-05-06  3:54       ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-05-06  3:54 UTC (permalink / raw)
  To: Joe Perches, Tom Joseph, Bjorn Helgaas, Rob Herring,
	Lorenzo Pieralisi, Andrew Murray
  Cc: devicetree, Arnd Bergmann, Greg Kroah-Hartman, linux-kernel,
	linux-pci, linux-arm-kernel

Hi Joe,

On 4/17/2020 8:49 PM, Joe Perches wrote:
> On Fri, 2020-04-17 at 18:27 +0530, Kishon Vijay Abraham I wrote:
>> Add Kishon Vijay Abraham I as MAINTAINER for TI J721E SoC PCIe.
> []
>> diff --git a/MAINTAINERS b/MAINTAINERS
> []
>> @@ -12968,13 +12968,15 @@ S:	Maintained
>>  F:	Documentation/devicetree/bindings/pci/designware-pcie.txt
>>  F:	drivers/pci/controller/dwc/*designware*
>>  
>> -PCI DRIVER FOR TI DRA7XX
>> +PCI DRIVER FOR TI DRA7XX/J721E
>>  M:	Kishon Vijay Abraham I <kishon@ti.com>
>>  L:	linux-omap@vger.kernel.org
>>  L:	linux-pci@vger.kernel.org
>> +L:	linux-arm-kernel@lists.infradead.org
>>  S:	Supported
>>  F:	Documentation/devicetree/bindings/pci/ti-pci.txt
>>  F:	drivers/pci/controller/dwc/pci-dra7xx.c
>> +F:	drivers/pci/controller/cadence/pci-j721e.c
> 
> Please keep file patterns in alphabetic order by
> moving this new cadence line up one line above dwc.

Sure, will fix this up in my next revision.

Thanks
Kishon

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v3 09/14] PCI: cadence: Add MSI-X support to Endpoint driver
  2020-04-30  1:55     ` Rob Herring
@ 2020-05-06  3:58       ` Kishon Vijay Abraham I
  -1 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-05-06  3:58 UTC (permalink / raw)
  To: Rob Herring
  Cc: Tom Joseph, Bjorn Helgaas, Lorenzo Pieralisi, Andrew Murray,
	Arnd Bergmann, Greg Kroah-Hartman, linux-arm-kernel, linux-pci,
	devicetree, linux-kernel

Hi Rob,

On 4/30/2020 7:25 AM, Rob Herring wrote:
> On Fri, Apr 17, 2020 at 06:27:48PM +0530, Kishon Vijay Abraham I wrote:
>> From: Alan Douglas <adouglas@cadence.com>
>>
>> Implement ->set_msix() and ->get_msix() callback functions in order
>> to configure MSIX capability in the PCIe endpoint controller.
>>
>> Add cdns_pcie_ep_send_msix_irq() to send MSIX interrupts to Host.
>> cdns_pcie_ep_send_msix_irq() gets the MSIX table address (virtual
>> address) from "struct cdns_pcie_epf" that gets initialized in
>> ->set_bar() call back function.
>>
>> [kishon@ti.com: Re-implement MSIX support in accordance with the
>>  re-designed core MSI-X interfaces]
>> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
>> Signed-off-by: Alan Douglas <adouglas@cadence.com>
> 
> Your Sob should be last.

Will fix this!

Thanks
Kishon
> 
>> ---
>>  .../pci/controller/cadence/pcie-cadence-ep.c  | 112 +++++++++++++++++-
>>  drivers/pci/controller/cadence/pcie-cadence.h |  10 ++
>>  2 files changed, 121 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c
>> index 14021d760482..c43340ca0630 100644
>> --- a/drivers/pci/controller/cadence/pcie-cadence-ep.c
>> +++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c
>> @@ -51,6 +51,7 @@ static int cdns_pcie_ep_set_bar(struct pci_epc *epc, u8 fn,
>>  				struct pci_epf_bar *epf_bar)
>>  {
>>  	struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
>> +	struct cdns_pcie_epf *epf = &ep->epf[fn];
>>  	struct cdns_pcie *pcie = &ep->pcie;
>>  	dma_addr_t bar_phys = epf_bar->phys_addr;
>>  	enum pci_barno bar = epf_bar->barno;
>> @@ -111,6 +112,8 @@ static int cdns_pcie_ep_set_bar(struct pci_epc *epc, u8 fn,
>>  		CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl));
>>  	cdns_pcie_writel(pcie, reg, cfg);
>>  
>> +	epf->epf_bar[bar] = epf_bar;
>> +
>>  	return 0;
>>  }
>>  
>> @@ -118,6 +121,7 @@ static void cdns_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn,
>>  				   struct pci_epf_bar *epf_bar)
>>  {
>>  	struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
>> +	struct cdns_pcie_epf *epf = &ep->epf[fn];
>>  	struct cdns_pcie *pcie = &ep->pcie;
>>  	enum pci_barno bar = epf_bar->barno;
>>  	u32 reg, cfg, b, ctrl;
>> @@ -139,6 +143,8 @@ static void cdns_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn,
>>  
>>  	cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar), 0);
>>  	cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar), 0);
>> +
>> +	epf->epf_bar[bar] = NULL;
>>  }
>>  
>>  static int cdns_pcie_ep_map_addr(struct pci_epc *epc, u8 fn, phys_addr_t addr,
>> @@ -224,6 +230,50 @@ static int cdns_pcie_ep_get_msi(struct pci_epc *epc, u8 fn)
>>  	return mme;
>>  }
>>  
>> +static int cdns_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no)
>> +{
>> +	struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
>> +	struct cdns_pcie *pcie = &ep->pcie;
>> +	u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
>> +	u32 val, reg;
>> +
>> +	reg = cap + PCI_MSIX_FLAGS;
>> +	val = cdns_pcie_ep_fn_readw(pcie, func_no, reg);
>> +	if (!(val & PCI_MSIX_FLAGS_ENABLE))
>> +		return -EINVAL;
>> +
>> +	val &= PCI_MSIX_FLAGS_QSIZE;
>> +
>> +	return val;
>> +}
>> +
>> +static int cdns_pcie_ep_set_msix(struct pci_epc *epc, u8 fn, u16 interrupts,
>> +				 enum pci_barno bir, u32 offset)
>> +{
>> +	struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
>> +	struct cdns_pcie *pcie = &ep->pcie;
>> +	u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
>> +	u32 val, reg;
>> +
>> +	reg = cap + PCI_MSIX_FLAGS;
>> +	val = cdns_pcie_ep_fn_readw(pcie, fn, reg);
>> +	val &= ~PCI_MSIX_FLAGS_QSIZE;
>> +	val |= interrupts;
>> +	cdns_pcie_ep_fn_writew(pcie, fn, reg, val);
>> +
>> +	/* Set MSIX BAR and offset */
>> +	reg = cap + PCI_MSIX_TABLE;
>> +	val = offset | bir;
>> +	cdns_pcie_ep_fn_writel(pcie, fn, reg, val);
>> +
>> +	/* Set PBA BAR and offset.  BAR must match MSIX BAR */
>> +	reg = cap + PCI_MSIX_PBA;
>> +	val = (offset + (interrupts * PCI_MSIX_ENTRY_SIZE)) | bir;
>> +	cdns_pcie_ep_fn_writel(pcie, fn, reg, val);
>> +
>> +	return 0;
>> +}
>> +
>>  static void cdns_pcie_ep_assert_intx(struct cdns_pcie_ep *ep, u8 fn,
>>  				     u8 intx, bool is_asserted)
>>  {
>> @@ -330,6 +380,56 @@ static int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn,
>>  	return 0;
>>  }
>>  
>> +static int cdns_pcie_ep_send_msix_irq(struct cdns_pcie_ep *ep, u8 fn,
>> +				      u16 interrupt_num)
>> +{
>> +	u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
>> +	u32 tbl_offset, msg_data, reg, vec_ctrl;
>> +	struct cdns_pcie *pcie = &ep->pcie;
>> +	struct pci_epf_msix_tbl *msix_tbl;
>> +	struct pci_epf_bar *epf_bar;
>> +	struct cdns_pcie_epf *epf;
>> +	u64 pci_addr_mask = 0xff;
>> +	u64 msg_addr;
>> +	u16 flags;
>> +	u8 bir;
>> +
>> +	/* Check whether the MSI-X feature has been enabled by the PCI host. */
>> +	flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSIX_FLAGS);
>> +	if (!(flags & PCI_MSIX_FLAGS_ENABLE))
>> +		return -EINVAL;
>> +
>> +	reg = cap + PCI_MSIX_TABLE;
>> +	tbl_offset = cdns_pcie_ep_fn_readl(pcie, fn, reg);
>> +	bir = tbl_offset & PCI_MSIX_TABLE_BIR;
>> +	tbl_offset &= PCI_MSIX_TABLE_OFFSET;
>> +
>> +	epf = &ep->epf[fn];
>> +	epf_bar = epf->epf_bar[bir];
>> +	msix_tbl = epf_bar->addr;
>> +	msix_tbl = (struct pci_epf_msix_tbl *)((char *)msix_tbl + tbl_offset);
>> +
>> +	msg_addr = msix_tbl[(interrupt_num - 1)].msg_addr;
>> +	msg_data = msix_tbl[(interrupt_num - 1)].msg_data;
>> +	vec_ctrl = msix_tbl[(interrupt_num - 1)].vector_ctrl;
>> +
>> +	/* Set the outbound region if needed. */
>> +	if (ep->irq_pci_addr != (msg_addr & ~pci_addr_mask) ||
>> +	    ep->irq_pci_fn != fn) {
>> +		/* First region was reserved for IRQ writes. */
>> +		cdns_pcie_set_outbound_region(pcie, fn, 0,
>> +					      false,
>> +					      ep->irq_phys_addr,
>> +					      msg_addr & ~pci_addr_mask,
>> +					      pci_addr_mask + 1);
>> +		ep->irq_pci_addr = (msg_addr & ~pci_addr_mask);
>> +		ep->irq_pci_fn = fn;
>> +	}
>> +	writel(msg_data, ep->irq_cpu_addr + (msg_addr & pci_addr_mask));
>> +
>> +	return 0;
>> +}
>> +
>>  static int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn,
>>  				  enum pci_epc_irq_type type,
>>  				  u16 interrupt_num)
>> @@ -343,6 +443,9 @@ static int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn,
>>  	case PCI_EPC_IRQ_MSI:
>>  		return cdns_pcie_ep_send_msi_irq(ep, fn, interrupt_num);
>>  
>> +	case PCI_EPC_IRQ_MSIX:
>> +		return cdns_pcie_ep_send_msix_irq(ep, fn, interrupt_num);
>> +
>>  	default:
>>  		break;
>>  	}
>> @@ -380,7 +483,7 @@ static int cdns_pcie_ep_start(struct pci_epc *epc)
>>  static const struct pci_epc_features cdns_pcie_epc_features = {
>>  	.linkup_notifier = false,
>>  	.msi_capable = true,
>> -	.msix_capable = false,
>> +	.msix_capable = true,
>>  };
>>  
>>  static const struct pci_epc_features*
>> @@ -397,6 +500,8 @@ static const struct pci_epc_ops cdns_pcie_epc_ops = {
>>  	.unmap_addr	= cdns_pcie_ep_unmap_addr,
>>  	.set_msi	= cdns_pcie_ep_set_msi,
>>  	.get_msi	= cdns_pcie_ep_get_msi,
>> +	.set_msix	= cdns_pcie_ep_set_msix,
>> +	.get_msix	= cdns_pcie_ep_get_msix,
>>  	.raise_irq	= cdns_pcie_ep_raise_irq,
>>  	.start		= cdns_pcie_ep_start,
>>  	.get_features	= cdns_pcie_ep_get_features,
>> @@ -455,6 +560,11 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
>>  	if (of_property_read_u8(np, "max-functions", &epc->max_functions) < 0)
>>  		epc->max_functions = 1;
>>  
>> +	ep->epf = devm_kcalloc(dev, epc->max_functions, sizeof(*ep->epf),
>> +			       GFP_KERNEL);
>> +	if (!ep->epf)
>> +		return -ENOMEM;
>> +
>>  	ret = pci_epc_mem_init(epc, pcie->mem_res->start,
>>  			       resource_size(pcie->mem_res));
>>  	if (ret < 0) {
>> diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
>> index 16a6b0ee547c..ea850290a602 100644
>> --- a/drivers/pci/controller/cadence/pcie-cadence.h
>> +++ b/drivers/pci/controller/cadence/pcie-cadence.h
>> @@ -99,6 +99,7 @@
>>  #define CDNS_PCIE_EP_FUNC_BASE(fn)	(((fn) << 12) & GENMASK(19, 12))
>>  
>>  #define CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET	0x90
>> +#define CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET	0xb0
>>  
>>  /*
>>   * Root Port Registers (PCI configuration space for the root port function)
>> @@ -280,6 +281,14 @@ struct cdns_pcie_rc {
>>  	u32			device_id;
>>  };
>>  
>> +/**
>> + * struct cdns_pcie_epf - Structure to hold info about endpoint function
>> + * @epf_bar: reference to the pci_epf_bar for the six Base Address Registers
>> + */
>> +struct cdns_pcie_epf {
>> +	struct pci_epf_bar *epf_bar[PCI_STD_NUM_BARS];
>> +};
>> +
>>  /**
>>   * struct cdns_pcie_ep - private data for this PCIe endpoint controller driver
>>   * @pcie: Cadence PCIe controller
>> @@ -307,6 +316,7 @@ struct cdns_pcie_ep {
>>  	u64			irq_pci_addr;
>>  	u8			irq_pci_fn;
>>  	u8			irq_pending;
>> +	struct cdns_pcie_epf	*epf;
>>  };
>>  
>>  
>> -- 
>> 2.17.1
>>

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

* Re: [PATCH v3 09/14] PCI: cadence: Add MSI-X support to Endpoint driver
@ 2020-05-06  3:58       ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-05-06  3:58 UTC (permalink / raw)
  To: Rob Herring
  Cc: devicetree, Lorenzo Pieralisi, Arnd Bergmann, Greg Kroah-Hartman,
	linux-kernel, Tom Joseph, linux-pci, Bjorn Helgaas,
	linux-arm-kernel, Andrew Murray

Hi Rob,

On 4/30/2020 7:25 AM, Rob Herring wrote:
> On Fri, Apr 17, 2020 at 06:27:48PM +0530, Kishon Vijay Abraham I wrote:
>> From: Alan Douglas <adouglas@cadence.com>
>>
>> Implement ->set_msix() and ->get_msix() callback functions in order
>> to configure MSIX capability in the PCIe endpoint controller.
>>
>> Add cdns_pcie_ep_send_msix_irq() to send MSIX interrupts to Host.
>> cdns_pcie_ep_send_msix_irq() gets the MSIX table address (virtual
>> address) from "struct cdns_pcie_epf" that gets initialized in
>> ->set_bar() call back function.
>>
>> [kishon@ti.com: Re-implement MSIX support in accordance with the
>>  re-designed core MSI-X interfaces]
>> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
>> Signed-off-by: Alan Douglas <adouglas@cadence.com>
> 
> Your Sob should be last.

Will fix this!

Thanks
Kishon
> 
>> ---
>>  .../pci/controller/cadence/pcie-cadence-ep.c  | 112 +++++++++++++++++-
>>  drivers/pci/controller/cadence/pcie-cadence.h |  10 ++
>>  2 files changed, 121 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c
>> index 14021d760482..c43340ca0630 100644
>> --- a/drivers/pci/controller/cadence/pcie-cadence-ep.c
>> +++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c
>> @@ -51,6 +51,7 @@ static int cdns_pcie_ep_set_bar(struct pci_epc *epc, u8 fn,
>>  				struct pci_epf_bar *epf_bar)
>>  {
>>  	struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
>> +	struct cdns_pcie_epf *epf = &ep->epf[fn];
>>  	struct cdns_pcie *pcie = &ep->pcie;
>>  	dma_addr_t bar_phys = epf_bar->phys_addr;
>>  	enum pci_barno bar = epf_bar->barno;
>> @@ -111,6 +112,8 @@ static int cdns_pcie_ep_set_bar(struct pci_epc *epc, u8 fn,
>>  		CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl));
>>  	cdns_pcie_writel(pcie, reg, cfg);
>>  
>> +	epf->epf_bar[bar] = epf_bar;
>> +
>>  	return 0;
>>  }
>>  
>> @@ -118,6 +121,7 @@ static void cdns_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn,
>>  				   struct pci_epf_bar *epf_bar)
>>  {
>>  	struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
>> +	struct cdns_pcie_epf *epf = &ep->epf[fn];
>>  	struct cdns_pcie *pcie = &ep->pcie;
>>  	enum pci_barno bar = epf_bar->barno;
>>  	u32 reg, cfg, b, ctrl;
>> @@ -139,6 +143,8 @@ static void cdns_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn,
>>  
>>  	cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar), 0);
>>  	cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar), 0);
>> +
>> +	epf->epf_bar[bar] = NULL;
>>  }
>>  
>>  static int cdns_pcie_ep_map_addr(struct pci_epc *epc, u8 fn, phys_addr_t addr,
>> @@ -224,6 +230,50 @@ static int cdns_pcie_ep_get_msi(struct pci_epc *epc, u8 fn)
>>  	return mme;
>>  }
>>  
>> +static int cdns_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no)
>> +{
>> +	struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
>> +	struct cdns_pcie *pcie = &ep->pcie;
>> +	u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
>> +	u32 val, reg;
>> +
>> +	reg = cap + PCI_MSIX_FLAGS;
>> +	val = cdns_pcie_ep_fn_readw(pcie, func_no, reg);
>> +	if (!(val & PCI_MSIX_FLAGS_ENABLE))
>> +		return -EINVAL;
>> +
>> +	val &= PCI_MSIX_FLAGS_QSIZE;
>> +
>> +	return val;
>> +}
>> +
>> +static int cdns_pcie_ep_set_msix(struct pci_epc *epc, u8 fn, u16 interrupts,
>> +				 enum pci_barno bir, u32 offset)
>> +{
>> +	struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
>> +	struct cdns_pcie *pcie = &ep->pcie;
>> +	u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
>> +	u32 val, reg;
>> +
>> +	reg = cap + PCI_MSIX_FLAGS;
>> +	val = cdns_pcie_ep_fn_readw(pcie, fn, reg);
>> +	val &= ~PCI_MSIX_FLAGS_QSIZE;
>> +	val |= interrupts;
>> +	cdns_pcie_ep_fn_writew(pcie, fn, reg, val);
>> +
>> +	/* Set MSIX BAR and offset */
>> +	reg = cap + PCI_MSIX_TABLE;
>> +	val = offset | bir;
>> +	cdns_pcie_ep_fn_writel(pcie, fn, reg, val);
>> +
>> +	/* Set PBA BAR and offset.  BAR must match MSIX BAR */
>> +	reg = cap + PCI_MSIX_PBA;
>> +	val = (offset + (interrupts * PCI_MSIX_ENTRY_SIZE)) | bir;
>> +	cdns_pcie_ep_fn_writel(pcie, fn, reg, val);
>> +
>> +	return 0;
>> +}
>> +
>>  static void cdns_pcie_ep_assert_intx(struct cdns_pcie_ep *ep, u8 fn,
>>  				     u8 intx, bool is_asserted)
>>  {
>> @@ -330,6 +380,56 @@ static int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn,
>>  	return 0;
>>  }
>>  
>> +static int cdns_pcie_ep_send_msix_irq(struct cdns_pcie_ep *ep, u8 fn,
>> +				      u16 interrupt_num)
>> +{
>> +	u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
>> +	u32 tbl_offset, msg_data, reg, vec_ctrl;
>> +	struct cdns_pcie *pcie = &ep->pcie;
>> +	struct pci_epf_msix_tbl *msix_tbl;
>> +	struct pci_epf_bar *epf_bar;
>> +	struct cdns_pcie_epf *epf;
>> +	u64 pci_addr_mask = 0xff;
>> +	u64 msg_addr;
>> +	u16 flags;
>> +	u8 bir;
>> +
>> +	/* Check whether the MSI-X feature has been enabled by the PCI host. */
>> +	flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSIX_FLAGS);
>> +	if (!(flags & PCI_MSIX_FLAGS_ENABLE))
>> +		return -EINVAL;
>> +
>> +	reg = cap + PCI_MSIX_TABLE;
>> +	tbl_offset = cdns_pcie_ep_fn_readl(pcie, fn, reg);
>> +	bir = tbl_offset & PCI_MSIX_TABLE_BIR;
>> +	tbl_offset &= PCI_MSIX_TABLE_OFFSET;
>> +
>> +	epf = &ep->epf[fn];
>> +	epf_bar = epf->epf_bar[bir];
>> +	msix_tbl = epf_bar->addr;
>> +	msix_tbl = (struct pci_epf_msix_tbl *)((char *)msix_tbl + tbl_offset);
>> +
>> +	msg_addr = msix_tbl[(interrupt_num - 1)].msg_addr;
>> +	msg_data = msix_tbl[(interrupt_num - 1)].msg_data;
>> +	vec_ctrl = msix_tbl[(interrupt_num - 1)].vector_ctrl;
>> +
>> +	/* Set the outbound region if needed. */
>> +	if (ep->irq_pci_addr != (msg_addr & ~pci_addr_mask) ||
>> +	    ep->irq_pci_fn != fn) {
>> +		/* First region was reserved for IRQ writes. */
>> +		cdns_pcie_set_outbound_region(pcie, fn, 0,
>> +					      false,
>> +					      ep->irq_phys_addr,
>> +					      msg_addr & ~pci_addr_mask,
>> +					      pci_addr_mask + 1);
>> +		ep->irq_pci_addr = (msg_addr & ~pci_addr_mask);
>> +		ep->irq_pci_fn = fn;
>> +	}
>> +	writel(msg_data, ep->irq_cpu_addr + (msg_addr & pci_addr_mask));
>> +
>> +	return 0;
>> +}
>> +
>>  static int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn,
>>  				  enum pci_epc_irq_type type,
>>  				  u16 interrupt_num)
>> @@ -343,6 +443,9 @@ static int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn,
>>  	case PCI_EPC_IRQ_MSI:
>>  		return cdns_pcie_ep_send_msi_irq(ep, fn, interrupt_num);
>>  
>> +	case PCI_EPC_IRQ_MSIX:
>> +		return cdns_pcie_ep_send_msix_irq(ep, fn, interrupt_num);
>> +
>>  	default:
>>  		break;
>>  	}
>> @@ -380,7 +483,7 @@ static int cdns_pcie_ep_start(struct pci_epc *epc)
>>  static const struct pci_epc_features cdns_pcie_epc_features = {
>>  	.linkup_notifier = false,
>>  	.msi_capable = true,
>> -	.msix_capable = false,
>> +	.msix_capable = true,
>>  };
>>  
>>  static const struct pci_epc_features*
>> @@ -397,6 +500,8 @@ static const struct pci_epc_ops cdns_pcie_epc_ops = {
>>  	.unmap_addr	= cdns_pcie_ep_unmap_addr,
>>  	.set_msi	= cdns_pcie_ep_set_msi,
>>  	.get_msi	= cdns_pcie_ep_get_msi,
>> +	.set_msix	= cdns_pcie_ep_set_msix,
>> +	.get_msix	= cdns_pcie_ep_get_msix,
>>  	.raise_irq	= cdns_pcie_ep_raise_irq,
>>  	.start		= cdns_pcie_ep_start,
>>  	.get_features	= cdns_pcie_ep_get_features,
>> @@ -455,6 +560,11 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
>>  	if (of_property_read_u8(np, "max-functions", &epc->max_functions) < 0)
>>  		epc->max_functions = 1;
>>  
>> +	ep->epf = devm_kcalloc(dev, epc->max_functions, sizeof(*ep->epf),
>> +			       GFP_KERNEL);
>> +	if (!ep->epf)
>> +		return -ENOMEM;
>> +
>>  	ret = pci_epc_mem_init(epc, pcie->mem_res->start,
>>  			       resource_size(pcie->mem_res));
>>  	if (ret < 0) {
>> diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
>> index 16a6b0ee547c..ea850290a602 100644
>> --- a/drivers/pci/controller/cadence/pcie-cadence.h
>> +++ b/drivers/pci/controller/cadence/pcie-cadence.h
>> @@ -99,6 +99,7 @@
>>  #define CDNS_PCIE_EP_FUNC_BASE(fn)	(((fn) << 12) & GENMASK(19, 12))
>>  
>>  #define CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET	0x90
>> +#define CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET	0xb0
>>  
>>  /*
>>   * Root Port Registers (PCI configuration space for the root port function)
>> @@ -280,6 +281,14 @@ struct cdns_pcie_rc {
>>  	u32			device_id;
>>  };
>>  
>> +/**
>> + * struct cdns_pcie_epf - Structure to hold info about endpoint function
>> + * @epf_bar: reference to the pci_epf_bar for the six Base Address Registers
>> + */
>> +struct cdns_pcie_epf {
>> +	struct pci_epf_bar *epf_bar[PCI_STD_NUM_BARS];
>> +};
>> +
>>  /**
>>   * struct cdns_pcie_ep - private data for this PCIe endpoint controller driver
>>   * @pcie: Cadence PCIe controller
>> @@ -307,6 +316,7 @@ struct cdns_pcie_ep {
>>  	u64			irq_pci_addr;
>>  	u8			irq_pci_fn;
>>  	u8			irq_pending;
>> +	struct cdns_pcie_epf	*epf;
>>  };
>>  
>>  
>> -- 
>> 2.17.1
>>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v3 12/14] PCI: j721e: Add TI J721E PCIe driver
  2020-04-30  2:11     ` Rob Herring
@ 2020-05-06  4:18       ` Kishon Vijay Abraham I
  -1 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-05-06  4:18 UTC (permalink / raw)
  To: Rob Herring
  Cc: Tom Joseph, Bjorn Helgaas, Lorenzo Pieralisi, Andrew Murray,
	Arnd Bergmann, Greg Kroah-Hartman, linux-arm-kernel, linux-pci,
	devicetree, linux-kernel

Hi Rob,

On 4/30/2020 7:41 AM, Rob Herring wrote:
> On Fri, Apr 17, 2020 at 06:27:51PM +0530, Kishon Vijay Abraham I wrote:
>> Add support for PCIe controller in J721E SoC. The controller uses the
>> Cadence PCIe core programmed by pcie-cadence*.c. The PCIe controller
>> will work in both host mode and device mode.
>> Some of the features of the controller are:
>>   *) Supports both RC mode and EP mode
>>   *) Supports MSI and MSI-X support
>>   *) Supports upto GEN3 speed mode
>>   *) Supports SR-IOV capability
>>   *) Ability to route all transactions via SMMU (support will be added
>>      in a later patch).
>>
>> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
>> ---
>>  drivers/pci/controller/cadence/Kconfig        |  23 +
>>  drivers/pci/controller/cadence/Makefile       |   1 +
>>  drivers/pci/controller/cadence/pci-j721e.c    | 500 ++++++++++++++++++
>>  .../controller/cadence/pcie-cadence-host.c    |   4 +-
>>  drivers/pci/controller/cadence/pcie-cadence.h |   8 +
>>  5 files changed, 534 insertions(+), 2 deletions(-)
>>  create mode 100644 drivers/pci/controller/cadence/pci-j721e.c
>>
>> diff --git a/drivers/pci/controller/cadence/Kconfig b/drivers/pci/controller/cadence/Kconfig
>> index b76b3cf55ce5..5d30564190e1 100644
>> --- a/drivers/pci/controller/cadence/Kconfig
>> +++ b/drivers/pci/controller/cadence/Kconfig
>> @@ -42,4 +42,27 @@ config PCIE_CADENCE_PLAT_EP
>>  	  endpoint mode. This PCIe controller may be embedded into many
>>  	  different vendors SoCs.
>>  
>> +config PCI_J721E
>> +	bool
>> +
>> +config PCI_J721E_HOST
>> +	bool "TI J721E PCIe platform host controller"
>> +	depends on OF
>> +	select PCIE_CADENCE_HOST
>> +	select PCI_J721E
>> +	help
>> +	  Say Y here if you want to support the TI J721E PCIe platform
>> +	  controller in host mode. TI J721E PCIe controller uses Cadence PCIe
>> +	  core.
>> +
>> +config PCI_J721E_EP
>> +	bool "TI J721E PCIe platform endpoint controller"
>> +	depends on OF
>> +	depends on PCI_ENDPOINT
>> +	select PCIE_CADENCE_EP
>> +	select PCI_J721E
>> +	help
>> +	  Say Y here if you want to support the TI J721E PCIe platform
>> +	  controller in endpoint mode. TI J721E PCIe controller uses Cadence PCIe
>> +	  core.
>>  endmenu
>> diff --git a/drivers/pci/controller/cadence/Makefile b/drivers/pci/controller/cadence/Makefile
>> index 232a3f20876a..9bac5fb2f13d 100644
>> --- a/drivers/pci/controller/cadence/Makefile
>> +++ b/drivers/pci/controller/cadence/Makefile
>> @@ -3,3 +3,4 @@ obj-$(CONFIG_PCIE_CADENCE) += pcie-cadence.o
>>  obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o
>>  obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep.o
>>  obj-$(CONFIG_PCIE_CADENCE_PLAT) += pcie-cadence-plat.o
>> +obj-$(CONFIG_PCI_J721E) += pci-j721e.o
>> diff --git a/drivers/pci/controller/cadence/pci-j721e.c b/drivers/pci/controller/cadence/pci-j721e.c
>> new file mode 100644
>> index 000000000000..eee619c6ffae
>> --- /dev/null
>> +++ b/drivers/pci/controller/cadence/pci-j721e.c
>> @@ -0,0 +1,500 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/**
>> + * pci-j721e - PCIe controller driver for TI's J721E SoCs
>> + *
>> + * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com
>> + * Author: Kishon Vijay Abraham I <kishon@ti.com>
>> + */
>> +
>> +#include <linux/delay.h>
>> +#include <linux/gpio/consumer.h>
>> +#include <linux/io.h>
>> +#include <linux/irqchip/chained_irq.h>
>> +#include <linux/irqdomain.h>
>> +#include <linux/mfd/syscon.h>
>> +#include <linux/of_device.h>
>> +#include <linux/of_irq.h>
>> +#include <linux/pci.h>
>> +#include <linux/pm_runtime.h>
>> +#include <linux/regmap.h>
>> +
>> +#include "../../pci.h"
>> +#include "pcie-cadence.h"
>> +
>> +#define ENABLE_REG_SYS_2	0x108
>> +#define STATUS_REG_SYS_2	0x508
>> +#define STATUS_CLR_REG_SYS_2	0x708
>> +#define LINK_DOWN		BIT(1)
>> +
>> +#define J721E_PCIE_USER_CMD_STATUS	0x4
>> +#define LINK_TRAINING_ENABLE		BIT(0)
>> +
>> +#define J721E_PCIE_USER_LINKSTATUS	0x14
>> +#define LINK_STATUS			GENMASK(1, 0)
>> +
>> +enum link_status {
>> +	NO_RECEIVERS_DETECTED,
>> +	LINK_TRAINING_IN_PROGRESS,
>> +	LINK_UP_DL_IN_PROGRESS,
>> +	LINK_UP_DL_COMPLETED,
>> +};
>> +
>> +#define J721E_MODE_RC			BIT(7)
>> +#define LANE_COUNT_MASK			BIT(8)
>> +#define LANE_COUNT(n)			((n) << 8)
>> +
>> +#define GENERATION_SEL_MASK		GENMASK(1, 0)
>> +
>> +#define MAX_LANES			2
>> +
>> +struct j721e_pcie {
>> +	struct device		*dev;
>> +	struct device_node	*node;
>> +	u32			mode;
>> +	u32			num_lanes;
>> +	struct cdns_pcie	*cdns_pcie;
>> +	void __iomem		*user_cfg_base;
>> +	void __iomem		*intd_cfg_base;
>> +};
>> +
>> +enum j721e_pcie_mode {
>> +	PCI_MODE_RC,
>> +	PCI_MODE_EP,
>> +};
>> +
>> +struct j721e_pcie_data {
>> +	enum j721e_pcie_mode	mode;
>> +};
>> +
>> +static inline u32 j721e_pcie_user_readl(struct j721e_pcie *pcie, u32 offset)
>> +{
>> +	return readl(pcie->user_cfg_base + offset);
>> +}
>> +
>> +static inline void j721e_pcie_user_writel(struct j721e_pcie *pcie, u32 offset,
>> +					  u32 value)
>> +{
>> +	writel(value, pcie->user_cfg_base + offset);
>> +}
>> +
>> +static inline u32 j721e_pcie_intd_readl(struct j721e_pcie *pcie, u32 offset)
>> +{
>> +	return readl(pcie->intd_cfg_base + offset);
>> +}
>> +
>> +static inline void j721e_pcie_intd_writel(struct j721e_pcie *pcie, u32 offset,
>> +					  u32 value)
>> +{
>> +	writel(value, pcie->intd_cfg_base + offset);
>> +}
>> +
>> +static irqreturn_t j721e_pcie_link_irq_handler(int irq, void *priv)
>> +{
>> +	struct j721e_pcie *pcie = priv;
>> +	struct device *dev = pcie->dev;
>> +	u32 reg;
>> +
>> +	reg = j721e_pcie_intd_readl(pcie, STATUS_REG_SYS_2);
>> +	if (!(reg & LINK_DOWN))
>> +		return IRQ_NONE;
>> +
>> +	dev_err(dev, "LINK DOWN!\n");
>> +
>> +	j721e_pcie_intd_writel(pcie, STATUS_CLR_REG_SYS_2, LINK_DOWN);
>> +	return IRQ_HANDLED;
>> +}
>> +
>> +static void j721e_pcie_config_link_irq(struct j721e_pcie *pcie)
>> +{
>> +	u32 reg;
>> +
>> +	reg = j721e_pcie_intd_readl(pcie, ENABLE_REG_SYS_2);
>> +	reg |= LINK_DOWN;
>> +	j721e_pcie_intd_writel(pcie, ENABLE_REG_SYS_2, reg);
>> +}
>> +
>> +static int j721e_pcie_start_link(struct cdns_pcie *cdns_pcie)
>> +{
>> +	struct j721e_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
>> +	u32 reg;
>> +
>> +	reg = j721e_pcie_user_readl(pcie, J721E_PCIE_USER_CMD_STATUS);
>> +	reg |= LINK_TRAINING_ENABLE;
>> +	j721e_pcie_user_writel(pcie, J721E_PCIE_USER_CMD_STATUS, reg);
>> +
>> +	return 0;
>> +}
>> +
>> +static void j721e_pcie_stop_link(struct cdns_pcie *cdns_pcie)
>> +{
>> +	struct j721e_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
>> +	u32 reg;
>> +
>> +	reg = j721e_pcie_user_readl(pcie, J721E_PCIE_USER_CMD_STATUS);
>> +	reg &= ~LINK_TRAINING_ENABLE;
>> +	j721e_pcie_user_writel(pcie, J721E_PCIE_USER_CMD_STATUS, reg);
>> +}
>> +
>> +static bool j721e_pcie_link_up(struct cdns_pcie *cdns_pcie)
>> +{
>> +	struct j721e_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
>> +	u32 reg;
>> +
>> +	reg = j721e_pcie_user_readl(pcie, J721E_PCIE_USER_LINKSTATUS);
>> +	reg &= LINK_STATUS;
>> +	if (reg == LINK_UP_DL_COMPLETED)
>> +		return true;
>> +
>> +	return false;
>> +}
>> +
>> +static const struct cdns_pcie_ops j721e_ops_ops = {
>> +	.read = cdns_platform_pcie_read32,
>> +	.write = cdns_platform_pcie_write32,
>> +	.start_link = j721e_pcie_start_link,
>> +	.stop_link = j721e_pcie_stop_link,
>> +	.link_up = j721e_pcie_link_up,
>> +};
>> +
>> +static int j721e_pcie_set_mode(struct j721e_pcie *pcie, struct regmap *syscon)
>> +{
>> +	struct device *dev = pcie->dev;
>> +	u32 mask = J721E_MODE_RC;
>> +	u32 mode = pcie->mode;
>> +	u32 val = 0;
>> +	int ret = 0;
>> +
>> +	if (mode == PCI_MODE_RC)
>> +		val = J721E_MODE_RC;
>> +
>> +	ret = regmap_update_bits(syscon, 0, mask, val);
>> +	if (ret)
>> +		dev_err(dev, "failed to set pcie mode\n");
>> +
>> +	return ret;
>> +}
>> +
>> +static int j721e_pcie_set_link_speed(struct j721e_pcie *pcie,
>> +				     struct regmap *syscon)
>> +{
>> +	struct device *dev = pcie->dev;
>> +	struct device_node *np = dev->of_node;
>> +	int link_speed;
>> +	u32 val = 0;
>> +	int ret;
>> +
>> +	link_speed = of_pci_get_max_link_speed(np);
>> +	if (link_speed < 2)
>> +		link_speed = 2;
>> +
>> +	val = link_speed - 1;
>> +	ret = regmap_update_bits(syscon, 0, GENERATION_SEL_MASK, val);
>> +	if (ret)
>> +		dev_err(dev, "failed to set link speed\n");
>> +
>> +	return ret;
>> +}
>> +
>> +static int j721e_pcie_set_lane_count(struct j721e_pcie *pcie,
>> +				     struct regmap *syscon)
>> +{
>> +	struct device *dev = pcie->dev;
>> +	u32 lanes = pcie->num_lanes;
>> +	u32 val = 0;
>> +	int ret;
>> +
>> +	val = LANE_COUNT(lanes - 1);
>> +	ret = regmap_update_bits(syscon, 0, LANE_COUNT_MASK, val);
>> +	if (ret)
>> +		dev_err(dev, "failed to set link count\n");
>> +
>> +	return ret;
>> +}
>> +
>> +static int j721e_pcie_ctrl_init(struct j721e_pcie *pcie)
>> +{
>> +	struct device *dev = pcie->dev;
>> +	struct device_node *node = dev->of_node;
>> +	struct regmap *syscon;
>> +	int ret;
>> +
>> +	syscon = syscon_regmap_lookup_by_phandle(node, "ti,syscon-pcie-ctrl");
>> +	if (IS_ERR(syscon)) {
>> +		dev_err(dev, "Unable to get ti,syscon-pcie-ctrl regmap\n");
>> +		return PTR_ERR(syscon);
>> +	}
>> +
>> +	ret = j721e_pcie_set_mode(pcie, syscon);
>> +	if (ret < 0) {
>> +		dev_err(dev, "Failed to set pci mode\n");
>> +		return ret;
>> +	}
>> +
>> +	ret = j721e_pcie_set_link_speed(pcie, syscon);
>> +	if (ret < 0) {
>> +		dev_err(dev, "Failed to set link speed\n");
>> +		return ret;
>> +	}
>> +
>> +	ret = j721e_pcie_set_lane_count(pcie, syscon);
>> +	if (ret < 0) {
>> +		dev_err(dev, "Failed to set num-lanes\n");
>> +		return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int cdns_ti_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
>> +				    int where, int size, u32 *value)
>> +{
>> +	struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
>> +	struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge);
>> +	unsigned int busn = bus->number;
>> +
>> +	if (busn == rc->bus_range->start)
>> +		return pci_generic_config_read32(bus, devfn, where, size,
>> +						 value);
>> +
>> +	return pci_generic_config_read(bus, devfn, where, size, value);
>> +}
>> +
>> +static int cdns_ti_pcie_config_write(struct pci_bus *bus, unsigned int devfn,
>> +				     int where, int size, u32 value)
>> +{
>> +	struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
>> +	struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge);
>> +	unsigned int busn = bus->number;
>> +
>> +	if (busn == rc->bus_range->start)
>> +		return pci_generic_config_write32(bus, devfn, where, size,
>> +						  value);
>> +
>> +	return pci_generic_config_write(bus, devfn, where, size, value);
>> +}
>> +
>> +static struct pci_ops cdns_ti_pcie_host_ops = {
>> +	.map_bus	= cdns_pci_map_bus,
>> +	.read		= cdns_ti_pcie_config_read,
>> +	.write		= cdns_ti_pcie_config_write,
>> +};
>> +
>> +static const struct j721e_pcie_data j721e_pcie_rc_data = {
>> +	.mode = PCI_MODE_RC,
>> +};
>> +
>> +static const struct j721e_pcie_data j721e_pcie_ep_data = {
>> +	.mode = PCI_MODE_EP,
>> +};
>> +
>> +static const struct of_device_id of_j721e_pcie_match[] = {
>> +	{
>> +		.compatible = "ti,j721e-pcie-host",
>> +		.data = &j721e_pcie_rc_data,
>> +	},
>> +	{
>> +		.compatible = "ti,j721e-pcie-ep",
>> +		.data = &j721e_pcie_ep_data,
>> +	},
>> +	{},
>> +};
>> +
>> +static int j721e_pcie_probe(struct platform_device *pdev)
>> +{
>> +	struct device *dev = &pdev->dev;
>> +	struct device_node *node = dev->of_node;
>> +	const struct of_device_id *match;
>> +	struct pci_host_bridge *bridge;
>> +	struct j721e_pcie_data *data;
>> +	struct cdns_pcie *cdns_pcie;
>> +	struct j721e_pcie *pcie;
>> +	struct cdns_pcie_rc *rc;
>> +	struct cdns_pcie_ep *ep;
>> +	struct gpio_desc *gpiod;
>> +	struct resource *res;
>> +	void __iomem *base;
>> +	u32 num_lanes;
>> +	u32 mode;
>> +	int ret;
>> +	int irq;
>> +
>> +	match = of_match_device(of_match_ptr(of_j721e_pcie_match), dev);
>> +	if (!match)
>> +		return -EINVAL;
>> +
>> +	data = (struct j721e_pcie_data *)match->data;
> 
> Use of_device_get_match_data()
> 
>> +	mode = (u32)data->mode;
>> +
>> +	pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
>> +	if (!pcie)
>> +		return -ENOMEM;
>> +
>> +	pcie->dev = dev;
>> +	pcie->node = node;
> 
> The dev has the node, why do you need it twice?
> 
>> +	pcie->mode = mode;
>> +
>> +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intd_cfg");
>> +	base = devm_ioremap_resource(dev, res);
> 
> devm_platform_ioremap_resource_byname()
> 
>> +	if (IS_ERR(base))
>> +		return PTR_ERR(base);
>> +	pcie->intd_cfg_base = base;
>> +
>> +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "user_cfg");
>> +	base = devm_ioremap_resource(dev, res);
> 
> devm_platform_ioremap_resource_byname
> 
>> +	if (IS_ERR(base))
>> +		return PTR_ERR(base);
>> +	pcie->user_cfg_base = base;
>> +
>> +	ret = of_property_read_u32(node, "num-lanes", &num_lanes);
>> +	if (ret || num_lanes > MAX_LANES)
>> +		num_lanes = 1;
>> +	pcie->num_lanes = num_lanes;
>> +
>> +	irq = platform_get_irq_byname(pdev, "link_state");
>> +	if (irq < 0)
>> +		return irq;
>> +
>> +	dev_set_drvdata(dev, pcie);
>> +	pm_runtime_enable(dev);
>> +	ret = pm_runtime_get_sync(dev);
>> +	if (ret < 0) {
>> +		dev_err(dev, "pm_runtime_get_sync failed\n");
>> +		goto err_get_sync;
>> +	}
>> +
>> +	ret = j721e_pcie_ctrl_init(pcie);
>> +	if (ret < 0) {
>> +		dev_err(dev, "pm_runtime_get_sync failed\n");
>> +		goto err_get_sync;
>> +	}
>> +
>> +	ret = devm_request_irq(dev, irq, j721e_pcie_link_irq_handler,
>> +			       IRQF_SHARED, "j721e-pcie-link_state-irq", pcie);
> 
> Really shared?
> 
>> +	if (ret < 0) {
>> +		dev_err(dev, "failed to request link state IRQ %d\n", irq);
>> +		goto err_get_sync;
>> +	}
>> +
>> +	j721e_pcie_config_link_irq(pcie);
>> +
>> +	switch (mode) {
>> +	case PCI_MODE_RC:
>> +		if (!IS_ENABLED(CONFIG_PCIE_CADENCE_HOST)) {
>> +			ret = -ENODEV;
>> +			goto err_get_sync;
>> +		}
>> +
>> +		bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
>> +		if (!bridge) {
>> +			ret = -ENOMEM;
>> +			goto err_get_sync;
>> +		}
>> +
>> +		bridge->ops = &cdns_ti_pcie_host_ops;
>> +		rc = pci_host_bridge_priv(bridge);
>> +
>> +		cdns_pcie = &rc->pcie;
>> +		cdns_pcie->dev = dev;
>> +		cdns_pcie->ops = &j721e_ops_ops;
>> +		pcie->cdns_pcie = cdns_pcie;
>> +
>> +		gpiod = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
>> +		if (IS_ERR(gpiod)) {
>> +			ret = PTR_ERR(gpiod);
>> +			if (ret != -EPROBE_DEFER)
>> +				dev_err(dev, "Failed to get reset GPIO\n");
>> +			goto err_get_sync;
>> +		}
>> +
>> +		ret = cdns_pcie_init_phy(dev, cdns_pcie);
>> +		if (ret) {
>> +			dev_err(dev, "Failed to init phy\n");
>> +			goto err_get_sync;
>> +		}
>> +
>> +		/*
>> +		 * "Power Sequencing and Reset Signal Timings" table in
>> +		 * PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 3.0
>> +		 * indicates PERST# should be deasserted after minimum of 100us
>> +		 * once REFCLK is stable. The REFCLK to the connector in RC
>> +		 * mode is selected while enabling the PHY. So deassert PERST#
>> +		 * after 100 us.
>> +		 */
>> +		if (gpiod) {
>> +			usleep_range(100, 200);
>> +			gpiod_set_value_cansleep(gpiod, 1);
>> +		}
>> +
>> +		ret = cdns_pcie_host_setup(rc);
>> +		if (ret < 0)
>> +			goto err_pcie_setup;
>> +
>> +		break;
>> +	case PCI_MODE_EP:
>> +		if (!IS_ENABLED(CONFIG_PCIE_CADENCE_EP)) {
>> +			ret = -ENODEV;
>> +			goto err_get_sync;
>> +		}
>> +
>> +		ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
>> +		if (!ep) {
>> +			ret = -ENOMEM;
>> +			goto err_get_sync;
>> +		}
>> +
>> +		cdns_pcie = &ep->pcie;
>> +		cdns_pcie->dev = dev;
>> +		cdns_pcie->ops = &j721e_ops_ops;
>> +		pcie->cdns_pcie = cdns_pcie;
>> +
>> +		ret = cdns_pcie_init_phy(dev, cdns_pcie);
>> +		if (ret) {
>> +			dev_err(dev, "Failed to init phy\n");
>> +			goto err_get_sync;
>> +		}
>> +
>> +		ret = cdns_pcie_ep_setup(ep);
>> +		if (ret < 0)
>> +			goto err_pcie_setup;
>> +
>> +		break;
>> +	default:
>> +		dev_err(dev, "INVALID device type %d\n", mode);
>> +	}
>> +
>> +	return 0;
>> +
>> +err_pcie_setup:
>> +	cdns_pcie_disable_phy(cdns_pcie);
>> +
>> +err_get_sync:
>> +	pm_runtime_put(dev);
>> +	pm_runtime_disable(dev);
>> +
>> +	return ret;
>> +}
>> +
>> +static int j721e_pcie_remove(struct platform_device *pdev)
>> +{
>> +	struct j721e_pcie *pcie = platform_get_drvdata(pdev);
>> +	struct cdns_pcie *cdns_pcie = pcie->cdns_pcie;
>> +	struct device *dev = &pdev->dev;
>> +
>> +	cdns_pcie_disable_phy(cdns_pcie);
>> +	pm_runtime_put(dev);
>> +	pm_runtime_disable(dev);
>> +	of_platform_depopulate(dev);
> 
> I don't see a populate. Is this supposed to be here?

Missed to remove this from the previous version which had a populate. Will
remove this and fix the rest of your comments in the next revision.

Thanks
Kishon

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

* Re: [PATCH v3 12/14] PCI: j721e: Add TI J721E PCIe driver
@ 2020-05-06  4:18       ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 46+ messages in thread
From: Kishon Vijay Abraham I @ 2020-05-06  4:18 UTC (permalink / raw)
  To: Rob Herring
  Cc: devicetree, Lorenzo Pieralisi, Arnd Bergmann, Greg Kroah-Hartman,
	linux-kernel, Tom Joseph, linux-pci, Bjorn Helgaas,
	linux-arm-kernel, Andrew Murray

Hi Rob,

On 4/30/2020 7:41 AM, Rob Herring wrote:
> On Fri, Apr 17, 2020 at 06:27:51PM +0530, Kishon Vijay Abraham I wrote:
>> Add support for PCIe controller in J721E SoC. The controller uses the
>> Cadence PCIe core programmed by pcie-cadence*.c. The PCIe controller
>> will work in both host mode and device mode.
>> Some of the features of the controller are:
>>   *) Supports both RC mode and EP mode
>>   *) Supports MSI and MSI-X support
>>   *) Supports upto GEN3 speed mode
>>   *) Supports SR-IOV capability
>>   *) Ability to route all transactions via SMMU (support will be added
>>      in a later patch).
>>
>> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
>> ---
>>  drivers/pci/controller/cadence/Kconfig        |  23 +
>>  drivers/pci/controller/cadence/Makefile       |   1 +
>>  drivers/pci/controller/cadence/pci-j721e.c    | 500 ++++++++++++++++++
>>  .../controller/cadence/pcie-cadence-host.c    |   4 +-
>>  drivers/pci/controller/cadence/pcie-cadence.h |   8 +
>>  5 files changed, 534 insertions(+), 2 deletions(-)
>>  create mode 100644 drivers/pci/controller/cadence/pci-j721e.c
>>
>> diff --git a/drivers/pci/controller/cadence/Kconfig b/drivers/pci/controller/cadence/Kconfig
>> index b76b3cf55ce5..5d30564190e1 100644
>> --- a/drivers/pci/controller/cadence/Kconfig
>> +++ b/drivers/pci/controller/cadence/Kconfig
>> @@ -42,4 +42,27 @@ config PCIE_CADENCE_PLAT_EP
>>  	  endpoint mode. This PCIe controller may be embedded into many
>>  	  different vendors SoCs.
>>  
>> +config PCI_J721E
>> +	bool
>> +
>> +config PCI_J721E_HOST
>> +	bool "TI J721E PCIe platform host controller"
>> +	depends on OF
>> +	select PCIE_CADENCE_HOST
>> +	select PCI_J721E
>> +	help
>> +	  Say Y here if you want to support the TI J721E PCIe platform
>> +	  controller in host mode. TI J721E PCIe controller uses Cadence PCIe
>> +	  core.
>> +
>> +config PCI_J721E_EP
>> +	bool "TI J721E PCIe platform endpoint controller"
>> +	depends on OF
>> +	depends on PCI_ENDPOINT
>> +	select PCIE_CADENCE_EP
>> +	select PCI_J721E
>> +	help
>> +	  Say Y here if you want to support the TI J721E PCIe platform
>> +	  controller in endpoint mode. TI J721E PCIe controller uses Cadence PCIe
>> +	  core.
>>  endmenu
>> diff --git a/drivers/pci/controller/cadence/Makefile b/drivers/pci/controller/cadence/Makefile
>> index 232a3f20876a..9bac5fb2f13d 100644
>> --- a/drivers/pci/controller/cadence/Makefile
>> +++ b/drivers/pci/controller/cadence/Makefile
>> @@ -3,3 +3,4 @@ obj-$(CONFIG_PCIE_CADENCE) += pcie-cadence.o
>>  obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o
>>  obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep.o
>>  obj-$(CONFIG_PCIE_CADENCE_PLAT) += pcie-cadence-plat.o
>> +obj-$(CONFIG_PCI_J721E) += pci-j721e.o
>> diff --git a/drivers/pci/controller/cadence/pci-j721e.c b/drivers/pci/controller/cadence/pci-j721e.c
>> new file mode 100644
>> index 000000000000..eee619c6ffae
>> --- /dev/null
>> +++ b/drivers/pci/controller/cadence/pci-j721e.c
>> @@ -0,0 +1,500 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/**
>> + * pci-j721e - PCIe controller driver for TI's J721E SoCs
>> + *
>> + * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com
>> + * Author: Kishon Vijay Abraham I <kishon@ti.com>
>> + */
>> +
>> +#include <linux/delay.h>
>> +#include <linux/gpio/consumer.h>
>> +#include <linux/io.h>
>> +#include <linux/irqchip/chained_irq.h>
>> +#include <linux/irqdomain.h>
>> +#include <linux/mfd/syscon.h>
>> +#include <linux/of_device.h>
>> +#include <linux/of_irq.h>
>> +#include <linux/pci.h>
>> +#include <linux/pm_runtime.h>
>> +#include <linux/regmap.h>
>> +
>> +#include "../../pci.h"
>> +#include "pcie-cadence.h"
>> +
>> +#define ENABLE_REG_SYS_2	0x108
>> +#define STATUS_REG_SYS_2	0x508
>> +#define STATUS_CLR_REG_SYS_2	0x708
>> +#define LINK_DOWN		BIT(1)
>> +
>> +#define J721E_PCIE_USER_CMD_STATUS	0x4
>> +#define LINK_TRAINING_ENABLE		BIT(0)
>> +
>> +#define J721E_PCIE_USER_LINKSTATUS	0x14
>> +#define LINK_STATUS			GENMASK(1, 0)
>> +
>> +enum link_status {
>> +	NO_RECEIVERS_DETECTED,
>> +	LINK_TRAINING_IN_PROGRESS,
>> +	LINK_UP_DL_IN_PROGRESS,
>> +	LINK_UP_DL_COMPLETED,
>> +};
>> +
>> +#define J721E_MODE_RC			BIT(7)
>> +#define LANE_COUNT_MASK			BIT(8)
>> +#define LANE_COUNT(n)			((n) << 8)
>> +
>> +#define GENERATION_SEL_MASK		GENMASK(1, 0)
>> +
>> +#define MAX_LANES			2
>> +
>> +struct j721e_pcie {
>> +	struct device		*dev;
>> +	struct device_node	*node;
>> +	u32			mode;
>> +	u32			num_lanes;
>> +	struct cdns_pcie	*cdns_pcie;
>> +	void __iomem		*user_cfg_base;
>> +	void __iomem		*intd_cfg_base;
>> +};
>> +
>> +enum j721e_pcie_mode {
>> +	PCI_MODE_RC,
>> +	PCI_MODE_EP,
>> +};
>> +
>> +struct j721e_pcie_data {
>> +	enum j721e_pcie_mode	mode;
>> +};
>> +
>> +static inline u32 j721e_pcie_user_readl(struct j721e_pcie *pcie, u32 offset)
>> +{
>> +	return readl(pcie->user_cfg_base + offset);
>> +}
>> +
>> +static inline void j721e_pcie_user_writel(struct j721e_pcie *pcie, u32 offset,
>> +					  u32 value)
>> +{
>> +	writel(value, pcie->user_cfg_base + offset);
>> +}
>> +
>> +static inline u32 j721e_pcie_intd_readl(struct j721e_pcie *pcie, u32 offset)
>> +{
>> +	return readl(pcie->intd_cfg_base + offset);
>> +}
>> +
>> +static inline void j721e_pcie_intd_writel(struct j721e_pcie *pcie, u32 offset,
>> +					  u32 value)
>> +{
>> +	writel(value, pcie->intd_cfg_base + offset);
>> +}
>> +
>> +static irqreturn_t j721e_pcie_link_irq_handler(int irq, void *priv)
>> +{
>> +	struct j721e_pcie *pcie = priv;
>> +	struct device *dev = pcie->dev;
>> +	u32 reg;
>> +
>> +	reg = j721e_pcie_intd_readl(pcie, STATUS_REG_SYS_2);
>> +	if (!(reg & LINK_DOWN))
>> +		return IRQ_NONE;
>> +
>> +	dev_err(dev, "LINK DOWN!\n");
>> +
>> +	j721e_pcie_intd_writel(pcie, STATUS_CLR_REG_SYS_2, LINK_DOWN);
>> +	return IRQ_HANDLED;
>> +}
>> +
>> +static void j721e_pcie_config_link_irq(struct j721e_pcie *pcie)
>> +{
>> +	u32 reg;
>> +
>> +	reg = j721e_pcie_intd_readl(pcie, ENABLE_REG_SYS_2);
>> +	reg |= LINK_DOWN;
>> +	j721e_pcie_intd_writel(pcie, ENABLE_REG_SYS_2, reg);
>> +}
>> +
>> +static int j721e_pcie_start_link(struct cdns_pcie *cdns_pcie)
>> +{
>> +	struct j721e_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
>> +	u32 reg;
>> +
>> +	reg = j721e_pcie_user_readl(pcie, J721E_PCIE_USER_CMD_STATUS);
>> +	reg |= LINK_TRAINING_ENABLE;
>> +	j721e_pcie_user_writel(pcie, J721E_PCIE_USER_CMD_STATUS, reg);
>> +
>> +	return 0;
>> +}
>> +
>> +static void j721e_pcie_stop_link(struct cdns_pcie *cdns_pcie)
>> +{
>> +	struct j721e_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
>> +	u32 reg;
>> +
>> +	reg = j721e_pcie_user_readl(pcie, J721E_PCIE_USER_CMD_STATUS);
>> +	reg &= ~LINK_TRAINING_ENABLE;
>> +	j721e_pcie_user_writel(pcie, J721E_PCIE_USER_CMD_STATUS, reg);
>> +}
>> +
>> +static bool j721e_pcie_link_up(struct cdns_pcie *cdns_pcie)
>> +{
>> +	struct j721e_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
>> +	u32 reg;
>> +
>> +	reg = j721e_pcie_user_readl(pcie, J721E_PCIE_USER_LINKSTATUS);
>> +	reg &= LINK_STATUS;
>> +	if (reg == LINK_UP_DL_COMPLETED)
>> +		return true;
>> +
>> +	return false;
>> +}
>> +
>> +static const struct cdns_pcie_ops j721e_ops_ops = {
>> +	.read = cdns_platform_pcie_read32,
>> +	.write = cdns_platform_pcie_write32,
>> +	.start_link = j721e_pcie_start_link,
>> +	.stop_link = j721e_pcie_stop_link,
>> +	.link_up = j721e_pcie_link_up,
>> +};
>> +
>> +static int j721e_pcie_set_mode(struct j721e_pcie *pcie, struct regmap *syscon)
>> +{
>> +	struct device *dev = pcie->dev;
>> +	u32 mask = J721E_MODE_RC;
>> +	u32 mode = pcie->mode;
>> +	u32 val = 0;
>> +	int ret = 0;
>> +
>> +	if (mode == PCI_MODE_RC)
>> +		val = J721E_MODE_RC;
>> +
>> +	ret = regmap_update_bits(syscon, 0, mask, val);
>> +	if (ret)
>> +		dev_err(dev, "failed to set pcie mode\n");
>> +
>> +	return ret;
>> +}
>> +
>> +static int j721e_pcie_set_link_speed(struct j721e_pcie *pcie,
>> +				     struct regmap *syscon)
>> +{
>> +	struct device *dev = pcie->dev;
>> +	struct device_node *np = dev->of_node;
>> +	int link_speed;
>> +	u32 val = 0;
>> +	int ret;
>> +
>> +	link_speed = of_pci_get_max_link_speed(np);
>> +	if (link_speed < 2)
>> +		link_speed = 2;
>> +
>> +	val = link_speed - 1;
>> +	ret = regmap_update_bits(syscon, 0, GENERATION_SEL_MASK, val);
>> +	if (ret)
>> +		dev_err(dev, "failed to set link speed\n");
>> +
>> +	return ret;
>> +}
>> +
>> +static int j721e_pcie_set_lane_count(struct j721e_pcie *pcie,
>> +				     struct regmap *syscon)
>> +{
>> +	struct device *dev = pcie->dev;
>> +	u32 lanes = pcie->num_lanes;
>> +	u32 val = 0;
>> +	int ret;
>> +
>> +	val = LANE_COUNT(lanes - 1);
>> +	ret = regmap_update_bits(syscon, 0, LANE_COUNT_MASK, val);
>> +	if (ret)
>> +		dev_err(dev, "failed to set link count\n");
>> +
>> +	return ret;
>> +}
>> +
>> +static int j721e_pcie_ctrl_init(struct j721e_pcie *pcie)
>> +{
>> +	struct device *dev = pcie->dev;
>> +	struct device_node *node = dev->of_node;
>> +	struct regmap *syscon;
>> +	int ret;
>> +
>> +	syscon = syscon_regmap_lookup_by_phandle(node, "ti,syscon-pcie-ctrl");
>> +	if (IS_ERR(syscon)) {
>> +		dev_err(dev, "Unable to get ti,syscon-pcie-ctrl regmap\n");
>> +		return PTR_ERR(syscon);
>> +	}
>> +
>> +	ret = j721e_pcie_set_mode(pcie, syscon);
>> +	if (ret < 0) {
>> +		dev_err(dev, "Failed to set pci mode\n");
>> +		return ret;
>> +	}
>> +
>> +	ret = j721e_pcie_set_link_speed(pcie, syscon);
>> +	if (ret < 0) {
>> +		dev_err(dev, "Failed to set link speed\n");
>> +		return ret;
>> +	}
>> +
>> +	ret = j721e_pcie_set_lane_count(pcie, syscon);
>> +	if (ret < 0) {
>> +		dev_err(dev, "Failed to set num-lanes\n");
>> +		return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int cdns_ti_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
>> +				    int where, int size, u32 *value)
>> +{
>> +	struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
>> +	struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge);
>> +	unsigned int busn = bus->number;
>> +
>> +	if (busn == rc->bus_range->start)
>> +		return pci_generic_config_read32(bus, devfn, where, size,
>> +						 value);
>> +
>> +	return pci_generic_config_read(bus, devfn, where, size, value);
>> +}
>> +
>> +static int cdns_ti_pcie_config_write(struct pci_bus *bus, unsigned int devfn,
>> +				     int where, int size, u32 value)
>> +{
>> +	struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
>> +	struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge);
>> +	unsigned int busn = bus->number;
>> +
>> +	if (busn == rc->bus_range->start)
>> +		return pci_generic_config_write32(bus, devfn, where, size,
>> +						  value);
>> +
>> +	return pci_generic_config_write(bus, devfn, where, size, value);
>> +}
>> +
>> +static struct pci_ops cdns_ti_pcie_host_ops = {
>> +	.map_bus	= cdns_pci_map_bus,
>> +	.read		= cdns_ti_pcie_config_read,
>> +	.write		= cdns_ti_pcie_config_write,
>> +};
>> +
>> +static const struct j721e_pcie_data j721e_pcie_rc_data = {
>> +	.mode = PCI_MODE_RC,
>> +};
>> +
>> +static const struct j721e_pcie_data j721e_pcie_ep_data = {
>> +	.mode = PCI_MODE_EP,
>> +};
>> +
>> +static const struct of_device_id of_j721e_pcie_match[] = {
>> +	{
>> +		.compatible = "ti,j721e-pcie-host",
>> +		.data = &j721e_pcie_rc_data,
>> +	},
>> +	{
>> +		.compatible = "ti,j721e-pcie-ep",
>> +		.data = &j721e_pcie_ep_data,
>> +	},
>> +	{},
>> +};
>> +
>> +static int j721e_pcie_probe(struct platform_device *pdev)
>> +{
>> +	struct device *dev = &pdev->dev;
>> +	struct device_node *node = dev->of_node;
>> +	const struct of_device_id *match;
>> +	struct pci_host_bridge *bridge;
>> +	struct j721e_pcie_data *data;
>> +	struct cdns_pcie *cdns_pcie;
>> +	struct j721e_pcie *pcie;
>> +	struct cdns_pcie_rc *rc;
>> +	struct cdns_pcie_ep *ep;
>> +	struct gpio_desc *gpiod;
>> +	struct resource *res;
>> +	void __iomem *base;
>> +	u32 num_lanes;
>> +	u32 mode;
>> +	int ret;
>> +	int irq;
>> +
>> +	match = of_match_device(of_match_ptr(of_j721e_pcie_match), dev);
>> +	if (!match)
>> +		return -EINVAL;
>> +
>> +	data = (struct j721e_pcie_data *)match->data;
> 
> Use of_device_get_match_data()
> 
>> +	mode = (u32)data->mode;
>> +
>> +	pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
>> +	if (!pcie)
>> +		return -ENOMEM;
>> +
>> +	pcie->dev = dev;
>> +	pcie->node = node;
> 
> The dev has the node, why do you need it twice?
> 
>> +	pcie->mode = mode;
>> +
>> +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intd_cfg");
>> +	base = devm_ioremap_resource(dev, res);
> 
> devm_platform_ioremap_resource_byname()
> 
>> +	if (IS_ERR(base))
>> +		return PTR_ERR(base);
>> +	pcie->intd_cfg_base = base;
>> +
>> +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "user_cfg");
>> +	base = devm_ioremap_resource(dev, res);
> 
> devm_platform_ioremap_resource_byname
> 
>> +	if (IS_ERR(base))
>> +		return PTR_ERR(base);
>> +	pcie->user_cfg_base = base;
>> +
>> +	ret = of_property_read_u32(node, "num-lanes", &num_lanes);
>> +	if (ret || num_lanes > MAX_LANES)
>> +		num_lanes = 1;
>> +	pcie->num_lanes = num_lanes;
>> +
>> +	irq = platform_get_irq_byname(pdev, "link_state");
>> +	if (irq < 0)
>> +		return irq;
>> +
>> +	dev_set_drvdata(dev, pcie);
>> +	pm_runtime_enable(dev);
>> +	ret = pm_runtime_get_sync(dev);
>> +	if (ret < 0) {
>> +		dev_err(dev, "pm_runtime_get_sync failed\n");
>> +		goto err_get_sync;
>> +	}
>> +
>> +	ret = j721e_pcie_ctrl_init(pcie);
>> +	if (ret < 0) {
>> +		dev_err(dev, "pm_runtime_get_sync failed\n");
>> +		goto err_get_sync;
>> +	}
>> +
>> +	ret = devm_request_irq(dev, irq, j721e_pcie_link_irq_handler,
>> +			       IRQF_SHARED, "j721e-pcie-link_state-irq", pcie);
> 
> Really shared?
> 
>> +	if (ret < 0) {
>> +		dev_err(dev, "failed to request link state IRQ %d\n", irq);
>> +		goto err_get_sync;
>> +	}
>> +
>> +	j721e_pcie_config_link_irq(pcie);
>> +
>> +	switch (mode) {
>> +	case PCI_MODE_RC:
>> +		if (!IS_ENABLED(CONFIG_PCIE_CADENCE_HOST)) {
>> +			ret = -ENODEV;
>> +			goto err_get_sync;
>> +		}
>> +
>> +		bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
>> +		if (!bridge) {
>> +			ret = -ENOMEM;
>> +			goto err_get_sync;
>> +		}
>> +
>> +		bridge->ops = &cdns_ti_pcie_host_ops;
>> +		rc = pci_host_bridge_priv(bridge);
>> +
>> +		cdns_pcie = &rc->pcie;
>> +		cdns_pcie->dev = dev;
>> +		cdns_pcie->ops = &j721e_ops_ops;
>> +		pcie->cdns_pcie = cdns_pcie;
>> +
>> +		gpiod = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
>> +		if (IS_ERR(gpiod)) {
>> +			ret = PTR_ERR(gpiod);
>> +			if (ret != -EPROBE_DEFER)
>> +				dev_err(dev, "Failed to get reset GPIO\n");
>> +			goto err_get_sync;
>> +		}
>> +
>> +		ret = cdns_pcie_init_phy(dev, cdns_pcie);
>> +		if (ret) {
>> +			dev_err(dev, "Failed to init phy\n");
>> +			goto err_get_sync;
>> +		}
>> +
>> +		/*
>> +		 * "Power Sequencing and Reset Signal Timings" table in
>> +		 * PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 3.0
>> +		 * indicates PERST# should be deasserted after minimum of 100us
>> +		 * once REFCLK is stable. The REFCLK to the connector in RC
>> +		 * mode is selected while enabling the PHY. So deassert PERST#
>> +		 * after 100 us.
>> +		 */
>> +		if (gpiod) {
>> +			usleep_range(100, 200);
>> +			gpiod_set_value_cansleep(gpiod, 1);
>> +		}
>> +
>> +		ret = cdns_pcie_host_setup(rc);
>> +		if (ret < 0)
>> +			goto err_pcie_setup;
>> +
>> +		break;
>> +	case PCI_MODE_EP:
>> +		if (!IS_ENABLED(CONFIG_PCIE_CADENCE_EP)) {
>> +			ret = -ENODEV;
>> +			goto err_get_sync;
>> +		}
>> +
>> +		ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
>> +		if (!ep) {
>> +			ret = -ENOMEM;
>> +			goto err_get_sync;
>> +		}
>> +
>> +		cdns_pcie = &ep->pcie;
>> +		cdns_pcie->dev = dev;
>> +		cdns_pcie->ops = &j721e_ops_ops;
>> +		pcie->cdns_pcie = cdns_pcie;
>> +
>> +		ret = cdns_pcie_init_phy(dev, cdns_pcie);
>> +		if (ret) {
>> +			dev_err(dev, "Failed to init phy\n");
>> +			goto err_get_sync;
>> +		}
>> +
>> +		ret = cdns_pcie_ep_setup(ep);
>> +		if (ret < 0)
>> +			goto err_pcie_setup;
>> +
>> +		break;
>> +	default:
>> +		dev_err(dev, "INVALID device type %d\n", mode);
>> +	}
>> +
>> +	return 0;
>> +
>> +err_pcie_setup:
>> +	cdns_pcie_disable_phy(cdns_pcie);
>> +
>> +err_get_sync:
>> +	pm_runtime_put(dev);
>> +	pm_runtime_disable(dev);
>> +
>> +	return ret;
>> +}
>> +
>> +static int j721e_pcie_remove(struct platform_device *pdev)
>> +{
>> +	struct j721e_pcie *pcie = platform_get_drvdata(pdev);
>> +	struct cdns_pcie *cdns_pcie = pcie->cdns_pcie;
>> +	struct device *dev = &pdev->dev;
>> +
>> +	cdns_pcie_disable_phy(cdns_pcie);
>> +	pm_runtime_put(dev);
>> +	pm_runtime_disable(dev);
>> +	of_platform_depopulate(dev);
> 
> I don't see a populate. Is this supposed to be here?

Missed to remove this from the previous version which had a populate. Will
remove this and fix the rest of your comments in the next revision.

Thanks
Kishon

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

end of thread, other threads:[~2020-05-06  4:19 UTC | newest]

Thread overview: 46+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-04-17 12:57 [PATCH v3 00/14] Add PCIe support to TI's J721E SoC Kishon Vijay Abraham I
2020-04-17 12:57 ` Kishon Vijay Abraham I
2020-04-17 12:57 ` [PATCH v3 01/14] PCI: cadence: Fix cdns_pcie_{host|ep}_setup() error path Kishon Vijay Abraham I
2020-04-17 12:57   ` Kishon Vijay Abraham I
2020-04-17 12:57 ` [PATCH v3 02/14] linux/kernel.h: Add PTR_ALIGN_DOWN macro Kishon Vijay Abraham I
2020-04-17 12:57   ` Kishon Vijay Abraham I
2020-04-17 12:57 ` [PATCH v3 03/14] PCI: cadence: Add support to use custom read and write accessors Kishon Vijay Abraham I
2020-04-17 12:57   ` Kishon Vijay Abraham I
2020-04-17 12:57 ` [PATCH v3 04/14] PCI: cadence: Add support to start link and verify link status Kishon Vijay Abraham I
2020-04-17 12:57   ` Kishon Vijay Abraham I
2020-04-17 12:57 ` [PATCH v3 05/14] PCI: cadence: Add read/write accessors to perform only 32-bit accesses Kishon Vijay Abraham I
2020-04-17 12:57   ` Kishon Vijay Abraham I
2020-04-17 12:57 ` [PATCH v3 06/14] PCI: cadence: Allow pci_host_bridge to have custom pci_ops Kishon Vijay Abraham I
2020-04-17 12:57   ` Kishon Vijay Abraham I
2020-04-17 12:57 ` [PATCH v3 07/14] PCI: cadence: Add new *ops* for CPU addr fixup Kishon Vijay Abraham I
2020-04-17 12:57   ` Kishon Vijay Abraham I
2020-04-17 12:57 ` [PATCH v3 08/14] PCI: cadence: Fix updating Vendor ID and Subsystem Vendor ID register Kishon Vijay Abraham I
2020-04-17 12:57   ` Kishon Vijay Abraham I
2020-04-17 12:57 ` [PATCH v3 09/14] PCI: cadence: Add MSI-X support to Endpoint driver Kishon Vijay Abraham I
2020-04-17 12:57   ` Kishon Vijay Abraham I
2020-04-30  1:55   ` Rob Herring
2020-04-30  1:55     ` Rob Herring
2020-05-06  3:58     ` Kishon Vijay Abraham I
2020-05-06  3:58       ` Kishon Vijay Abraham I
2020-04-17 12:57 ` [PATCH v3 10/14] dt-bindings: PCI: Add host mode dt-bindings for TI's J721E SoC Kishon Vijay Abraham I
2020-04-17 12:57   ` Kishon Vijay Abraham I
2020-04-30  2:11   ` Rob Herring
2020-04-30  2:11     ` Rob Herring
2020-04-17 12:57 ` [PATCH v3 11/14] dt-bindings: PCI: Add EP " Kishon Vijay Abraham I
2020-04-17 12:57   ` Kishon Vijay Abraham I
2020-04-30  2:13   ` Rob Herring
2020-04-30  2:13     ` Rob Herring
2020-04-17 12:57 ` [PATCH v3 12/14] PCI: j721e: Add TI J721E PCIe driver Kishon Vijay Abraham I
2020-04-17 12:57   ` Kishon Vijay Abraham I
2020-04-30  2:11   ` Rob Herring
2020-04-30  2:11     ` Rob Herring
2020-05-06  4:18     ` Kishon Vijay Abraham I
2020-05-06  4:18       ` Kishon Vijay Abraham I
2020-04-17 12:57 ` [PATCH v3 13/14] misc: pci_endpoint_test: Add J721E in pci_device_id table Kishon Vijay Abraham I
2020-04-17 12:57   ` Kishon Vijay Abraham I
2020-04-17 12:57 ` [PATCH v3 14/14] MAINTAINERS: Add Kishon Vijay Abraham I for TI J721E SoC PCIe Kishon Vijay Abraham I
2020-04-17 12:57   ` Kishon Vijay Abraham I
2020-04-17 15:19   ` Joe Perches
2020-04-17 15:19     ` Joe Perches
2020-05-06  3:54     ` Kishon Vijay Abraham I
2020-05-06  3:54       ` Kishon Vijay Abraham I

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.