Add Cadence PCIe endpoint driver supporting configuration
of header, bars and MSI for device.
Signed-off-by: Ramon Fried
---
.../pci_endpoint/cdns,cdns-pcie-ep.txt| 18 +
drivers/pci_endpoint/Kconfig | 8 +
drivers/pci_endpoint/Makefile | 1 +
drivers/pci_endpoint/pcie-cadence-ep.c| 177 ++
drivers/pci_endpoint/pcie-cadence.h | 309 ++
5 files changed, 513 insertions(+)
create mode 100644 doc/device-tree-bindings/pci_endpoint/cdns,cdns-pcie-ep.txt
create mode 100644 drivers/pci_endpoint/pcie-cadence-ep.c
create mode 100644 drivers/pci_endpoint/pcie-cadence.h
diff --git a/doc/device-tree-bindings/pci_endpoint/cdns,cdns-pcie-ep.txt
b/doc/device-tree-bindings/pci_endpoint/cdns,cdns-pcie-ep.txt
new file mode 100644
index 00..7705430559
--- /dev/null
+++ b/doc/device-tree-bindings/pci_endpoint/cdns,cdns-pcie-ep.txt
@@ -0,0 +1,18 @@
+* Cadence PCIe endpoint controller
+
+Required properties:
+- compatible: Should contain "cdns,cdns-pcie-ep" to identify the IP used.
+- reg: Should contain the controller register base address.
+
+Optional properties:
+- max-functions: Maximum number of functions that can be configured (default
1).
+- cdns,max-outbound-regions: Set to maximum number of outbound regions
(default 8)
+
+Example:
+
+pcie_ep@fc00 {
+ compatible = "cdns,cdns-pcie-ep";
+ reg = <0x0 0xfc00 0x0 0x0100>;
+ cdns,max-outbound-regions = <16>;
+ max-functions = /bits/ 8 <8>;
+};
diff --git a/drivers/pci_endpoint/Kconfig b/drivers/pci_endpoint/Kconfig
index ac4f43d1ab..c54bd2a9ac 100644
--- a/drivers/pci_endpoint/Kconfig
+++ b/drivers/pci_endpoint/Kconfig
@@ -14,4 +14,12 @@ config PCI_ENDPOINT
controllers that can operate in endpoint mode (as a device
connected to PCI host or bridge).
+config PCIE_CADENCE_EP
+ bool "Cadence PCIe endpoint controller"
+ depends on PCI_ENDPOINT
+ help
+ Say Y here if you want to support the Cadence PCIe controller in
+ endpoint mode. This PCIe controller may be embedded into many
+ different vendors SoCs.
+
endmenu
diff --git a/drivers/pci_endpoint/Makefile b/drivers/pci_endpoint/Makefile
index 80a1066925..0a849deb19 100644
--- a/drivers/pci_endpoint/Makefile
+++ b/drivers/pci_endpoint/Makefile
@@ -4,3 +4,4 @@
# Ramon Fried
obj-y += pci_ep-uclass.o
+obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep.o
diff --git a/drivers/pci_endpoint/pcie-cadence-ep.c
b/drivers/pci_endpoint/pcie-cadence-ep.c
new file mode 100644
index 00..60032fc724
--- /dev/null
+++ b/drivers/pci_endpoint/pcie-cadence-ep.c
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2019
+ * Written by Ramon Fried
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "pcie-cadence.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int cdns_write_header(struct udevice *dev, uint fn,
+struct pci_ep_header *hdr)
+{
+ struct cdns_pcie *pcie = dev_get_priv(dev);
+
+ cdns_pcie_ep_fn_writew(pcie, fn, PCI_DEVICE_ID, hdr->deviceid);
+ cdns_pcie_ep_fn_writeb(pcie, fn, PCI_REVISION_ID, hdr->revid);
+ cdns_pcie_ep_fn_writeb(pcie, fn, PCI_CLASS_PROG,
+ hdr->progif_code);
+ cdns_pcie_ep_fn_writew(pcie, fn, PCI_CLASS_DEVICE,
+ hdr->subclass_code |
+ hdr->baseclass_code << 8);
+ cdns_pcie_ep_fn_writeb(pcie, fn, PCI_CACHE_LINE_SIZE,
+ hdr->cache_line_size);
+ cdns_pcie_ep_fn_writew(pcie, fn, PCI_SUBSYSTEM_ID,
+ hdr->subsys_id);
+ cdns_pcie_ep_fn_writeb(pcie, fn, PCI_INTERRUPT_PIN,
+ hdr->interrupt_pin);
+
+ /*
+* Vendor ID can only be modified from function 0, all other functions
+* use the same vendor ID as function 0.
+*/
+ if (fn == 0) {
+ /* Update the vendor IDs. */
+ u32 id = CDNS_PCIE_LM_ID_VENDOR(hdr->vendorid) |
+CDNS_PCIE_LM_ID_SUBSYS(hdr->subsys_vendor_id);
+
+ cdns_pcie_writel(pcie, CDNS_PCIE_LM_ID, id);
+ }
+
+ return 0;
+}
+
+static int cdns_set_bar(struct udevice *dev, uint fn, struct pci_bar *ep_bar)
+{
+ struct cdns_pcie *pcie = dev_get_priv(dev);
+ dma_addr_t bar_phys = ep_bar->phys_addr;
+ enum pci_barno bar = ep_bar->barno;
+ int flags = ep_bar->flags;
+ u32 addr0, addr1, reg, cfg, b, aperture, ctrl;
+ u64 sz;
+
+ /* BAR size is 2^(aperture + 7) */
+ sz = max_t(size_t, ep_bar->size, CDNS_PCIE_EP_MIN_APERTURE);
+ /*
+* roundup_pow_of_two() returns an unsigned long, which is not suited
+* for 64bit values.
+*/
+ sz = 1ULL << fls64(sz - 1);
+ aperture = ilog2(sz) - 7; /* 128B -> 0, 256B -> 1, 512B -> 2, ... */
+