2019-10-15 11:14:28

by Bao Xiaowei

[permalink] [raw]
Subject: [PATCH v2 0/6] Add the Mobiveil EP and Layerscape Gen4 EP driver support

This patch set are for adding Mobiveil EP driver and adding PCIe Gen4
EP driver of NXP Layerscape platform.

This patch set depends on:
https://patchwork.kernel.org/project/linux-pci/list/?series=159139

Xiaowei Bao (6):
PCI: mobiveil: Add the EP driver support
dt-bindings: Add DT binding for PCIE GEN4 EP of the layerscape
PCI: mobiveil: Add PCIe Gen4 EP driver for NXP Layerscape SoCs
PCI: mobiveil: Add workaround for unsupported request error
arm64: dts: lx2160a: Add PCIe EP node
misc: pci_endpoint_test: Add the layerscape PCIe GEN4 EP device
support

.../bindings/pci/layerscape-pcie-gen4.txt | 27 +-
MAINTAINERS | 3 +
arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 56 ++
drivers/misc/pci_endpoint_test.c | 2 +
drivers/pci/controller/mobiveil/Kconfig | 22 +-
drivers/pci/controller/mobiveil/Makefile | 2 +
.../controller/mobiveil/pcie-layerscape-gen4-ep.c | 169 ++++++
drivers/pci/controller/mobiveil/pcie-mobiveil-ep.c | 569 +++++++++++++++++++++
drivers/pci/controller/mobiveil/pcie-mobiveil.c | 99 +++-
drivers/pci/controller/mobiveil/pcie-mobiveil.h | 72 +++
10 files changed, 1009 insertions(+), 12 deletions(-)
create mode 100644 drivers/pci/controller/mobiveil/pcie-layerscape-gen4-ep.c
create mode 100644 drivers/pci/controller/mobiveil/pcie-mobiveil-ep.c

--
2.9.5


2019-10-15 11:14:46

by Bao Xiaowei

[permalink] [raw]
Subject: [PATCH v2 6/6] misc: pci_endpoint_test: Add the layerscape PCIe GEN4 EP device support

Add the layerscape PCIE GEN4 EP device support in pci_endpoint_test driver.

Signed-off-by: Xiaowei Bao <[email protected]>
---
v2:
- No change.

drivers/misc/pci_endpoint_test.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index 6e208a0..8b145a7 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -65,6 +65,7 @@
#define PCI_ENDPOINT_TEST_IRQ_NUMBER 0x28

#define PCI_DEVICE_ID_TI_AM654 0xb00c
+#define PCI_DEVICE_ID_LX2160A 0x8d80

#define is_am654_pci_dev(pdev) \
((pdev)->device == PCI_DEVICE_ID_TI_AM654)
@@ -793,6 +794,7 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x) },
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA72x) },
{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x81c0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_LX2160A) },
{ PCI_DEVICE_DATA(SYNOPSYS, EDDA, NULL) },
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM654),
.driver_data = (kernel_ulong_t)&am654_data
--
2.9.5

2019-10-15 11:14:55

by Bao Xiaowei

[permalink] [raw]
Subject: [PATCH v2 4/6] PCI: mobiveil: Add workaround for unsupported request error

Errata: unsupported request error on inbound posted write
transaction, PCIe controller reports advisory error instead
of uncorrectable error message to RC.

Signed-off-by: Xiaowei Bao <[email protected]>
---
v3:
- Use BIT replce the expression.

drivers/pci/controller/mobiveil/pcie-layerscape-gen4-ep.c | 13 +++++++++++++
drivers/pci/controller/mobiveil/pcie-mobiveil.h | 4 ++++
2 files changed, 17 insertions(+)

diff --git a/drivers/pci/controller/mobiveil/pcie-layerscape-gen4-ep.c b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4-ep.c
index 56603ea..82bb38d 100644
--- a/drivers/pci/controller/mobiveil/pcie-layerscape-gen4-ep.c
+++ b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4-ep.c
@@ -49,6 +49,19 @@ static void ls_pcie_g4_ep_init(struct mobiveil_pcie_ep *ep)
struct mobiveil_pcie *mv_pci = to_mobiveil_pcie_from_ep(ep);
int win_idx;
u8 bar;
+ u32 val;
+
+ /*
+ * Errata: unsupported request error on inbound posted write
+ * transaction, PCIe controller reports advisory error instead
+ * of uncorrectable error message to RC.
+ * workaround: set the bit20(unsupported_request_Error_severity) with
+ * value 1 in uncorrectable_Error_Severity_Register, make the
+ * unsupported request error generate the fatal error.
+ */
+ val = csr_readl(mv_pci, CFG_UNCORRECTABLE_ERROR_SEVERITY);
+ val |= BIT(UNSUPPORTED_REQUEST_ERROR_SHIFT);
+ csr_writel(mv_pci, val, CFG_UNCORRECTABLE_ERROR_SEVERITY);

ep->bar_num = PCIE_LX2_BAR_NUM;

diff --git a/drivers/pci/controller/mobiveil/pcie-mobiveil.h b/drivers/pci/controller/mobiveil/pcie-mobiveil.h
index 7308fa4..a40707e 100644
--- a/drivers/pci/controller/mobiveil/pcie-mobiveil.h
+++ b/drivers/pci/controller/mobiveil/pcie-mobiveil.h
@@ -123,6 +123,10 @@
#define GPEX_BAR_SIZE_UDW 0x4DC
#define GPEX_BAR_SELECT 0x4E0

+#define CFG_UNCORRECTABLE_ERROR_SEVERITY 0x10c
+#define UNSUPPORTED_REQUEST_ERROR_SHIFT 20
+#define CFG_UNCORRECTABLE_ERROR_MASK 0x108
+
/* starting offset of INTX bits in status register */
#define PAB_INTX_START 5

--
2.9.5

2019-10-15 11:14:56

by Bao Xiaowei

[permalink] [raw]
Subject: [PATCH v2 5/6] arm64: dts: lx2160a: Add PCIe EP node

Add the LX2160A PCIe EP node.

Signed-off-by: Xiaowei Bao <[email protected]>
---
v2:
- No change.

arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 56 ++++++++++++++++++++++++++
1 file changed, 56 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
index f60e5ac..18330df 100644
--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
@@ -1005,6 +1005,15 @@
status = "disabled";
};

+ pcie_ep@3400000 {
+ compatible = "fsl,lx2160a-pcie-ep";
+ reg = <0x00 0x03400000 0x0 0x00100000
+ 0x80 0x00000000 0x8 0x00000000>;
+ reg-names = "regs", "addr_space";
+ apio-wins = <8>;
+ status = "disabled";
+ };
+
pcie@3500000 {
compatible = "fsl,lx2160a-pcie";
reg = <0x00 0x03500000 0x0 0x00100000 /* controller registers */
@@ -1032,6 +1041,15 @@
status = "disabled";
};

+ pcie_ep@3500000 {
+ compatible = "fsl,lx2160a-pcie-ep";
+ reg = <0x00 0x03500000 0x0 0x00100000
+ 0x88 0x00000000 0x8 0x00000000>;
+ reg-names = "regs", "addr_space";
+ apio-wins = <8>;
+ status = "disabled";
+ };
+
pcie@3600000 {
compatible = "fsl,lx2160a-pcie";
reg = <0x00 0x03600000 0x0 0x00100000 /* controller registers */
@@ -1059,6 +1077,16 @@
status = "disabled";
};

+ pcie_ep@3600000 {
+ compatible = "fsl,lx2160a-pcie-ep";
+ reg = <0x00 0x03600000 0x0 0x00100000
+ 0x90 0x00000000 0x8 0x00000000>;
+ reg-names = "regs", "addr_space";
+ apio-wins = <256>;
+ max-functions = /bits/ 8 <2>;
+ status = "disabled";
+ };
+
pcie@3700000 {
compatible = "fsl,lx2160a-pcie";
reg = <0x00 0x03700000 0x0 0x00100000 /* controller registers */
@@ -1086,6 +1114,15 @@
status = "disabled";
};

+ pcie_ep@3700000 {
+ compatible = "fsl,lx2160a-pcie-ep";
+ reg = <0x00 0x03700000 0x0 0x00100000
+ 0x98 0x00000000 0x8 0x00000000>;
+ reg-names = "regs", "addr_space";
+ apio-wins = <8>;
+ status = "disabled";
+ };
+
pcie@3800000 {
compatible = "fsl,lx2160a-pcie";
reg = <0x00 0x03800000 0x0 0x00100000 /* controller registers */
@@ -1113,6 +1150,16 @@
status = "disabled";
};

+ pcie_ep@3800000 {
+ compatible = "fsl,lx2160a-pcie-ep";
+ reg = <0x00 0x03800000 0x0 0x00100000
+ 0xa0 0x00000000 0x8 0x00000000>;
+ reg-names = "regs", "addr_space";
+ apio-wins = <256>;
+ max-functions = /bits/ 8 <2>;
+ status = "disabled";
+ };
+
pcie@3900000 {
compatible = "fsl,lx2160a-pcie";
reg = <0x00 0x03900000 0x0 0x00100000 /* controller registers */
@@ -1140,5 +1187,14 @@
status = "disabled";
};

+ pcie_ep@3900000 {
+ compatible = "fsl,lx2160a-pcie-ep";
+ reg = <0x00 0x03900000 0x0 0x00100000
+ 0xa8 0x00000000 0x8 0x00000000>;
+ reg-names = "regs", "addr_space";
+ apio-wins = <8>;
+ status = "disabled";
+ };
+
};
};
--
2.9.5

2019-10-15 11:15:04

by Bao Xiaowei

[permalink] [raw]
Subject: [PATCH v2 1/6] PCI: mobiveil: Add the EP driver support

Add the EP driver support for Mobiveil base on endpoint framework.

Signed-off-by: Xiaowei Bao <[email protected]>
---
v2:
- Modify the Copyright.

MAINTAINERS | 1 +
drivers/pci/controller/mobiveil/Kconfig | 5 +
drivers/pci/controller/mobiveil/Makefile | 1 +
drivers/pci/controller/mobiveil/pcie-mobiveil-ep.c | 569 +++++++++++++++++++++
drivers/pci/controller/mobiveil/pcie-mobiveil.c | 99 +++-
drivers/pci/controller/mobiveil/pcie-mobiveil.h | 68 +++
6 files changed, 735 insertions(+), 8 deletions(-)
create mode 100644 drivers/pci/controller/mobiveil/pcie-mobiveil-ep.c

diff --git a/MAINTAINERS b/MAINTAINERS
index e6a4de0..b997056 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12409,6 +12409,7 @@ F: drivers/ntb/hw/mscc/
PCI DRIVER FOR MOBIVEIL PCIE IP
M: Karthikeyan Mitran <[email protected]>
M: Hou Zhiqiang <[email protected]>
+M: Xiaowei Bao <[email protected]>
L: [email protected]
S: Supported
F: Documentation/devicetree/bindings/pci/mobiveil-pcie.txt
diff --git a/drivers/pci/controller/mobiveil/Kconfig b/drivers/pci/controller/mobiveil/Kconfig
index c823be8..2054950 100644
--- a/drivers/pci/controller/mobiveil/Kconfig
+++ b/drivers/pci/controller/mobiveil/Kconfig
@@ -11,6 +11,11 @@ config PCIE_MOBIVEIL_HOST
depends on PCI_MSI_IRQ_DOMAIN
select PCIE_MOBIVEIL

+config PCIE_MOBIVEIL_EP
+ bool
+ depends on PCI_ENDPOINT
+ select PCIE_MOBIVEIL
+
config PCIE_MOBIVEIL_PLAT
bool "Mobiveil AXI PCIe controller"
depends on ARCH_ZYNQMP || COMPILE_TEST
diff --git a/drivers/pci/controller/mobiveil/Makefile b/drivers/pci/controller/mobiveil/Makefile
index 99d879d..686d41f 100644
--- a/drivers/pci/controller/mobiveil/Makefile
+++ b/drivers/pci/controller/mobiveil/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o
obj-$(CONFIG_PCIE_MOBIVEIL_HOST) += pcie-mobiveil-host.o
+obj-$(CONFIG_PCIE_MOBIVEIL_EP) += pcie-mobiveil-ep.o
obj-$(CONFIG_PCIE_MOBIVEIL_PLAT) += pcie-mobiveil-plat.o
obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie-layerscape-gen4.o
diff --git a/drivers/pci/controller/mobiveil/pcie-mobiveil-ep.c b/drivers/pci/controller/mobiveil/pcie-mobiveil-ep.c
new file mode 100644
index 0000000..285d7cb
--- /dev/null
+++ b/drivers/pci/controller/mobiveil/pcie-mobiveil-ep.c
@@ -0,0 +1,569 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Mobiveil PCIe Endpoint controller driver
+ *
+ * Copyright 2019 NXP
+ *
+ * Author: Xiaowei Bao <[email protected]>
+ */
+
+#include <linux/of.h>
+#include <linux/pci-epc.h>
+#include <linux/pci-epf.h>
+#include <linux/platform_device.h>
+#include "pcie-mobiveil.h"
+
+static void mobiveil_pcie_ep_func_select(struct mobiveil_pcie *pcie, u8 func_no)
+{
+ u32 func_num;
+
+ /*
+ * select to access the config space of func_no by setting func_no
+ * to FUNC_SEL_SHIFT bit of PAB_CTRL register.
+ */
+ func_num = csr_readl(pcie, PAB_CTRL);
+ func_num &= ~(FUNC_SEL_MASK << FUNC_SEL_SHIFT);
+ func_num |= (func_no & FUNC_SEL_MASK) << FUNC_SEL_SHIFT;
+ csr_writel(pcie, func_num, PAB_CTRL);
+}
+
+static void mobiveil_pcie_ep_func_deselect(struct mobiveil_pcie *pcie)
+{
+ u32 func_num;
+
+ /*
+ * clear the FUNC_SEL_SHIFT bits when access other registers except
+ * config space register.
+ */
+ func_num = csr_readl(pcie, PAB_CTRL);
+ func_num &= ~(FUNC_SEL_MASK << FUNC_SEL_SHIFT);
+ csr_writel(pcie, func_num, PAB_CTRL);
+}
+
+static void __mobiveil_pcie_ep_reset_bar(struct mobiveil_pcie *pcie, u8 bar)
+{
+ csr_writel(pcie, bar, GPEX_BAR_SELECT);
+ csr_writel(pcie, 0, GPEX_BAR_SIZE_LDW);
+ csr_writel(pcie, 0, GPEX_BAR_SIZE_UDW);
+}
+
+void mobiveil_pcie_ep_reset_bar(struct mobiveil_pcie *pcie, u8 bar)
+{
+ __mobiveil_pcie_ep_reset_bar(pcie, bar);
+}
+
+static u8 __mobiveil_pcie_ep_find_next_cap(struct mobiveil_pcie *pcie,
+ u8 func_no, u8 cap_ptr, u8 cap)
+{
+ u8 cap_id, next_cap_ptr;
+ u16 reg;
+
+ if (!cap_ptr)
+ return 0;
+
+ mobiveil_pcie_ep_func_select(pcie, func_no);
+
+ reg = csr_readw(pcie, cap_ptr);
+ cap_id = (reg & 0x00ff);
+
+ mobiveil_pcie_ep_func_deselect(pcie);
+
+ if (cap_id > PCI_CAP_ID_MAX)
+ return 0;
+
+ if (cap_id == cap)
+ return cap_ptr;
+
+ next_cap_ptr = (reg & 0xff00) >> 8;
+ return __mobiveil_pcie_ep_find_next_cap(pcie, func_no,
+ next_cap_ptr, cap);
+}
+
+static u8 mobiveil_pcie_ep_find_capability(struct mobiveil_pcie_ep *ep,
+ u8 func_no, u8 cap)
+{
+ struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
+ u8 next_cap_ptr;
+ u16 reg;
+
+ mobiveil_pcie_ep_func_select(pcie, func_no);
+
+ reg = csr_readw(pcie, PCI_CAPABILITY_LIST);
+ next_cap_ptr = (reg & 0x00ff);
+
+ mobiveil_pcie_ep_func_deselect(pcie);
+
+ return __mobiveil_pcie_ep_find_next_cap(pcie, func_no,
+ next_cap_ptr, cap);
+}
+
+static int mobiveil_pcie_ep_write_header(struct pci_epc *epc, u8 func_no,
+ struct pci_epf_header *hdr)
+{
+ struct mobiveil_pcie_ep *ep = epc_get_drvdata(epc);
+ struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
+
+ mobiveil_pcie_ep_func_select(pcie, func_no);
+
+ csr_writew(pcie, hdr->vendorid, PCI_VENDOR_ID);
+ csr_writew(pcie, hdr->deviceid, PCI_DEVICE_ID);
+ csr_writeb(pcie, hdr->revid, PCI_REVISION_ID);
+ csr_writeb(pcie, hdr->progif_code, PCI_CLASS_PROG);
+ csr_writew(pcie, hdr->subclass_code | hdr->baseclass_code << 8,
+ PCI_CLASS_DEVICE);
+ csr_writeb(pcie, hdr->cache_line_size, PCI_CACHE_LINE_SIZE);
+ csr_writew(pcie, hdr->subsys_vendor_id, PCI_SUBSYSTEM_VENDOR_ID);
+ csr_writew(pcie, hdr->subsys_id, PCI_SUBSYSTEM_ID);
+ csr_writeb(pcie, hdr->interrupt_pin, PCI_INTERRUPT_PIN);
+
+ mobiveil_pcie_ep_func_deselect(pcie);
+
+ return 0;
+}
+
+static void mobiveil_pcie_ep_inbound_win(struct mobiveil_pcie_ep *ep,
+ u8 func_no, enum pci_barno bar,
+ dma_addr_t cpu_addr)
+{
+ struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
+
+ program_ib_windows_ep(pcie, func_no, bar, cpu_addr);
+}
+
+static int mobiveil_pcie_ep_outbound_win(struct mobiveil_pcie_ep *ep,
+ phys_addr_t phys_addr,
+ u64 pci_addr, u8 func_no,
+ size_t size)
+{
+ u32 free_win;
+ struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
+
+ free_win = find_first_zero_bit(ep->apio_wins_map, ep->apio_wins);
+ if (free_win >= ep->apio_wins) {
+ dev_err(&pcie->pdev->dev, "No free outbound window\n");
+ return -EINVAL;
+ }
+
+ program_ob_windows_ep(pcie, func_no, free_win, phys_addr,
+ pci_addr, MEM_WINDOW_TYPE, size);
+
+ set_bit(free_win, ep->apio_wins_map);
+ ep->apio_addr[free_win] = phys_addr;
+
+ return 0;
+}
+
+static void mobiveil_pcie_ep_clear_bar(struct pci_epc *epc, u8 func_no,
+ struct pci_epf_bar *epf_bar)
+{
+ struct mobiveil_pcie_ep *ep = epc_get_drvdata(epc);
+ struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
+ enum pci_barno bar = epf_bar->barno;
+
+ if (bar < ep->bar_num) {
+ __mobiveil_pcie_ep_reset_bar(pcie, func_no * ep->bar_num + bar);
+
+ mobiveil_pcie_disable_ib_win_ep(pcie, func_no, bar);
+ }
+}
+
+static int mobiveil_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no,
+ struct pci_epf_bar *epf_bar)
+{
+ struct mobiveil_pcie_ep *ep = epc_get_drvdata(epc);
+ struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
+ enum pci_barno bar = epf_bar->barno;
+ size_t size = epf_bar->size;
+
+ if (bar < ep->bar_num) {
+ mobiveil_pcie_ep_inbound_win(ep, func_no, bar,
+ epf_bar->phys_addr);
+
+ csr_writel(pcie, func_no * ep->bar_num + bar,
+ GPEX_BAR_SELECT);
+ csr_writel(pcie, lower_32_bits(~(size - 1)),
+ GPEX_BAR_SIZE_LDW);
+ csr_writel(pcie, upper_32_bits(~(size - 1)),
+ GPEX_BAR_SIZE_UDW);
+ }
+
+ return 0;
+}
+
+static int mobiveil_pcie_find_index(struct mobiveil_pcie_ep *ep,
+ phys_addr_t addr,
+ u32 *atu_index)
+{
+ u32 index;
+
+ for (index = 0; index < ep->apio_wins; index++) {
+ if (ep->apio_addr[index] != addr)
+ continue;
+ *atu_index = index;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static void mobiveil_pcie_ep_unmap_addr(struct pci_epc *epc, u8 func_no,
+ phys_addr_t addr)
+{
+ int ret;
+ u32 atu_index;
+ struct mobiveil_pcie_ep *ep = epc_get_drvdata(epc);
+ struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
+
+ ret = mobiveil_pcie_find_index(ep, addr, &atu_index);
+ if (ret < 0)
+ return;
+
+ mobiveil_pcie_disable_ob_win(pcie, atu_index);
+ clear_bit(atu_index, ep->apio_wins_map);
+}
+
+static int mobiveil_pcie_ep_map_addr(struct pci_epc *epc, u8 func_no,
+ phys_addr_t addr,
+ u64 pci_addr, size_t size)
+{
+ int ret;
+ struct mobiveil_pcie_ep *ep = epc_get_drvdata(epc);
+ struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
+
+ ret = mobiveil_pcie_ep_outbound_win(ep, addr, pci_addr, func_no, size);
+ if (ret) {
+ dev_err(&pcie->pdev->dev, "Failed to enable address\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mobiveil_pcie_ep_get_msi(struct pci_epc *epc, u8 func_no)
+{
+ struct mobiveil_pcie_ep *ep = epc_get_drvdata(epc);
+ struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
+ u32 val, reg;
+ u8 msi_cap;
+
+ msi_cap = mobiveil_pcie_ep_find_capability(ep, func_no,
+ PCI_CAP_ID_MSI);
+ if (!msi_cap)
+ return -EINVAL;
+
+ mobiveil_pcie_ep_func_select(pcie, func_no);
+
+ reg = msi_cap + PCI_MSI_FLAGS;
+ val = csr_readw(pcie, reg);
+
+ mobiveil_pcie_ep_func_deselect(pcie);
+
+ if (!(val & PCI_MSI_FLAGS_ENABLE))
+ return -EINVAL;
+
+ val = (val & PCI_MSI_FLAGS_QSIZE) >> 4;
+
+ return val;
+}
+
+static int mobiveil_pcie_ep_set_msi(struct pci_epc *epc,
+ u8 func_no, u8 interrupts)
+{
+ struct mobiveil_pcie_ep *ep = epc_get_drvdata(epc);
+ struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
+ u32 val, reg;
+ u8 msi_cap;
+
+ msi_cap = mobiveil_pcie_ep_find_capability(ep, func_no,
+ PCI_CAP_ID_MSI);
+ if (!msi_cap)
+ return -EINVAL;
+
+ mobiveil_pcie_ep_func_select(pcie, func_no);
+
+ reg = msi_cap + PCI_MSI_FLAGS;
+ val = csr_readw(pcie, reg);
+ val &= ~PCI_MSI_FLAGS_QMASK;
+ val |= (interrupts << 1) & PCI_MSI_FLAGS_QMASK;
+ csr_writew(pcie, val, reg);
+
+ mobiveil_pcie_ep_func_deselect(pcie);
+
+ return 0;
+}
+
+static int mobiveil_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no)
+{
+ struct mobiveil_pcie_ep *ep = epc_get_drvdata(epc);
+ struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
+ u32 val, reg;
+ u8 msix_cap;
+
+ msix_cap = mobiveil_pcie_ep_find_capability(ep, func_no,
+ PCI_CAP_ID_MSIX);
+ if (!msix_cap)
+ return -EINVAL;
+
+ mobiveil_pcie_ep_func_select(pcie, func_no);
+
+ reg = msix_cap + PCI_MSIX_FLAGS;
+ val = csr_readw(pcie, reg);
+
+ mobiveil_pcie_ep_func_deselect(pcie);
+
+ if (!(val & PCI_MSIX_FLAGS_ENABLE))
+ return -EINVAL;
+
+ val &= PCI_MSIX_FLAGS_QSIZE;
+
+ return val;
+}
+
+static int mobiveil_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no,
+ u16 interrupts)
+{
+ struct mobiveil_pcie_ep *ep = epc_get_drvdata(epc);
+ struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
+ u32 val, reg;
+ u8 msix_cap;
+
+ msix_cap = mobiveil_pcie_ep_find_capability(ep, func_no,
+ PCI_CAP_ID_MSIX);
+ if (!msix_cap)
+ return -EINVAL;
+
+ mobiveil_pcie_ep_func_select(pcie, func_no);
+
+ reg = msix_cap + PCI_MSIX_FLAGS;
+ val = csr_readw(pcie, reg);
+ val &= ~PCI_MSIX_FLAGS_QSIZE;
+ val |= interrupts;
+ csr_writew(pcie, val, reg);
+
+ mobiveil_pcie_ep_func_deselect(pcie);
+
+ return 0;
+}
+
+static int mobiveil_pcie_ep_raise_irq(struct pci_epc *epc, u8 func_no,
+ enum pci_epc_irq_type type,
+ u16 interrupt_num)
+{
+ struct mobiveil_pcie_ep *ep = epc_get_drvdata(epc);
+
+ if (!ep->ops->raise_irq)
+ return -EINVAL;
+
+ return ep->ops->raise_irq(ep, func_no, type, interrupt_num);
+}
+
+static const struct pci_epc_features*
+mobiveil_pcie_ep_get_features(struct pci_epc *epc, u8 func_no)
+{
+ struct mobiveil_pcie_ep *ep = epc_get_drvdata(epc);
+
+ if (!ep->ops->get_features)
+ return NULL;
+
+ return ep->ops->get_features(ep);
+}
+
+static const struct pci_epc_ops epc_ops = {
+ .write_header = mobiveil_pcie_ep_write_header,
+ .set_bar = mobiveil_pcie_ep_set_bar,
+ .clear_bar = mobiveil_pcie_ep_clear_bar,
+ .map_addr = mobiveil_pcie_ep_map_addr,
+ .unmap_addr = mobiveil_pcie_ep_unmap_addr,
+ .set_msi = mobiveil_pcie_ep_set_msi,
+ .get_msi = mobiveil_pcie_ep_get_msi,
+ .set_msix = mobiveil_pcie_ep_set_msix,
+ .get_msix = mobiveil_pcie_ep_get_msix,
+ .raise_irq = mobiveil_pcie_ep_raise_irq,
+ .get_features = mobiveil_pcie_ep_get_features,
+};
+
+int mobiveil_pcie_ep_raise_legacy_irq(struct mobiveil_pcie_ep *ep, u8 func_no)
+{
+ struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
+
+ dev_err(&pcie->pdev->dev, "EP cannot trigger legacy IRQs\n");
+
+ return -EINVAL;
+}
+
+int mobiveil_pcie_ep_raise_msi_irq(struct mobiveil_pcie_ep *ep, u8 func_no,
+ u8 interrupt_num)
+{
+ struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
+ struct pci_epc *epc = ep->epc;
+ u16 msg_ctrl, msg_data;
+ u32 msg_addr_lower, msg_addr_upper, reg;
+ u64 msg_addr;
+ bool has_upper;
+ int ret;
+ u8 msi_cap;
+
+ msi_cap = mobiveil_pcie_ep_find_capability(ep, func_no,
+ PCI_CAP_ID_MSI);
+ if (!msi_cap)
+ return -EINVAL;
+
+ mobiveil_pcie_ep_func_select(pcie, func_no);
+
+ reg = msi_cap + PCI_MSI_FLAGS;
+ msg_ctrl = csr_readw(pcie, reg);
+ has_upper = !!(msg_ctrl & PCI_MSI_FLAGS_64BIT);
+ reg = msi_cap + PCI_MSI_ADDRESS_LO;
+ msg_addr_lower = csr_readl(pcie, reg);
+ if (has_upper) {
+ reg = msi_cap + PCI_MSI_ADDRESS_HI;
+ msg_addr_upper = csr_readl(pcie, reg);
+ reg = msi_cap + PCI_MSI_DATA_64;
+ msg_data = csr_readw(pcie, reg);
+ } else {
+ msg_addr_upper = 0;
+ reg = msi_cap + PCI_MSI_DATA_32;
+ msg_data = csr_readw(pcie, reg);
+ }
+ msg_addr = ((u64) msg_addr_upper) << 32 | msg_addr_lower;
+
+ mobiveil_pcie_ep_func_deselect(pcie);
+
+ ret = mobiveil_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys,
+ msg_addr, epc->mem->page_size);
+ if (ret)
+ return ret;
+
+ writel(msg_data | (interrupt_num - 1), ep->msi_mem);
+
+ mobiveil_pcie_ep_unmap_addr(epc, func_no, ep->msi_mem_phys);
+
+ return 0;
+}
+
+int mobiveil_pcie_ep_raise_msix_irq(struct mobiveil_pcie_ep *ep, u8 func_no,
+ u16 interrupt_num)
+{
+ struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
+ struct pci_epc *epc = ep->epc;
+ u32 msg_addr_upper, msg_addr_lower;
+ u32 msg_data;
+ u64 msg_addr;
+ u8 msix_cap;
+ int ret;
+
+ msix_cap = mobiveil_pcie_ep_find_capability(ep, func_no,
+ PCI_CAP_ID_MSIX);
+ if (!msix_cap)
+ return -EINVAL;
+
+ mobiveil_pcie_ep_func_deselect(pcie);
+
+ msg_addr_lower = csr_readl(pcie, PAB_MSIX_TABLE_PBA_ACCESS +
+ PCI_MSIX_ENTRY_LOWER_ADDR +
+ (interrupt_num - 1) * PCI_MSIX_ENTRY_SIZE);
+ msg_addr_upper = csr_readl(pcie, PAB_MSIX_TABLE_PBA_ACCESS +
+ PCI_MSIX_ENTRY_UPPER_ADDR +
+ (interrupt_num - 1) * PCI_MSIX_ENTRY_SIZE);
+ msg_addr = ((u64) msg_addr_upper) << 32 | msg_addr_lower;
+ msg_data = csr_readl(pcie, PAB_MSIX_TABLE_PBA_ACCESS +
+ PCI_MSIX_ENTRY_DATA +
+ (interrupt_num - 1) * PCI_MSIX_ENTRY_SIZE);
+
+ ret = mobiveil_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys,
+ msg_addr, epc->mem->page_size);
+ if (ret)
+ return ret;
+
+ writel(msg_data, ep->msi_mem);
+
+ mobiveil_pcie_ep_unmap_addr(epc, func_no, ep->msi_mem_phys);
+
+ return 0;
+}
+
+void mobiveil_pcie_ep_exit(struct mobiveil_pcie_ep *ep)
+{
+ struct pci_epc *epc = ep->epc;
+
+ pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem,
+ epc->mem->page_size);
+
+ pci_epc_mem_exit(epc);
+}
+
+int mobiveil_pcie_ep_init(struct mobiveil_pcie_ep *ep)
+{
+ int ret;
+ void *addr;
+ struct pci_epc *epc;
+ struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
+ struct device *dev = &pcie->pdev->dev;
+ struct device_node *np = dev->of_node;
+
+ if (!pcie->csr_axi_slave_base) {
+ dev_err(dev, "csr_base is not populated\n");
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32(np, "apio-wins", &ep->apio_wins);
+ if (ret < 0) {
+ dev_err(dev, "Unable to read apio-wins property\n");
+ return ret;
+ }
+
+ if (ep->apio_wins > MAX_IATU_OUT) {
+ dev_err(dev, "Invalid apio-wins\n");
+ return -EINVAL;
+ }
+ ep->apio_wins_map = devm_kcalloc(dev,
+ BITS_TO_LONGS(ep->apio_wins),
+ sizeof(long),
+ GFP_KERNEL);
+ if (!ep->apio_wins_map)
+ return -ENOMEM;
+
+ addr = devm_kcalloc(dev, ep->apio_wins, sizeof(phys_addr_t),
+ GFP_KERNEL);
+ if (!addr)
+ return -ENOMEM;
+
+ ep->apio_addr = addr;
+
+ mobiveil_pcie_enable_bridge_pio(pcie);
+ mobiveil_pcie_enable_engine_apio(pcie);
+ mobiveil_pcie_enable_engine_ppio(pcie);
+ mobiveil_pcie_enable_msi_ep(pcie);
+
+ epc = devm_pci_epc_create(dev, &epc_ops);
+ if (IS_ERR(epc)) {
+ dev_err(dev, "Failed to create epc device\n");
+ return PTR_ERR(epc);
+ }
+
+ ep->epc = epc;
+ epc_set_drvdata(epc, ep);
+
+ ret = of_property_read_u8(np, "max-functions", &epc->max_functions);
+ if (ret < 0)
+ epc->max_functions = 1;
+
+ if (ep->ops->ep_init)
+ ep->ops->ep_init(ep);
+
+ ret = __pci_epc_mem_init(epc, ep->phys_base, ep->addr_size,
+ ep->page_size);
+ if (ret < 0) {
+ dev_err(dev, "Failed to initialize address space\n");
+ return ret;
+ }
+
+ ep->msi_mem = pci_epc_mem_alloc_addr(epc, &ep->msi_mem_phys,
+ epc->mem->page_size);
+ if (!ep->msi_mem) {
+ dev_err(dev, "Failed to reserve memory for MSI/MSI-X\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
diff --git a/drivers/pci/controller/mobiveil/pcie-mobiveil.c b/drivers/pci/controller/mobiveil/pcie-mobiveil.c
index 94b23be..6d47164 100644
--- a/drivers/pci/controller/mobiveil/pcie-mobiveil.c
+++ b/drivers/pci/controller/mobiveil/pcie-mobiveil.c
@@ -168,18 +168,12 @@ void program_ib_windows(struct mobiveil_pcie *pcie, int win_num, u64 cpu_addr,
/*
* routine to program the outbound windows
*/
-void program_ob_windows(struct mobiveil_pcie *pcie, int win_num, u64 cpu_addr,
- u64 pci_addr, u32 type, u64 size)
+void __program_ob_windows(struct mobiveil_pcie *pcie, u8 func_no, int win_num,
+ u64 cpu_addr, u64 pci_addr, u32 type, u64 size)
{
u32 value;
u64 size64 = ~(size - 1);

- if (win_num >= pcie->apio_wins) {
- dev_err(&pcie->pdev->dev,
- "ERROR: max outbound windows reached !\n");
- return;
- }
-
/*
* program Enable Bit to 1, Type Bit to (00) base 2, AXI Window Size Bit
* to 4 KB in PAB_AXI_AMAP_CTRL register
@@ -192,6 +186,7 @@ void program_ob_windows(struct mobiveil_pcie *pcie, int win_num, u64 cpu_addr,

csr_writel(pcie, upper_32_bits(size64), PAB_EXT_AXI_AMAP_SIZE(win_num));

+ csr_writel(pcie, func_no, PAB_AXI_AMAP_PCI_HDR_PARAM(win_num));
/*
* program AXI window base with appropriate value in
* PAB_AXI_AMAP_AXI_WIN0 register
@@ -205,10 +200,98 @@ void program_ob_windows(struct mobiveil_pcie *pcie, int win_num, u64 cpu_addr,
PAB_AXI_AMAP_PEX_WIN_L(win_num));
csr_writel(pcie, upper_32_bits(pci_addr),
PAB_AXI_AMAP_PEX_WIN_H(win_num));
+}
+
+void program_ob_windows(struct mobiveil_pcie *pcie, int win_num, u64 cpu_addr,
+ u64 pci_addr, u32 type, u64 size)
+{
+ if (win_num >= pcie->apio_wins) {
+ dev_err(&pcie->pdev->dev,
+ "ERROR: max outbound windows reached !\n");
+ return;
+ }
+
+ __program_ob_windows(pcie, 0, win_num, cpu_addr,
+ pci_addr, type, size);

pcie->ob_wins_configured++;
}

+void program_ob_windows_ep(struct mobiveil_pcie *pcie, u8 func_no, int win_num,
+ u64 cpu_addr, u64 pci_addr, u32 type, u64 size)
+{
+ if (size & (size - 1))
+ size = 1 << (1 + ilog2(size));
+
+ __program_ob_windows(pcie, func_no, win_num, cpu_addr,
+ pci_addr, type, size);
+}
+
+void program_ib_windows_ep(struct mobiveil_pcie *pcie, u8 func_no,
+ int bar, u64 phys)
+{
+ csr_writel(pcie, upper_32_bits(phys),
+ PAB_EXT_PEX_BAR_AMAP(func_no, bar));
+ csr_writel(pcie, lower_32_bits(phys) | PEX_BAR_AMAP_EN,
+ PAB_PEX_BAR_AMAP(func_no, bar));
+}
+
+void mobiveil_pcie_disable_ib_win_ep(struct mobiveil_pcie *pcie,
+ u8 func_no, u8 bar)
+{
+ u32 val;
+
+ val = csr_readl(pcie, PAB_PEX_BAR_AMAP(func_no, bar));
+ val &= ~(1 << 0);
+ csr_writel(pcie, val, PAB_PEX_BAR_AMAP(func_no, bar));
+}
+
+void mobiveil_pcie_disable_ob_win(struct mobiveil_pcie *pcie, int win_num)
+{
+ u32 val;
+
+ val = csr_readl(pcie, PAB_AXI_AMAP_CTRL(win_num));
+ val &= ~(1 << WIN_ENABLE_SHIFT);
+ csr_writel(pcie, val, PAB_AXI_AMAP_CTRL(win_num));
+}
+
+void mobiveil_pcie_enable_bridge_pio(struct mobiveil_pcie *pcie)
+{
+ u32 val;
+
+ val = csr_readl(pcie, PAB_CTRL);
+ val |= 1 << AMBA_PIO_ENABLE_SHIFT;
+ val |= 1 << PEX_PIO_ENABLE_SHIFT;
+ csr_writel(pcie, val, PAB_CTRL);
+}
+
+void mobiveil_pcie_enable_engine_apio(struct mobiveil_pcie *pcie)
+{
+ u32 val;
+
+ val = csr_readl(pcie, PAB_AXI_PIO_CTRL);
+ val |= APIO_EN_MASK;
+ csr_writel(pcie, val, PAB_AXI_PIO_CTRL);
+}
+
+void mobiveil_pcie_enable_engine_ppio(struct mobiveil_pcie *pcie)
+{
+ u32 val;
+
+ val = csr_readl(pcie, PAB_PEX_PIO_CTRL);
+ val |= 1 << PIO_ENABLE_SHIFT;
+ csr_writel(pcie, val, PAB_PEX_PIO_CTRL);
+}
+
+void mobiveil_pcie_enable_msi_ep(struct mobiveil_pcie *pcie)
+{
+ u32 val;
+
+ val = csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
+ val |= PAB_INTP_PAMR;
+ csr_writel(pcie, val, PAB_INTP_AMBA_MISC_ENB);
+}
+
int mobiveil_bringup_link(struct mobiveil_pcie *pcie)
{
int retries;
diff --git a/drivers/pci/controller/mobiveil/pcie-mobiveil.h b/drivers/pci/controller/mobiveil/pcie-mobiveil.h
index b7e9603..7308fa4 100644
--- a/drivers/pci/controller/mobiveil/pcie-mobiveil.h
+++ b/drivers/pci/controller/mobiveil/pcie-mobiveil.h
@@ -15,8 +15,12 @@
#include <linux/pci.h>
#include <linux/irq.h>
#include <linux/msi.h>
+#include <linux/pci-epc.h>
+#include <linux/pci-epf.h>
+
#include "../../pci.h"

+#define MAX_IATU_OUT 256
/* register offsets and bit positions */

/*
@@ -42,6 +46,9 @@
#define PAGE_SEL_MASK 0x3f
#define PAGE_LO_MASK 0x3ff
#define PAGE_SEL_OFFSET_SHIFT 10
+#define FUNC_SEL_SHIFT 19
+#define FUNC_SEL_MASK 0x1ff
+#define MSI_SW_CTRL_EN BIT(29)

#define PAB_ACTIVITY_STAT 0x81c

@@ -52,6 +59,7 @@
#define PIO_ENABLE_SHIFT 0

#define PAB_INTP_AMBA_MISC_ENB 0x0b0c
+#define PAB_INTP_PAMR BIT(0)
#define PAB_INTP_AMBA_MISC_STAT 0x0b1c
#define PAB_INTP_RESET BIT(1)
#define PAB_INTP_MSI BIT(3)
@@ -72,6 +80,8 @@
#define WIN_TYPE_MASK 0x3
#define WIN_SIZE_MASK 0xfffffc00

+#define PAB_AXI_AMAP_PCI_HDR_PARAM(win) PAB_EXT_REG_ADDR(0x5ba0, win)
+
#define PAB_EXT_AXI_AMAP_SIZE(win) PAB_EXT_REG_ADDR(0xbaf0, win)

#define PAB_EXT_AXI_AMAP_AXI_WIN(win) PAB_EXT_REG_ADDR(0x80a0, win)
@@ -101,6 +111,18 @@
#define PAB_PEX_AMAP_PEX_WIN_L(win) PAB_REG_ADDR(0x4ba8, win)
#define PAB_PEX_AMAP_PEX_WIN_H(win) PAB_REG_ADDR(0x4bac, win)

+/* PPIO WINs EP mode */
+#define PAB_PEX_BAR_AMAP(func, bar) (0x1ba0 + 0x20 * func + 4 * bar)
+#define PAB_EXT_PEX_BAR_AMAP(func, bar) (0x84a0 + 0x20 * func + 4 * bar)
+#define PEX_BAR_AMAP_EN BIT(0)
+
+#define PAB_MSIX_TABLE_PBA_ACCESS 0xD000
+
+#define GPEX_BAR_ENABLE 0x4D4
+#define GPEX_BAR_SIZE_LDW 0x4D8
+#define GPEX_BAR_SIZE_UDW 0x4DC
+#define GPEX_BAR_SELECT 0x4E0
+
/* starting offset of INTX bits in status register */
#define PAB_INTX_START 5

@@ -138,6 +160,7 @@
((off >> PAGE_SEL_OFFSET_SHIFT) & PAGE_SEL_MASK)

struct mobiveil_pcie;
+struct mobiveil_pcie_ep;

struct mobiveil_msi { /* MSI information */
struct mutex lock; /* protect bitmap variable */
@@ -170,6 +193,28 @@ struct mobiveil_pab_ops {
int (*host_init)(struct mobiveil_pcie *pcie);
};

+struct mobiveil_pcie_ep_ops {
+ void (*ep_init)(struct mobiveil_pcie_ep *ep);
+ int (*raise_irq)(struct mobiveil_pcie_ep *ep, u8 func_no,
+ enum pci_epc_irq_type type, u16 interrupt_num);
+ const struct pci_epc_features* (*get_features)
+ (struct mobiveil_pcie_ep *ep);
+};
+
+struct mobiveil_pcie_ep {
+ struct pci_epc *epc;
+ const struct mobiveil_pcie_ep_ops *ops;
+ phys_addr_t phys_base;
+ size_t addr_size;
+ size_t page_size;
+ phys_addr_t *apio_addr;
+ unsigned long *apio_wins_map;
+ u32 apio_wins;
+ void __iomem *msi_mem;
+ phys_addr_t msi_mem_phys;
+ u8 bar_num;
+};
+
struct mobiveil_pcie {
struct platform_device *pdev;
struct list_head *resources;
@@ -183,8 +228,12 @@ struct mobiveil_pcie {
const struct mobiveil_pab_ops *ops;
struct root_port rp;
struct pci_host_bridge *bridge;
+ struct mobiveil_pcie_ep ep;
};

+#define to_mobiveil_pcie_from_ep(endpoint) \
+ container_of((endpoint), struct mobiveil_pcie, ep)
+
int mobiveil_pcie_host_probe(struct mobiveil_pcie *pcie);
int mobiveil_host_init(struct mobiveil_pcie *pcie, bool reinit);
bool mobiveil_pcie_link_up(struct mobiveil_pcie *pcie);
@@ -226,4 +275,23 @@ static inline void csr_writeb(struct mobiveil_pcie *pcie, u32 val, u32 off)
csr_write(pcie, val, off, 0x1);
}

+void program_ib_windows_ep(struct mobiveil_pcie *pcie, u8 func_no,
+ int bar, u64 phys);
+void program_ob_windows_ep(struct mobiveil_pcie *pcie, u8 func_num, int win_num,
+ u64 cpu_addr, u64 pci_addr, u32 type, u64 size);
+void mobiveil_pcie_disable_ib_win_ep(struct mobiveil_pcie *pci,
+ u8 func_no, u8 bar);
+void mobiveil_pcie_disable_ob_win(struct mobiveil_pcie *pcie, int win_num);
+int mobiveil_pcie_ep_init(struct mobiveil_pcie_ep *ep);
+int mobiveil_pcie_ep_raise_legacy_irq(struct mobiveil_pcie_ep *ep, u8 func_no);
+int mobiveil_pcie_ep_raise_msi_irq(struct mobiveil_pcie_ep *ep, u8 func_no,
+ u8 interrupt_num);
+int mobiveil_pcie_ep_raise_msix_irq(struct mobiveil_pcie_ep *ep, u8 func_no,
+ u16 interrupt_num);
+void mobiveil_pcie_ep_reset_bar(struct mobiveil_pcie *pci, u8 bar);
+u8 mobiveil_pcie_ep_get_bar_num(struct mobiveil_pcie_ep *ep, u8 func_no);
+void mobiveil_pcie_enable_bridge_pio(struct mobiveil_pcie *pci);
+void mobiveil_pcie_enable_engine_apio(struct mobiveil_pcie *pci);
+void mobiveil_pcie_enable_engine_ppio(struct mobiveil_pcie *pci);
+void mobiveil_pcie_enable_msi_ep(struct mobiveil_pcie *pci);
#endif /* _PCIE_MOBIVEIL_H */
--
2.9.5

2019-10-15 11:16:37

by Bao Xiaowei

[permalink] [raw]
Subject: [PATCH v2 2/6] dt-bindings: Add DT binding for PCIE GEN4 EP of the layerscape

Add the documentation for the Device Tree binding of the layerscape
PCIe GEN4 controller with EP mode.

Signed-off-by: Xiaowei Bao <[email protected]>
---
v2:
- remove the status entry in EP Example.

.../bindings/pci/layerscape-pcie-gen4.txt | 27 +++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/pci/layerscape-pcie-gen4.txt b/Documentation/devicetree/bindings/pci/layerscape-pcie-gen4.txt
index b40fb5d..06f9309 100644
--- a/Documentation/devicetree/bindings/pci/layerscape-pcie-gen4.txt
+++ b/Documentation/devicetree/bindings/pci/layerscape-pcie-gen4.txt
@@ -3,6 +3,8 @@ NXP Layerscape PCIe Gen4 controller
This PCIe controller is based on the Mobiveil PCIe IP and thus inherits all
the common properties defined in mobiveil-pcie.txt.

+HOST MODE
+=========
Required properties:
- compatible: should contain the platform identifier such as:
"fsl,lx2160a-pcie"
@@ -23,7 +25,20 @@ Required properties:
- msi-parent : See the generic MSI binding described in
Documentation/devicetree/bindings/interrupt-controller/msi.txt.

-Example:
+DEVICE MODE
+=========
+Required properties:
+- compatible: should contain the platform identifier such as:
+ "fsl,lx2160a-pcie-ep"
+- reg: base addresses and lengths of the PCIe controller register blocks.
+ "regs": PCIe controller registers.
+ "addr_space" EP device CPU address.
+- apio-wins: number of requested apio outbound windows.
+
+Optional Property:
+- max-functions: Maximum number of functions that can be configured (default 1).
+
+RC Example:

pcie@3400000 {
compatible = "fsl,lx2160a-pcie";
@@ -50,3 +65,13 @@ Example:
<0000 0 0 3 &gic 0 0 GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>,
<0000 0 0 4 &gic 0 0 GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
};
+
+EP Example:
+
+ pcie_ep@3400000 {
+ compatible = "fsl,lx2160a-pcie-ep";
+ reg = <0x00 0x03400000 0x0 0x00100000
+ 0x80 0x00000000 0x8 0x00000000>;
+ reg-names = "regs", "addr_space";
+ apio-wins = <8>;
+ };
--
2.9.5

2019-10-15 11:16:58

by Bao Xiaowei

[permalink] [raw]
Subject: [PATCH v2 3/6] PCI: mobiveil: Add PCIe Gen4 EP driver for NXP Layerscape SoCs

This PCIe controller is based on the Mobiveil GPEX IP, it work in EP
mode if select this config opteration.

Signed-off-by: Xiaowei Bao <[email protected]>
---
v2:
- Modify the Copyright.

MAINTAINERS | 2 +
drivers/pci/controller/mobiveil/Kconfig | 17 ++-
drivers/pci/controller/mobiveil/Makefile | 1 +
.../controller/mobiveil/pcie-layerscape-gen4-ep.c | 156 +++++++++++++++++++++
4 files changed, 173 insertions(+), 3 deletions(-)
create mode 100644 drivers/pci/controller/mobiveil/pcie-layerscape-gen4-ep.c

diff --git a/MAINTAINERS b/MAINTAINERS
index b997056..0858b54 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12363,11 +12363,13 @@ F: drivers/pci/controller/dwc/*layerscape*

PCI DRIVER FOR NXP LAYERSCAPE GEN4 CONTROLLER
M: Hou Zhiqiang <[email protected]>
+M: Xiaowei Bao <[email protected]>
L: [email protected]
L: [email protected]
S: Maintained
F: Documentation/devicetree/bindings/pci/layerscape-pcie-gen4.txt
F: drivers/pci/controller/mobibeil/pcie-layerscape-gen4.c
+F: drivers/pci/controller/mobiveil/pcie-layerscape-gen4-ep.c

PCI DRIVER FOR GENERIC OF HOSTS
M: Will Deacon <[email protected]>
diff --git a/drivers/pci/controller/mobiveil/Kconfig b/drivers/pci/controller/mobiveil/Kconfig
index 2054950..0696b6e 100644
--- a/drivers/pci/controller/mobiveil/Kconfig
+++ b/drivers/pci/controller/mobiveil/Kconfig
@@ -27,13 +27,24 @@ config PCIE_MOBIVEIL_PLAT
for address translation and it is a PCIe Gen4 IP.

config PCIE_LAYERSCAPE_GEN4
- bool "Freescale Layerscape PCIe Gen4 controller"
+ bool "Freescale Layerscpe PCIe Gen4 controller in RC mode"
depends on PCI
depends on OF && (ARM64 || ARCH_LAYERSCAPE)
depends on PCI_MSI_IRQ_DOMAIN
select PCIE_MOBIVEIL_HOST
help
Say Y here if you want PCIe Gen4 controller support on
- Layerscape SoCs. The PCIe controller can work in RC or
- EP mode according to RCW[HOST_AGT_PEX] setting.
+ Layerscape SoCs. And the PCIe controller work in RC mode
+ by setting the RCW[HOST_AGT_PEX] to 0.
+
+config PCIE_LAYERSCAPE_GEN4_EP
+ bool "Freescale Layerscpe PCIe Gen4 controller in EP mode"
+ depends on PCI
+ depends on OF && (ARM64 || ARCH_LAYERSCAPE)
+ depends on PCI_ENDPOINT
+ select PCIE_MOBIVEIL_EP
+ help
+ Say Y here if you want PCIe Gen4 controller support on
+ Layerscape SoCs. And the PCIe controller work in EP mode
+ by setting the RCW[HOST_AGT_PEX] to 1.
endmenu
diff --git a/drivers/pci/controller/mobiveil/Makefile b/drivers/pci/controller/mobiveil/Makefile
index 686d41f..6f54856 100644
--- a/drivers/pci/controller/mobiveil/Makefile
+++ b/drivers/pci/controller/mobiveil/Makefile
@@ -4,3 +4,4 @@ obj-$(CONFIG_PCIE_MOBIVEIL_HOST) += pcie-mobiveil-host.o
obj-$(CONFIG_PCIE_MOBIVEIL_EP) += pcie-mobiveil-ep.o
obj-$(CONFIG_PCIE_MOBIVEIL_PLAT) += pcie-mobiveil-plat.o
obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie-layerscape-gen4.o
+obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4_EP) += pcie-layerscape-gen4-ep.o
diff --git a/drivers/pci/controller/mobiveil/pcie-layerscape-gen4-ep.c b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4-ep.c
new file mode 100644
index 0000000..56603ea
--- /dev/null
+++ b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4-ep.c
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PCIe controller EP driver for Freescale Layerscape SoCs
+ *
+ * Copyright 2019 NXP
+ *
+ * Author: Xiaowei Bao <[email protected]>
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/of_pci.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/resource.h>
+
+#include "pcie-mobiveil.h"
+
+#define PCIE_LX2_BAR_NUM 4
+
+#define to_ls_pcie_g4_ep(x) dev_get_drvdata((x)->dev)
+
+struct ls_pcie_g4_ep {
+ struct mobiveil_pcie *mv_pci;
+};
+
+static const struct of_device_id ls_pcie_g4_ep_of_match[] = {
+ { .compatible = "fsl,lx2160a-pcie-ep",},
+ { },
+};
+
+static const struct pci_epc_features ls_pcie_g4_epc_features = {
+ .linkup_notifier = false,
+ .msi_capable = true,
+ .msix_capable = true,
+ .reserved_bar = (1 << BAR_4) | (1 << BAR_5),
+};
+
+static const struct pci_epc_features*
+ls_pcie_g4_ep_get_features(struct mobiveil_pcie_ep *ep)
+{
+ return &ls_pcie_g4_epc_features;
+}
+
+static void ls_pcie_g4_ep_init(struct mobiveil_pcie_ep *ep)
+{
+ struct mobiveil_pcie *mv_pci = to_mobiveil_pcie_from_ep(ep);
+ int win_idx;
+ u8 bar;
+
+ ep->bar_num = PCIE_LX2_BAR_NUM;
+
+ for (bar = BAR_0; bar < ep->epc->max_functions * ep->bar_num; bar++)
+ mobiveil_pcie_ep_reset_bar(mv_pci, bar);
+
+ for (win_idx = 0; win_idx < ep->apio_wins; win_idx++)
+ mobiveil_pcie_disable_ob_win(mv_pci, win_idx);
+}
+
+static int ls_pcie_g4_ep_raise_irq(struct mobiveil_pcie_ep *ep, u8 func_no,
+ enum pci_epc_irq_type type,
+ u16 interrupt_num)
+{
+ struct mobiveil_pcie *mv_pci = to_mobiveil_pcie_from_ep(ep);
+
+ switch (type) {
+ case PCI_EPC_IRQ_LEGACY:
+ return mobiveil_pcie_ep_raise_legacy_irq(ep, func_no);
+ case PCI_EPC_IRQ_MSI:
+ return mobiveil_pcie_ep_raise_msi_irq(ep, func_no,
+ interrupt_num);
+ case PCI_EPC_IRQ_MSIX:
+ return mobiveil_pcie_ep_raise_msix_irq(ep, func_no,
+ interrupt_num);
+ default:
+ dev_err(&mv_pci->pdev->dev, "UNKNOWN IRQ type\n");
+ }
+
+ return 0;
+}
+
+static const struct mobiveil_pcie_ep_ops pcie_ep_ops = {
+ .ep_init = ls_pcie_g4_ep_init,
+ .raise_irq = ls_pcie_g4_ep_raise_irq,
+ .get_features = ls_pcie_g4_ep_get_features,
+};
+
+static int __init ls_pcie_gen4_add_pcie_ep(struct ls_pcie_g4_ep *ls_ep,
+ struct platform_device *pdev)
+{
+ struct mobiveil_pcie *mv_pci = ls_ep->mv_pci;
+ struct device *dev = &pdev->dev;
+ struct mobiveil_pcie_ep *ep;
+ struct resource *res;
+ int ret;
+
+ ep = &mv_pci->ep;
+ ep->ops = &pcie_ep_ops;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
+ if (!res)
+ return -EINVAL;
+
+ ep->phys_base = res->start;
+ ep->addr_size = resource_size(res);
+
+ ret = mobiveil_pcie_ep_init(ep);
+ if (ret) {
+ dev_err(dev, "failed to initialize layerscape endpoint\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int __init ls_pcie_g4_ep_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mobiveil_pcie *mv_pci;
+ struct ls_pcie_g4_ep *ls_ep;
+ struct resource *res;
+ int ret;
+
+ ls_ep = devm_kzalloc(dev, sizeof(*ls_ep), GFP_KERNEL);
+ if (!ls_ep)
+ return -ENOMEM;
+
+ mv_pci = devm_kzalloc(dev, sizeof(*mv_pci), GFP_KERNEL);
+ if (!mv_pci)
+ return -ENOMEM;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
+ mv_pci->csr_axi_slave_base = devm_pci_remap_cfg_resource(dev, res);
+ if (IS_ERR(mv_pci->csr_axi_slave_base))
+ return PTR_ERR(mv_pci->csr_axi_slave_base);
+
+ mv_pci->pdev = pdev;
+ ls_ep->mv_pci = mv_pci;
+
+ platform_set_drvdata(pdev, ls_ep);
+
+ ret = ls_pcie_gen4_add_pcie_ep(ls_ep, pdev);
+
+ return ret;
+}
+
+static struct platform_driver ls_pcie_g4_ep_driver = {
+ .driver = {
+ .name = "layerscape-pcie-gen4-ep",
+ .of_match_table = ls_pcie_g4_ep_of_match,
+ .suppress_bind_attrs = true,
+ },
+};
+builtin_platform_driver_probe(ls_pcie_g4_ep_driver, ls_pcie_g4_ep_probe);
--
2.9.5

2019-10-18 22:17:15

by Rob Herring

[permalink] [raw]
Subject: Re: [PATCH v2 2/6] dt-bindings: Add DT binding for PCIE GEN4 EP of the layerscape

On Tue, Oct 15, 2019 at 04:36:58PM +0800, Xiaowei Bao wrote:
> Add the documentation for the Device Tree binding of the layerscape
> PCIe GEN4 controller with EP mode.
>
> Signed-off-by: Xiaowei Bao <[email protected]>
> ---
> v2:
> - remove the status entry in EP Example.
>
> .../bindings/pci/layerscape-pcie-gen4.txt | 27 +++++++++++++++++++++-
> 1 file changed, 26 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/devicetree/bindings/pci/layerscape-pcie-gen4.txt b/Documentation/devicetree/bindings/pci/layerscape-pcie-gen4.txt
> index b40fb5d..06f9309 100644
> --- a/Documentation/devicetree/bindings/pci/layerscape-pcie-gen4.txt
> +++ b/Documentation/devicetree/bindings/pci/layerscape-pcie-gen4.txt
> @@ -3,6 +3,8 @@ NXP Layerscape PCIe Gen4 controller
> This PCIe controller is based on the Mobiveil PCIe IP and thus inherits all
> the common properties defined in mobiveil-pcie.txt.
>
> +HOST MODE
> +=========
> Required properties:
> - compatible: should contain the platform identifier such as:
> "fsl,lx2160a-pcie"
> @@ -23,7 +25,20 @@ Required properties:
> - msi-parent : See the generic MSI binding described in
> Documentation/devicetree/bindings/interrupt-controller/msi.txt.
>
> -Example:
> +DEVICE MODE
> +=========
> +Required properties:
> +- compatible: should contain the platform identifier such as:
> + "fsl,lx2160a-pcie-ep"
> +- reg: base addresses and lengths of the PCIe controller register blocks.
> + "regs": PCIe controller registers.
> + "addr_space" EP device CPU address.
> +- apio-wins: number of requested apio outbound windows.
> +
> +Optional Property:
> +- max-functions: Maximum number of functions that can be configured (default 1).
> +
> +RC Example:
>
> pcie@3400000 {
> compatible = "fsl,lx2160a-pcie";
> @@ -50,3 +65,13 @@ Example:
> <0000 0 0 3 &gic 0 0 GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>,
> <0000 0 0 4 &gic 0 0 GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
> };
> +
> +EP Example:
> +
> + pcie_ep@3400000 {

To repeat my previous comment:

pcie-endpoint@...

> + compatible = "fsl,lx2160a-pcie-ep";
> + reg = <0x00 0x03400000 0x0 0x00100000
> + 0x80 0x00000000 0x8 0x00000000>;
> + reg-names = "regs", "addr_space";
> + apio-wins = <8>;
> + };
> --
> 2.9.5
>

2019-10-18 22:29:34

by Bao Xiaowei

[permalink] [raw]
Subject: RE: [PATCH v2 2/6] dt-bindings: Add DT binding for PCIE GEN4 EP of the layerscape



> -----Original Message-----
> From: Rob Herring <[email protected]>
> Sent: 2019??10??18?? 3:03
> To: Xiaowei Bao <[email protected]>
> Cc: Z.q. Hou <[email protected]>; [email protected];
> [email protected]; [email protected]; Leo Li
> <[email protected]>; [email protected]; [email protected]; M.h. Lian
> <[email protected]>; [email protected]; Mingkai Hu
> <[email protected]>; [email protected];
> [email protected]; [email protected];
> [email protected]
> Subject: Re: [PATCH v2 2/6] dt-bindings: Add DT binding for PCIE GEN4 EP of
> the layerscape
>
> On Tue, Oct 15, 2019 at 04:36:58PM +0800, Xiaowei Bao wrote:
> > Add the documentation for the Device Tree binding of the layerscape
> > PCIe GEN4 controller with EP mode.
> >
> > Signed-off-by: Xiaowei Bao <[email protected]>
> > ---
> > v2:
> > - remove the status entry in EP Example.
> >
> > .../bindings/pci/layerscape-pcie-gen4.txt | 27
> +++++++++++++++++++++-
> > 1 file changed, 26 insertions(+), 1 deletion(-)
> >
> > diff --git
> > a/Documentation/devicetree/bindings/pci/layerscape-pcie-gen4.txt
> > b/Documentation/devicetree/bindings/pci/layerscape-pcie-gen4.txt
> > index b40fb5d..06f9309 100644
> > --- a/Documentation/devicetree/bindings/pci/layerscape-pcie-gen4.txt
> > +++ b/Documentation/devicetree/bindings/pci/layerscape-pcie-gen4.txt
> > @@ -3,6 +3,8 @@ NXP Layerscape PCIe Gen4 controller This PCIe
> > controller is based on the Mobiveil PCIe IP and thus inherits all the
> > common properties defined in mobiveil-pcie.txt.
> >
> > +HOST MODE
> > +=========
> > Required properties:
> > - compatible: should contain the platform identifier such as:
> > "fsl,lx2160a-pcie"
> > @@ -23,7 +25,20 @@ Required properties:
> > - msi-parent : See the generic MSI binding described in
> > Documentation/devicetree/bindings/interrupt-controller/msi.txt.
> >
> > -Example:
> > +DEVICE MODE
> > +=========
> > +Required properties:
> > +- compatible: should contain the platform identifier such as:
> > + "fsl,lx2160a-pcie-ep"
> > +- reg: base addresses and lengths of the PCIe controller register blocks.
> > + "regs": PCIe controller registers.
> > + "addr_space" EP device CPU address.
> > +- apio-wins: number of requested apio outbound windows.
> > +
> > +Optional Property:
> > +- max-functions: Maximum number of functions that can be configured
> (default 1).
> > +
> > +RC Example:
> >
> > pcie@3400000 {
> > compatible = "fsl,lx2160a-pcie";
> > @@ -50,3 +65,13 @@ Example:
> > <0000 0 0 3 &gic 0 0 GIC_SPI 111
> IRQ_TYPE_LEVEL_HIGH>,
> > <0000 0 0 4 &gic 0 0 GIC_SPI 112
> IRQ_TYPE_LEVEL_HIGH>;
> > };
> > +
> > +EP Example:
> > +
> > + pcie_ep@3400000 {
>
> To repeat my previous comment:

Sorry, I missed this comment.

Thanks
Xiaowei

>
> pcie-endpoint@...
>
> > + compatible = "fsl,lx2160a-pcie-ep";
> > + reg = <0x00 0x03400000 0x0 0x00100000
> > + 0x80 0x00000000 0x8 0x00000000>;
> > + reg-names = "regs", "addr_space";
> > + apio-wins = <8>;
> > + };
> > --
> > 2.9.5
> >