Introduce new UCLASS_PCI_EP class for handling PCI endpoint
devices, allowing to set various attributes of the PCI endpoint
device, such as:
* configuration space header
* BAR definitions
* outband memory mapping
* start/stop PCI link
Signed-off-by: Ramon Fried
---
Changes in v3: None
MAINTAINERS | 6 +
drivers/Kconfig | 2 +
drivers/Makefile | 1 +
drivers/pci_endpoint/Kconfig | 17 ++
drivers/pci_endpoint/Makefile| 6 +
drivers/pci_endpoint/pci_ep-uclass.c | 211 ++
include/dm/uclass-id.h | 1 +
include/pci_ep.h | 414 +++
8 files changed, 658 insertions(+)
create mode 100644 drivers/pci_endpoint/Kconfig
create mode 100644 drivers/pci_endpoint/Makefile
create mode 100644 drivers/pci_endpoint/pci_ep-uclass.c
create mode 100644 include/pci_ep.h
diff --git a/MAINTAINERS b/MAINTAINERS
index b9cb686a05..9d95ef826b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -626,6 +626,12 @@ M: Simon Glass
S: Maintained
F: tools/patman/
+PCI Endpoint
+M: Ramon Fried
+S: Maintained
+F: drivers/pci_endpoint/
+F: include/pci_ep.h
+
POWER
M: Jaehoon Chung
S: Maintained
diff --git a/drivers/Kconfig b/drivers/Kconfig
index e6702eced4..258dfa19e8 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -64,6 +64,8 @@ source "drivers/nvme/Kconfig"
source "drivers/pci/Kconfig"
+source "drivers/pci_endpoint/Kconfig"
+
source "drivers/pch/Kconfig"
source "drivers/pcmcia/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index a7bba3ed56..480b97ef58 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -85,6 +85,7 @@ obj-$(CONFIG_FPGA) += fpga/
obj-y += misc/
obj-$(CONFIG_MMC) += mmc/
obj-$(CONFIG_NVME) += nvme/
+obj-$(CONFIG_PCI_ENDPOINT) += pci_endpoint/
obj-y += pcmcia/
obj-y += dfu/
obj-$(CONFIG_PCH) += pch/
diff --git a/drivers/pci_endpoint/Kconfig b/drivers/pci_endpoint/Kconfig
new file mode 100644
index 00..ac4f43d1ab
--- /dev/null
+++ b/drivers/pci_endpoint/Kconfig
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# PCI Endpoint Support
+#
+
+menu "PCI Endpoint"
+
+config PCI_ENDPOINT
+ bool "PCI Endpoint Support"
+ depends on DM
+ help
+ Enable this configuration option to support configurable PCI
+ endpoints. This should be enabled if the platform has a PCI
+ controllers that can operate in endpoint mode (as a device
+ connected to PCI host or bridge).
+
+endmenu
diff --git a/drivers/pci_endpoint/Makefile b/drivers/pci_endpoint/Makefile
new file mode 100644
index 00..80a1066925
--- /dev/null
+++ b/drivers/pci_endpoint/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2019
+# Ramon Fried
+
+obj-y += pci_ep-uclass.o
diff --git a/drivers/pci_endpoint/pci_ep-uclass.c
b/drivers/pci_endpoint/pci_ep-uclass.c
new file mode 100644
index 00..2f9c70398d
--- /dev/null
+++ b/drivers/pci_endpoint/pci_ep-uclass.c
@@ -0,0 +1,211 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * PCI Endpoint uclass
+ *
+ * Based on Linux PCI-EP driver written by
+ * Kishon Vijay Abraham I
+ *
+ * Copyright (c) 2019
+ * Written by Ramon Fried
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int pci_ep_write_header(struct udevice *dev, uint fn, struct pci_ep_header
*hdr)
+{
+ struct pci_ep_ops *ops = pci_ep_get_ops(dev);
+
+ if (!ops->write_header)
+ return -ENOSYS;
+
+ return ops->write_header(dev, fn, hdr);
+}
+
+int pci_ep_read_header(struct udevice *dev, uint fn, struct pci_ep_header *hdr)
+{
+ struct pci_ep_ops *ops = pci_ep_get_ops(dev);
+
+ if (!ops->read_header)
+ return -ENOSYS;
+
+ return ops->read_header(dev, fn, hdr);
+}
+
+int pci_ep_set_bar(struct udevice *dev, uint func_no, struct pci_bar *ep_bar)
+{
+ struct pci_ep_ops *ops = pci_ep_get_ops(dev);
+ int flags = ep_bar->flags;
+
+ /* Some basic bar validity checks */
+ if (ep_bar->barno > BAR_5 || ep_bar < BAR_0)
+ return -EINVAL;
+
+ if ((ep_bar->barno == BAR_5 &&
+(flags & PCI_BASE_ADDRESS_MEM_TYPE_64)) ||
+ ((flags & PCI_BASE_ADDRESS_SPACE_IO) &&
+(flags & PCI_BASE_ADDRESS_IO_MASK)) ||
+ (upper_32_bits(ep_bar->size) &&
+!(flags & PCI_BASE_ADDRESS_MEM_TYPE_64)))
+ return -EINVAL;
+
+ if (!ops->set_bar)
+ return -ENOSYS;
+
+ return ops->set_bar(dev, func_no, ep_bar);
+}
+
+int pci_ep_read_bar(struct udevice *dev, uint func_no, struct pci_bar *ep_bar,
+ enum pci_barno barno)
+{
+ struct pci_ep_ops *ops = pci_ep_get_ops(dev);
+
+ /* Some basic bar validity checks */
+ if (barno > BAR_5 || barno < BAR_0)
+ return -EINVAL;
+
+ if (!ops->read_bar)
+