* [PATCH v7 00/13] Enhance the PCIe controller driver for next generation controllers
@ 2025-08-13 4:23 hans.zhang
2025-08-13 4:23 ` [PATCH v7 01/13] PCI: cadence: Add support for modules for cadence controller builds hans.zhang
` (13 more replies)
0 siblings, 14 replies; 40+ messages in thread
From: hans.zhang @ 2025-08-13 4:23 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kw, mani, robh, kwilczynski, krzk+dt,
conor+dt
Cc: mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel,
Hans Zhang
From: Hans Zhang <hans.zhang@cixtech.com>
---
Dear Maintainers,
This series is Cadence's HPA PCIe IP and the Root Port driver of our
CIX sky1. Please help review. Thank you very much.
---
Enhances the exiting Cadence PCIe controller drivers to support
HPA (High Performance Architecture) Cadence PCIe controllers.
The patch set enhances the Cadence PCIe driver for HPA support.
The header files are separated out for legacy and high performance
register maps, register address and bit definitions. The driver
read register and write register functions for HPA take the
updated offset stored from the platform driver to access the registers.
As part of refactoring of the code, few new files are added to the
driver by splitting the existing files.
This helps SoC vendor who change the address map within PCIe controller
in their designs. Setting the menuconfig appropriately will allow
selection between RP and/or EP PCIe controller support. The support
will include Legacy and HPA for the selected configuration.
The TI SoC continues to be supported with the changes incorporated.
The changes address the review comments in the previous patches where
the need to move away from "ops" pointers used in current implementation
and separate out the Legacy and HPA driver implementation was stressed.
The scripts/checkpatch.pl has been run on the patches with and without
--strict. With the --strict option, 4 checks are generated on 2 patch,
which can be ignored. There are no code fixes required for these checks.
All other checks generated by ./scripts/checkpatch.pl --strict can be
ignored.
---
Changes for v7
- Rebase to v6.17-rc1.
- Fixed the error issue of cix,sky1-pcie-host.yaml make dt_binding_check.
- CIX SKY1 Root Port driver compilation error issue: Add header
file, Kconfig select PCI_ECAM.
Changes for v6
- Based on the latest linux master branch.
- The IP level DTS changes for HPA have been removed as the SoC
level DTS is added
- Virtual FPGA platform is also removed as the CiX SoC support is
added
- Fix the issue of dt bindings
- Modify the order of PCIe node attributes in sky1-orion-o6.dts
and delete unnecessary attributes.
- Continue to simplify the RC driver.
- The patch of the Cix Sky1 platform has been accepted and merged into the linux master branch.
https://patchwork.kernel.org/project/linux-arm-kernel/cover/20250721144500.302202-1-peter.chen@cixtech.com/
Changes for v5
- Header and code files separated for library functions(common
functions used by both architectures) and Legacy and HPA.
- Few new files added as part of refactoring
- No checks for "is_hpa" as the functions have been separated
out
- Review comments from previous patches have been addressed
- Add region 0 for ECAM and region 1 for message.
- Add CIX sky1 PCIe drivers. Submissions based on the following v9 patches:
https://patchwork.kernel.org/project/linux-arm-kernel/cover/20250609031627.1605851-1-peter.chen@cixtech.com/
Cix Sky1 base dts review link to show its review status:
https://lore.kernel.org/all/20250609031627.1605851-9-peter.chen@cixtech.com/
The test log on the Orion O6 board is as follows:
root@cix-localhost:~# lspci
0000:c0:00.0 PCI bridge: Device 1f6c:0001
0000:c1:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. Device 8126 (rev 01)
0001:90:00.0 PCI bridge: Device 1f6c:0001
0001:91:00.0 Non-Volatile memory controller: Samsung Electronics Co Ltd NVMe SSD Controller PM9A1/PM9A3/980PRO
0002:60:00.0 PCI bridge: Device 1f6c:0001
0002:61:00.0 Network controller: Realtek Semiconductor Co., Ltd. RTL8852BE PCIe 802.11ax Wireless Network Controller
0003:00:00.0 PCI bridge: Device 1f6c:0001
0003:01:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. Device 8126 (rev 01)
0004:30:00.0 PCI bridge: Device 1f6c:0001
0004:31:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. Device 8126 (rev 01)
root@cix-localhost:~# uname -a
Linux cix-localhost 6.16.0-rc1-00023-gbaa962a95a28 #138 SMP PREEMPT Fri Jun 27 16:43:41 CST 2025 aarch64 GNU/Linux
root@cix-localhost:~# cat /etc/issue
Debian GNU/Linux 12 \n \l
Changes for v4
- Add header file bitfield.h to pcie-cadence.h
- Addressed the following review comments
Merged the TI patch as it
Removed initialization of struct variables to '0'
Changes for v3
- Patch version v3 added to the subject
- Use HPA tag for architecture descriptions
- Remove bug related changes to be submitted later as a separate
patch
- Two patches merged from the last series to ensure readability to
address the review comments
- Fix several description related issues, coding style issues and
some misleading comments
- Remove cpu_addr_fixup() functions
---
Hans Zhang (6):
dt-bindings: PCI: Add CIX Sky1 PCIe Root Complex bindings
PCI: Add Cix Technology Vendor and Device ID
PCI: sky1: Add PCIe host support for CIX Sky1
MAINTAINERS: add entry for CIX Sky1 PCIe driver
arm64: dts: cix: Add PCIe Root Complex on sky1
arm64: dts: cix: Enable PCIe on the Orion O6 board
Manikandan K Pillai (7):
PCI: cadence: Add support for modules for cadence controller builds
PCI: cadence: Split PCIe controller header file
PCI: cadence: Add register definitions for HPA(High Perf Architecture)
PCI: cadence: Split PCIe EP support into common and specific functions
PCI: cadence: Split PCIe RP support into common and specific functions
PCI: cadence: Split the common functions for PCIe controller support
PCI: cadence: Add support for High Performance Arch(HPA) controller
.../bindings/pci/cix,sky1-pcie-host.yaml | 79 +++
MAINTAINERS | 7 +
arch/arm64/boot/dts/cix/sky1-orion-o6.dts | 20 +
arch/arm64/boot/dts/cix/sky1.dtsi | 121 ++++
drivers/pci/controller/cadence/Kconfig | 19 +-
drivers/pci/controller/cadence/Makefile | 11 +-
drivers/pci/controller/cadence/pci-sky1.c | 294 +++++++++
.../controller/cadence/pcie-cadence-common.c | 142 +++++
.../cadence/pcie-cadence-ep-common.c | 252 ++++++++
.../cadence/pcie-cadence-ep-common.h | 36 ++
.../controller/cadence/pcie-cadence-ep-hpa.c | 528 ++++++++++++++++
.../pci/controller/cadence/pcie-cadence-ep.c | 243 +-------
.../cadence/pcie-cadence-host-common.c | 181 ++++++
.../cadence/pcie-cadence-host-common.h | 25 +
.../cadence/pcie-cadence-host-hpa.c | 586 ++++++++++++++++++
.../controller/cadence/pcie-cadence-host.c | 156 +----
.../cadence/pcie-cadence-hpa-regs.h | 212 +++++++
.../pci/controller/cadence/pcie-cadence-hpa.c | 207 +++++++
.../cadence/pcie-cadence-lga-regs.h | 228 +++++++
.../controller/cadence/pcie-cadence-plat.c | 28 +-
drivers/pci/controller/cadence/pcie-cadence.c | 139 +----
drivers/pci/controller/cadence/pcie-cadence.h | 436 ++++++-------
include/linux/pci_ids.h | 3 +
23 files changed, 3174 insertions(+), 779 deletions(-)
create mode 100644 Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.yaml
create mode 100644 drivers/pci/controller/cadence/pci-sky1.c
create mode 100644 drivers/pci/controller/cadence/pcie-cadence-common.c
create mode 100644 drivers/pci/controller/cadence/pcie-cadence-ep-common.c
create mode 100644 drivers/pci/controller/cadence/pcie-cadence-ep-common.h
create mode 100644 drivers/pci/controller/cadence/pcie-cadence-ep-hpa.c
create mode 100644 drivers/pci/controller/cadence/pcie-cadence-host-common.c
create mode 100644 drivers/pci/controller/cadence/pcie-cadence-host-common.h
create mode 100644 drivers/pci/controller/cadence/pcie-cadence-host-hpa.c
create mode 100644 drivers/pci/controller/cadence/pcie-cadence-hpa-regs.h
create mode 100644 drivers/pci/controller/cadence/pcie-cadence-hpa.c
create mode 100644 drivers/pci/controller/cadence/pcie-cadence-lga-regs.h
base-commit: 8742b2d8935f476449ef37e263bc4da3295c7b58
--
2.49.0
^ permalink raw reply [flat|nested] 40+ messages in thread
* [PATCH v7 01/13] PCI: cadence: Add support for modules for cadence controller builds
2025-08-13 4:23 [PATCH v7 00/13] Enhance the PCIe controller driver for next generation controllers hans.zhang
@ 2025-08-13 4:23 ` hans.zhang
2025-08-14 21:25 ` Bjorn Helgaas
2025-08-13 4:23 ` [PATCH v7 02/13] PCI: cadence: Split PCIe controller header file hans.zhang
` (12 subsequent siblings)
13 siblings, 1 reply; 40+ messages in thread
From: hans.zhang @ 2025-08-13 4:23 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kw, mani, robh, kwilczynski, krzk+dt,
conor+dt
Cc: mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel,
Hans Zhang
From: Manikandan K Pillai <mpillai@cadence.com>
Add support for building PCI cadence platforms as a module.
Signed-off-by: Manikandan K Pillai <mpillai@cadence.com>
Signed-off-by: Hans Zhang <hans.zhang@cixtech.com>
---
drivers/pci/controller/cadence/Kconfig | 6 +++---
drivers/pci/controller/cadence/pcie-cadence-plat.c | 4 ++++
drivers/pci/controller/cadence/pcie-cadence.c | 1 +
3 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/drivers/pci/controller/cadence/Kconfig b/drivers/pci/controller/cadence/Kconfig
index 666e16b6367f..117677a23d68 100644
--- a/drivers/pci/controller/cadence/Kconfig
+++ b/drivers/pci/controller/cadence/Kconfig
@@ -19,10 +19,10 @@ config PCIE_CADENCE_EP
select PCIE_CADENCE
config PCIE_CADENCE_PLAT
- bool
+ tristate
config PCIE_CADENCE_PLAT_HOST
- bool "Cadence platform PCIe controller (host mode)"
+ tristate "Cadence platform PCIe controller (host mode)"
depends on OF
select PCIE_CADENCE_HOST
select PCIE_CADENCE_PLAT
@@ -32,7 +32,7 @@ config PCIE_CADENCE_PLAT_HOST
vendors SoCs.
config PCIE_CADENCE_PLAT_EP
- bool "Cadence platform PCIe controller (endpoint mode)"
+ tristate "Cadence platform PCIe controller (endpoint mode)"
depends on OF
depends on PCI_ENDPOINT
select PCIE_CADENCE_EP
diff --git a/drivers/pci/controller/cadence/pcie-cadence-plat.c b/drivers/pci/controller/cadence/pcie-cadence-plat.c
index 0456845dabb9..c9330aa50a88 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-plat.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-plat.c
@@ -178,3 +178,7 @@ static struct platform_driver cdns_plat_pcie_driver = {
.shutdown = cdns_plat_pcie_shutdown,
};
builtin_platform_driver(cdns_plat_pcie_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cadence PCIe controller platform driver");
+MODULE_AUTHOR("Manikandan K Pillai <mpillai@cadence.com>");
diff --git a/drivers/pci/controller/cadence/pcie-cadence.c b/drivers/pci/controller/cadence/pcie-cadence.c
index 70a19573440e..5603f214f4c7 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.c
+++ b/drivers/pci/controller/cadence/pcie-cadence.c
@@ -279,6 +279,7 @@ const struct dev_pm_ops cdns_pcie_pm_ops = {
NOIRQ_SYSTEM_SLEEP_PM_OPS(cdns_pcie_suspend_noirq,
cdns_pcie_resume_noirq)
};
+EXPORT_SYMBOL_GPL(cdns_pcie_pm_ops);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Cadence PCIe controller driver");
--
2.49.0
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH v7 02/13] PCI: cadence: Split PCIe controller header file
2025-08-13 4:23 [PATCH v7 00/13] Enhance the PCIe controller driver for next generation controllers hans.zhang
2025-08-13 4:23 ` [PATCH v7 01/13] PCI: cadence: Add support for modules for cadence controller builds hans.zhang
@ 2025-08-13 4:23 ` hans.zhang
2025-08-14 21:16 ` Bjorn Helgaas
2025-08-13 4:23 ` [PATCH v7 03/13] PCI: cadence: Add register definitions for HPA(High Perf Architecture) hans.zhang
` (11 subsequent siblings)
13 siblings, 1 reply; 40+ messages in thread
From: hans.zhang @ 2025-08-13 4:23 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kw, mani, robh, kwilczynski, krzk+dt,
conor+dt
Cc: mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel,
Hans Zhang
From: Manikandan K Pillai <mpillai@cadence.com>
Split the Cadence PCIe header file by moving the Legacy(LGA)
controller register definitions to a separate header file for
support of next generation PCIe controller architecture.
Signed-off-by: Manikandan K Pillai <mpillai@cadence.com>
Co-developed-by: Hans Zhang <hans.zhang@cixtech.com>
Signed-off-by: Hans Zhang <hans.zhang@cixtech.com>
---
.../cadence/pcie-cadence-lga-regs.h | 228 ++++++++++++++++++
drivers/pci/controller/cadence/pcie-cadence.h | 226 +----------------
2 files changed, 229 insertions(+), 225 deletions(-)
create mode 100644 drivers/pci/controller/cadence/pcie-cadence-lga-regs.h
diff --git a/drivers/pci/controller/cadence/pcie-cadence-lga-regs.h b/drivers/pci/controller/cadence/pcie-cadence-lga-regs.h
new file mode 100644
index 000000000000..0e88beb77292
--- /dev/null
+++ b/drivers/pci/controller/cadence/pcie-cadence-lga-regs.h
@@ -0,0 +1,228 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (c) 2017 Cadence
+// Cadence PCIe controller driver.
+// Author: Manikandan K Pillai <mpillai@cadence.com>
+
+#ifndef _PCIE_CADENCE_LGA_REGS_H
+#define _PCIE_CADENCE_LGA_REGS_H
+
+#include <linux/bitfield.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 */
+#define CDNS_PCIE_LM_BASE 0x00100000
+
+/* Vendor ID Register */
+#define CDNS_PCIE_LM_ID (CDNS_PCIE_LM_BASE + 0x0044)
+#define CDNS_PCIE_LM_ID_VENDOR_MASK GENMASK(15, 0)
+#define CDNS_PCIE_LM_ID_VENDOR_SHIFT 0
+#define CDNS_PCIE_LM_ID_VENDOR(vid) \
+ (((vid) << CDNS_PCIE_LM_ID_VENDOR_SHIFT) & CDNS_PCIE_LM_ID_VENDOR_MASK)
+#define CDNS_PCIE_LM_ID_SUBSYS_MASK GENMASK(31, 16)
+#define CDNS_PCIE_LM_ID_SUBSYS_SHIFT 16
+#define CDNS_PCIE_LM_ID_SUBSYS(sub) \
+ (((sub) << CDNS_PCIE_LM_ID_SUBSYS_SHIFT) & CDNS_PCIE_LM_ID_SUBSYS_MASK)
+
+/* Root Port Requester ID Register */
+#define CDNS_PCIE_LM_RP_RID (CDNS_PCIE_LM_BASE + 0x0228)
+#define CDNS_PCIE_LM_RP_RID_MASK GENMASK(15, 0)
+#define CDNS_PCIE_LM_RP_RID_SHIFT 0
+#define CDNS_PCIE_LM_RP_RID_(rid) \
+ (((rid) << CDNS_PCIE_LM_RP_RID_SHIFT) & CDNS_PCIE_LM_RP_RID_MASK)
+
+/* Endpoint Bus and Device Number Register */
+#define CDNS_PCIE_LM_EP_ID (CDNS_PCIE_LM_BASE + 0x022C)
+#define CDNS_PCIE_LM_EP_ID_DEV_MASK GENMASK(4, 0)
+#define CDNS_PCIE_LM_EP_ID_DEV_SHIFT 0
+#define CDNS_PCIE_LM_EP_ID_BUS_MASK GENMASK(15, 8)
+#define CDNS_PCIE_LM_EP_ID_BUS_SHIFT 8
+
+/* Endpoint Function f BAR b Configuration Registers */
+#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG(bar, fn) \
+ (((bar) < BAR_4) ? CDNS_PCIE_LM_EP_FUNC_BAR_CFG0(fn) : CDNS_PCIE_LM_EP_FUNC_BAR_CFG1(fn))
+#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG0(fn) \
+ (CDNS_PCIE_LM_BASE + 0x0240 + (fn) * 0x0008)
+#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG1(fn) \
+ (CDNS_PCIE_LM_BASE + 0x0244 + (fn) * 0x0008)
+#define CDNS_PCIE_LM_EP_VFUNC_BAR_CFG(bar, fn) \
+ (((bar) < BAR_4) ? CDNS_PCIE_LM_EP_VFUNC_BAR_CFG0(fn) : CDNS_PCIE_LM_EP_VFUNC_BAR_CFG1(fn))
+#define CDNS_PCIE_LM_EP_VFUNC_BAR_CFG0(fn) \
+ (CDNS_PCIE_LM_BASE + 0x0280 + (fn) * 0x0008)
+#define CDNS_PCIE_LM_EP_VFUNC_BAR_CFG1(fn) \
+ (CDNS_PCIE_LM_BASE + 0x0284 + (fn) * 0x0008)
+#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) \
+ (GENMASK(4, 0) << ((b) * 8))
+#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE(b, a) \
+ (((a) << ((b) * 8)) & CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b))
+#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b) \
+ (GENMASK(7, 5) << ((b) * 8))
+#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, c) \
+ (((c) << ((b) * 8 + 5)) & CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b))
+
+/* Endpoint Function Configuration Register */
+#define CDNS_PCIE_LM_EP_FUNC_CFG (CDNS_PCIE_LM_BASE + 0x02C0)
+
+/* Root Complex BAR Configuration Register */
+#define CDNS_PCIE_LM_RC_BAR_CFG (CDNS_PCIE_LM_BASE + 0x0300)
+#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE_MASK GENMASK(5, 0)
+#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE(a) \
+ (((a) << 0) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE_MASK)
+#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK GENMASK(8, 6)
+#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(c) \
+ (((c) << 6) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK)
+#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE_MASK GENMASK(13, 9)
+#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE(a) \
+ (((a) << 9) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE_MASK)
+#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK GENMASK(16, 14)
+#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(c) \
+ (((c) << 14) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK)
+#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE BIT(17)
+#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_32BITS 0
+#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS BIT(18)
+#define CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE BIT(19)
+#define CDNS_PCIE_LM_RC_BAR_CFG_IO_16BITS 0
+#define CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS BIT(20)
+#define CDNS_PCIE_LM_RC_BAR_CFG_CHECK_ENABLE BIT(31)
+
+/* BAR control values applicable to both Endpoint Function and Root Complex */
+#define CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED 0x0
+#define CDNS_PCIE_LM_BAR_CFG_CTRL_IO_32BITS 0x1
+#define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS 0x4
+#define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS 0x5
+#define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS 0x6
+#define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS 0x7
+
+#define LM_RC_BAR_CFG_CTRL_DISABLED(bar) \
+ (CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED << (((bar) * 8) + 6))
+#define LM_RC_BAR_CFG_CTRL_IO_32BITS(bar) \
+ (CDNS_PCIE_LM_BAR_CFG_CTRL_IO_32BITS << (((bar) * 8) + 6))
+#define LM_RC_BAR_CFG_CTRL_MEM_32BITS(bar) \
+ (CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS << (((bar) * 8) + 6))
+#define LM_RC_BAR_CFG_CTRL_PREF_MEM_32BITS(bar) \
+ (CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS << (((bar) * 8) + 6))
+#define LM_RC_BAR_CFG_CTRL_MEM_64BITS(bar) \
+ (CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS << (((bar) * 8) + 6))
+#define LM_RC_BAR_CFG_CTRL_PREF_MEM_64BITS(bar) \
+ (CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS << (((bar) * 8) + 6))
+#define LM_RC_BAR_CFG_APERTURE(bar, aperture) \
+ (((aperture) - 2) << ((bar) * 8))
+
+/* PTM Control Register */
+#define CDNS_PCIE_LM_PTM_CTRL (CDNS_PCIE_LM_BASE + 0x0DA8)
+#define CDNS_PCIE_LM_TPM_CTRL_PTMRSEN BIT(17)
+
+/*
+ * Endpoint Function Registers (PCI configuration space for endpoint functions)
+ */
+#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
+#define CDNS_PCIE_EP_FUNC_DEV_CAP_OFFSET 0xC0
+#define CDNS_PCIE_EP_FUNC_SRIOV_CAP_OFFSET 0x200
+
+/* Endpoint PF Registers */
+#define CDNS_PCIE_CORE_PF_I_ARI_CAP_AND_CTRL(fn) (0x144 + (fn) * 0x1000)
+#define CDNS_PCIE_ARI_CAP_NFN_MASK GENMASK(15, 8)
+
+/* Root Port Registers (PCI configuration space for the root port function) */
+#define CDNS_PCIE_RP_BASE 0x00200000
+#define CDNS_PCIE_RP_CAP_OFFSET 0xC0
+
+/* Address Translation Registers */
+#define CDNS_PCIE_AT_BASE 0x00400000
+
+/* Region r Outbound AXI to PCIe Address Translation Register 0 */
+#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r) \
+ (CDNS_PCIE_AT_BASE + 0x0000 + ((r) & 0x1F) * 0x0020)
+#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK GENMASK(5, 0)
+#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(nbits) \
+ (((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK)
+#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK GENMASK(19, 12)
+#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) \
+ (((devfn) << 12) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK)
+#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK GENMASK(27, 20)
+#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(bus) \
+ (((bus) << 20) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK)
+
+/* Region r Outbound AXI to PCIe Address Translation Register 1 */
+#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r) \
+ (CDNS_PCIE_AT_BASE + 0x0004 + ((r) & 0x1F) * 0x0020)
+
+/* Region r Outbound PCIe Descriptor Register 0 */
+#define CDNS_PCIE_AT_OB_REGION_DESC0(r) \
+ (CDNS_PCIE_AT_BASE + 0x0008 + ((r) & 0x1F) * 0x0020)
+#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MASK GENMASK(3, 0)
+#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MEM 0x2
+#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_IO 0x6
+#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0 0xA
+#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1 0xB
+#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_NORMAL_MSG 0xC
+#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_VENDOR_MSG 0xD
+/* Bit 23 MUST be set in RC mode. */
+#define CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID BIT(23)
+#define CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK GENMASK(31, 24)
+#define CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(devfn) \
+ (((devfn) << 24) & CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK)
+
+/* Region r Outbound PCIe Descriptor Register 1 */
+#define CDNS_PCIE_AT_OB_REGION_DESC1(r) \
+ (CDNS_PCIE_AT_BASE + 0x000C + ((r) & 0x1F) * 0x0020)
+#define CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK GENMASK(7, 0)
+#define CDNS_PCIE_AT_OB_REGION_DESC1_BUS(bus) \
+ ((bus) & CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK)
+
+/* Region r AXI Region Base Address Register 0 */
+#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r) \
+ (CDNS_PCIE_AT_BASE + 0x0018 + ((r) & 0x1F) * 0x0020)
+#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK GENMASK(5, 0)
+#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) \
+ (((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK)
+
+/* Region r AXI Region Base Address Register 1 */
+#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r) \
+ (CDNS_PCIE_AT_BASE + 0x001C + ((r) & 0x1F) * 0x0020)
+
+/* Root Port BAR Inbound PCIe to AXI Address Translation Register */
+#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0(bar) \
+ (CDNS_PCIE_AT_BASE + 0x0800 + (bar) * 0x0008)
+#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK GENMASK(5, 0)
+#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(nbits) \
+ (((nbits) - 1) & CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK)
+#define CDNS_PCIE_AT_IB_RP_BAR_ADDR1(bar) \
+ (CDNS_PCIE_AT_BASE + 0x0804 + (bar) * 0x0008)
+
+/* AXI link down register */
+#define CDNS_PCIE_AT_LINKDOWN (CDNS_PCIE_AT_BASE + 0x0824)
+
+/* LTSSM Capabilities register */
+#define CDNS_PCIE_LTSSM_CONTROL_CAP (CDNS_PCIE_LM_BASE + 0x0054)
+#define CDNS_PCIE_DETECT_QUIET_MIN_DELAY_MASK GENMASK(2, 1)
+#define CDNS_PCIE_DETECT_QUIET_MIN_DELAY_SHIFT 1
+#define CDNS_PCIE_DETECT_QUIET_MIN_DELAY(delay) \
+ (((delay) << CDNS_PCIE_DETECT_QUIET_MIN_DELAY_SHIFT) & \
+ CDNS_PCIE_DETECT_QUIET_MIN_DELAY_MASK)
+
+#define CDNS_PCIE_RP_MAX_IB 0x3
+#define CDNS_PCIE_MAX_OB 32
+
+/* Endpoint Function BAR Inbound PCIe to AXI Address Translation Register */
+#define CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar) \
+ (CDNS_PCIE_AT_BASE + 0x0840 + (fn) * 0x0040 + (bar) * 0x0008)
+#define CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar) \
+ (CDNS_PCIE_AT_BASE + 0x0844 + (fn) * 0x0040 + (bar) * 0x0008)
+
+/* Normal/Vendor specific message access: offset inside some outbound region */
+#define CDNS_PCIE_NORMAL_MSG_ROUTING_MASK GENMASK(7, 5)
+#define CDNS_PCIE_NORMAL_MSG_ROUTING(route) \
+ (((route) << 5) & CDNS_PCIE_NORMAL_MSG_ROUTING_MASK)
+#define CDNS_PCIE_NORMAL_MSG_CODE_MASK GENMASK(15, 8)
+#define CDNS_PCIE_NORMAL_MSG_CODE(code) \
+ (((code) << 8) & CDNS_PCIE_NORMAL_MSG_CODE_MASK)
+#define CDNS_PCIE_MSG_NO_DATA BIT(16)
+
+#endif /* _PCIE_CADENCE_LGA_REGS_H */
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
index 1d81c4bf6c6d..79df86117fde 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -10,213 +10,7 @@
#include <linux/pci.h>
#include <linux/pci-epf.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
- */
-#define CDNS_PCIE_LM_BASE 0x00100000
-
-/* Vendor ID Register */
-#define CDNS_PCIE_LM_ID (CDNS_PCIE_LM_BASE + 0x0044)
-#define CDNS_PCIE_LM_ID_VENDOR_MASK GENMASK(15, 0)
-#define CDNS_PCIE_LM_ID_VENDOR_SHIFT 0
-#define CDNS_PCIE_LM_ID_VENDOR(vid) \
- (((vid) << CDNS_PCIE_LM_ID_VENDOR_SHIFT) & CDNS_PCIE_LM_ID_VENDOR_MASK)
-#define CDNS_PCIE_LM_ID_SUBSYS_MASK GENMASK(31, 16)
-#define CDNS_PCIE_LM_ID_SUBSYS_SHIFT 16
-#define CDNS_PCIE_LM_ID_SUBSYS(sub) \
- (((sub) << CDNS_PCIE_LM_ID_SUBSYS_SHIFT) & CDNS_PCIE_LM_ID_SUBSYS_MASK)
-
-/* Root Port Requester ID Register */
-#define CDNS_PCIE_LM_RP_RID (CDNS_PCIE_LM_BASE + 0x0228)
-#define CDNS_PCIE_LM_RP_RID_MASK GENMASK(15, 0)
-#define CDNS_PCIE_LM_RP_RID_SHIFT 0
-#define CDNS_PCIE_LM_RP_RID_(rid) \
- (((rid) << CDNS_PCIE_LM_RP_RID_SHIFT) & CDNS_PCIE_LM_RP_RID_MASK)
-
-/* Endpoint Bus and Device Number Register */
-#define CDNS_PCIE_LM_EP_ID (CDNS_PCIE_LM_BASE + 0x022c)
-#define CDNS_PCIE_LM_EP_ID_DEV_MASK GENMASK(4, 0)
-#define CDNS_PCIE_LM_EP_ID_DEV_SHIFT 0
-#define CDNS_PCIE_LM_EP_ID_BUS_MASK GENMASK(15, 8)
-#define CDNS_PCIE_LM_EP_ID_BUS_SHIFT 8
-
-/* Endpoint Function f BAR b Configuration Registers */
-#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG(bar, fn) \
- (((bar) < BAR_4) ? CDNS_PCIE_LM_EP_FUNC_BAR_CFG0(fn) : CDNS_PCIE_LM_EP_FUNC_BAR_CFG1(fn))
-#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG0(fn) \
- (CDNS_PCIE_LM_BASE + 0x0240 + (fn) * 0x0008)
-#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG1(fn) \
- (CDNS_PCIE_LM_BASE + 0x0244 + (fn) * 0x0008)
-#define CDNS_PCIE_LM_EP_VFUNC_BAR_CFG(bar, fn) \
- (((bar) < BAR_4) ? CDNS_PCIE_LM_EP_VFUNC_BAR_CFG0(fn) : CDNS_PCIE_LM_EP_VFUNC_BAR_CFG1(fn))
-#define CDNS_PCIE_LM_EP_VFUNC_BAR_CFG0(fn) \
- (CDNS_PCIE_LM_BASE + 0x0280 + (fn) * 0x0008)
-#define CDNS_PCIE_LM_EP_VFUNC_BAR_CFG1(fn) \
- (CDNS_PCIE_LM_BASE + 0x0284 + (fn) * 0x0008)
-#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) \
- (GENMASK(4, 0) << ((b) * 8))
-#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE(b, a) \
- (((a) << ((b) * 8)) & CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b))
-#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b) \
- (GENMASK(7, 5) << ((b) * 8))
-#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, c) \
- (((c) << ((b) * 8 + 5)) & CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b))
-
-/* Endpoint Function Configuration Register */
-#define CDNS_PCIE_LM_EP_FUNC_CFG (CDNS_PCIE_LM_BASE + 0x02c0)
-
-/* Root Complex BAR Configuration Register */
-#define CDNS_PCIE_LM_RC_BAR_CFG (CDNS_PCIE_LM_BASE + 0x0300)
-#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE_MASK GENMASK(5, 0)
-#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE(a) \
- (((a) << 0) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE_MASK)
-#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK GENMASK(8, 6)
-#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(c) \
- (((c) << 6) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK)
-#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE_MASK GENMASK(13, 9)
-#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE(a) \
- (((a) << 9) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE_MASK)
-#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK GENMASK(16, 14)
-#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(c) \
- (((c) << 14) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK)
-#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE BIT(17)
-#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_32BITS 0
-#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS BIT(18)
-#define CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE BIT(19)
-#define CDNS_PCIE_LM_RC_BAR_CFG_IO_16BITS 0
-#define CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS BIT(20)
-#define CDNS_PCIE_LM_RC_BAR_CFG_CHECK_ENABLE BIT(31)
-
-/* BAR control values applicable to both Endpoint Function and Root Complex */
-#define CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED 0x0
-#define CDNS_PCIE_LM_BAR_CFG_CTRL_IO_32BITS 0x1
-#define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS 0x4
-#define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS 0x5
-#define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS 0x6
-#define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS 0x7
-
-#define LM_RC_BAR_CFG_CTRL_DISABLED(bar) \
- (CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED << (((bar) * 8) + 6))
-#define LM_RC_BAR_CFG_CTRL_IO_32BITS(bar) \
- (CDNS_PCIE_LM_BAR_CFG_CTRL_IO_32BITS << (((bar) * 8) + 6))
-#define LM_RC_BAR_CFG_CTRL_MEM_32BITS(bar) \
- (CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS << (((bar) * 8) + 6))
-#define LM_RC_BAR_CFG_CTRL_PREF_MEM_32BITS(bar) \
- (CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS << (((bar) * 8) + 6))
-#define LM_RC_BAR_CFG_CTRL_MEM_64BITS(bar) \
- (CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS << (((bar) * 8) + 6))
-#define LM_RC_BAR_CFG_CTRL_PREF_MEM_64BITS(bar) \
- (CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS << (((bar) * 8) + 6))
-#define LM_RC_BAR_CFG_APERTURE(bar, aperture) \
- (((aperture) - 2) << ((bar) * 8))
-
-/* PTM Control Register */
-#define CDNS_PCIE_LM_PTM_CTRL (CDNS_PCIE_LM_BASE + 0x0da8)
-#define CDNS_PCIE_LM_TPM_CTRL_PTMRSEN BIT(17)
-
-/*
- * Endpoint Function Registers (PCI configuration space for endpoint functions)
- */
-#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
-#define CDNS_PCIE_EP_FUNC_DEV_CAP_OFFSET 0xc0
-#define CDNS_PCIE_EP_FUNC_SRIOV_CAP_OFFSET 0x200
-
-/*
- * Endpoint PF Registers
- */
-#define CDNS_PCIE_CORE_PF_I_ARI_CAP_AND_CTRL(fn) (0x144 + (fn) * 0x1000)
-#define CDNS_PCIE_ARI_CAP_NFN_MASK GENMASK(15, 8)
-
-/*
- * Root Port Registers (PCI configuration space for the root port function)
- */
-#define CDNS_PCIE_RP_BASE 0x00200000
-#define CDNS_PCIE_RP_CAP_OFFSET 0xc0
-
-/*
- * Address Translation Registers
- */
-#define CDNS_PCIE_AT_BASE 0x00400000
-
-/* Region r Outbound AXI to PCIe Address Translation Register 0 */
-#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r) \
- (CDNS_PCIE_AT_BASE + 0x0000 + ((r) & 0x1f) * 0x0020)
-#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK GENMASK(5, 0)
-#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(nbits) \
- (((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK)
-#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK GENMASK(19, 12)
-#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) \
- (((devfn) << 12) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK)
-#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK GENMASK(27, 20)
-#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(bus) \
- (((bus) << 20) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK)
-
-/* Region r Outbound AXI to PCIe Address Translation Register 1 */
-#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r) \
- (CDNS_PCIE_AT_BASE + 0x0004 + ((r) & 0x1f) * 0x0020)
-
-/* Region r Outbound PCIe Descriptor Register 0 */
-#define CDNS_PCIE_AT_OB_REGION_DESC0(r) \
- (CDNS_PCIE_AT_BASE + 0x0008 + ((r) & 0x1f) * 0x0020)
-#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MASK GENMASK(3, 0)
-#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MEM 0x2
-#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_IO 0x6
-#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0 0xa
-#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1 0xb
-#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_NORMAL_MSG 0xc
-#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_VENDOR_MSG 0xd
-/* Bit 23 MUST be set in RC mode. */
-#define CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID BIT(23)
-#define CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK GENMASK(31, 24)
-#define CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(devfn) \
- (((devfn) << 24) & CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK)
-
-/* Region r Outbound PCIe Descriptor Register 1 */
-#define CDNS_PCIE_AT_OB_REGION_DESC1(r) \
- (CDNS_PCIE_AT_BASE + 0x000c + ((r) & 0x1f) * 0x0020)
-#define CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK GENMASK(7, 0)
-#define CDNS_PCIE_AT_OB_REGION_DESC1_BUS(bus) \
- ((bus) & CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK)
-
-/* Region r AXI Region Base Address Register 0 */
-#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r) \
- (CDNS_PCIE_AT_BASE + 0x0018 + ((r) & 0x1f) * 0x0020)
-#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK GENMASK(5, 0)
-#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) \
- (((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK)
-
-/* Region r AXI Region Base Address Register 1 */
-#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r) \
- (CDNS_PCIE_AT_BASE + 0x001c + ((r) & 0x1f) * 0x0020)
-
-/* Root Port BAR Inbound PCIe to AXI Address Translation Register */
-#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0(bar) \
- (CDNS_PCIE_AT_BASE + 0x0800 + (bar) * 0x0008)
-#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK GENMASK(5, 0)
-#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(nbits) \
- (((nbits) - 1) & CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK)
-#define CDNS_PCIE_AT_IB_RP_BAR_ADDR1(bar) \
- (CDNS_PCIE_AT_BASE + 0x0804 + (bar) * 0x0008)
-
-/* AXI link down register */
-#define CDNS_PCIE_AT_LINKDOWN (CDNS_PCIE_AT_BASE + 0x0824)
-
-/* LTSSM Capabilities register */
-#define CDNS_PCIE_LTSSM_CONTROL_CAP (CDNS_PCIE_LM_BASE + 0x0054)
-#define CDNS_PCIE_DETECT_QUIET_MIN_DELAY_MASK GENMASK(2, 1)
-#define CDNS_PCIE_DETECT_QUIET_MIN_DELAY_SHIFT 1
-#define CDNS_PCIE_DETECT_QUIET_MIN_DELAY(delay) \
- (((delay) << CDNS_PCIE_DETECT_QUIET_MIN_DELAY_SHIFT) & \
- CDNS_PCIE_DETECT_QUIET_MIN_DELAY_MASK)
+#include "pcie-cadence-lga-regs.h"
enum cdns_pcie_rp_bar {
RP_BAR_UNDEFINED = -1,
@@ -225,29 +19,11 @@ enum cdns_pcie_rp_bar {
RP_NO_BAR
};
-#define CDNS_PCIE_RP_MAX_IB 0x3
-#define CDNS_PCIE_MAX_OB 32
-
struct cdns_pcie_rp_ib_bar {
u64 size;
bool free;
};
-/* Endpoint Function BAR Inbound PCIe to AXI Address Translation Register */
-#define CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar) \
- (CDNS_PCIE_AT_BASE + 0x0840 + (fn) * 0x0040 + (bar) * 0x0008)
-#define CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar) \
- (CDNS_PCIE_AT_BASE + 0x0844 + (fn) * 0x0040 + (bar) * 0x0008)
-
-/* Normal/Vendor specific message access: offset inside some outbound region */
-#define CDNS_PCIE_NORMAL_MSG_ROUTING_MASK GENMASK(7, 5)
-#define CDNS_PCIE_NORMAL_MSG_ROUTING(route) \
- (((route) << 5) & CDNS_PCIE_NORMAL_MSG_ROUTING_MASK)
-#define CDNS_PCIE_NORMAL_MSG_CODE_MASK GENMASK(15, 8)
-#define CDNS_PCIE_NORMAL_MSG_CODE(code) \
- (((code) << 8) & CDNS_PCIE_NORMAL_MSG_CODE_MASK)
-#define CDNS_PCIE_MSG_DATA BIT(16)
-
struct cdns_pcie;
struct cdns_pcie_ops {
--
2.49.0
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH v7 03/13] PCI: cadence: Add register definitions for HPA(High Perf Architecture)
2025-08-13 4:23 [PATCH v7 00/13] Enhance the PCIe controller driver for next generation controllers hans.zhang
2025-08-13 4:23 ` [PATCH v7 01/13] PCI: cadence: Add support for modules for cadence controller builds hans.zhang
2025-08-13 4:23 ` [PATCH v7 02/13] PCI: cadence: Split PCIe controller header file hans.zhang
@ 2025-08-13 4:23 ` hans.zhang
2025-08-13 19:17 ` Krzysztof Kozlowski
2025-08-14 21:35 ` Bjorn Helgaas
2025-08-13 4:23 ` [PATCH v7 04/13] PCI: cadence: Split PCIe EP support into common and specific functions hans.zhang
` (10 subsequent siblings)
13 siblings, 2 replies; 40+ messages in thread
From: hans.zhang @ 2025-08-13 4:23 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kw, mani, robh, kwilczynski, krzk+dt,
conor+dt
Cc: mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel,
Hans Zhang
From: Manikandan K Pillai <mpillai@cadence.com>
Add the register offsets and register definitions for HPA(High
Performance architecture) PCIe controllers from Cadence.
Signed-off-by: Manikandan K Pillai <mpillai@cadence.com>
Co-developed-by: Hans Zhang <hans.zhang@cixtech.com>
Signed-off-by: Hans Zhang <hans.zhang@cixtech.com>
---
.../cadence/pcie-cadence-hpa-regs.h | 212 ++++++++++++++++++
.../controller/cadence/pcie-cadence-plat.c | 4 -
drivers/pci/controller/cadence/pcie-cadence.h | 121 ++++++++--
3 files changed, 320 insertions(+), 17 deletions(-)
create mode 100644 drivers/pci/controller/cadence/pcie-cadence-hpa-regs.h
diff --git a/drivers/pci/controller/cadence/pcie-cadence-hpa-regs.h b/drivers/pci/controller/cadence/pcie-cadence-hpa-regs.h
new file mode 100644
index 000000000000..016144e2df81
--- /dev/null
+++ b/drivers/pci/controller/cadence/pcie-cadence-hpa-regs.h
@@ -0,0 +1,212 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (c) 2017 Cadence
+// Cadence PCIe controller driver.
+// Author: Manikandan K Pillai <mpillai@cadence.com>
+
+#ifndef _PCIE_CADENCE_HPA_REGS_H
+#define _PCIE_CADENCE_HPA_REGS_H
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/pci-epf.h>
+#include <linux/phy/phy.h>
+#include <linux/bitfield.h>
+
+/*
+ * HPA (High Performance Architecture) PCIe controller register
+ */
+#define CDNS_PCIE_HPA_IP_REG_BANK 0x01000000
+#define CDNS_PCIE_HPA_IP_CFG_CTRL_REG_BANK 0x01003C00
+#define CDNS_PCIE_HPA_IP_AXI_MASTER_COMMON 0x01020000
+/*
+ * Address Translation Registers(HPA)
+ */
+#define CDNS_PCIE_HPA_AXI_SLAVE 0x03000000
+#define CDNS_PCIE_HPA_AXI_MASTER 0x03002000
+/*
+ * Root port register base address
+ */
+#define CDNS_PCIE_HPA_RP_BASE 0x0
+
+#define CDNS_PCIE_HPA_LM_ID 0x1420
+
+/*
+ * Endpoint Function BARs(HPA) Configuration Registers
+ */
+#define CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG(bar, fn) \
+ (((bar) < BAR_3) ? CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG0(fn) : \
+ CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG1(fn))
+#define CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG0(pfn) (0x4000 * (pfn))
+#define CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG1(pfn) ((0x4000 * (pfn)) + 0x04)
+#define CDNS_PCIE_HPA_LM_EP_VFUNC_BAR_CFG(bar, fn) \
+ (((bar) < BAR_3) ? CDNS_PCIE_HPA_LM_EP_VFUNC_BAR_CFG0(fn) : \
+ CDNS_PCIE_HPA_LM_EP_VFUNC_BAR_CFG1(fn))
+#define CDNS_PCIE_HPA_LM_EP_VFUNC_BAR_CFG0(vfn) ((0x4000 * (vfn)) + 0x08)
+#define CDNS_PCIE_HPA_LM_EP_VFUNC_BAR_CFG1(vfn) ((0x4000 * (vfn)) + 0x0C)
+#define CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(f) \
+ (GENMASK(9, 4) << ((f) * 10))
+#define CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG_BAR_APERTURE(b, a) \
+ (((a) << (4 + ((b) * 10))) & (CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b)))
+#define CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(f) \
+ (GENMASK(3, 0) << ((f) * 10))
+#define CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, c) \
+ (((c) << ((b) * 10)) & (CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b)))
+
+/*
+ * Endpoint Function Configuration Register
+ */
+#define CDNS_PCIE_HPA_LM_EP_FUNC_CFG 0x02C0
+
+/*
+ * Root Complex BAR Configuration Register
+ */
+#define CDNS_PCIE_HPA_LM_RC_BAR_CFG 0x14
+#define CDNS_PCIE_HPA_LM_RC_BAR_CFG_BAR0_APERTURE_MASK GENMASK(9, 4)
+#define CDNS_PCIE_HPA_LM_RC_BAR_CFG_BAR0_APERTURE(a) \
+ FIELD_PREP(CDNS_PCIE_HPA_LM_RC_BAR_CFG_BAR0_APERTURE_MASK, a)
+#define CDNS_PCIE_HPA_LM_RC_BAR_CFG_BAR0_CTRL_MASK GENMASK(3, 0)
+#define CDNS_PCIE_HPA_LM_RC_BAR_CFG_BAR0_CTRL(c) \
+ FIELD_PREP(CDNS_PCIE_HPA_LM_RC_BAR_CFG_BAR0_CTRL_MASK, c)
+#define CDNS_PCIE_HPA_LM_RC_BAR_CFG_BAR1_APERTURE_MASK GENMASK(19, 14)
+#define CDNS_PCIE_HPA_LM_RC_BAR_CFG_BAR1_APERTURE(a) \
+ FIELD_PREP(CDNS_PCIE_HPA_LM_RC_BAR_CFG_BAR1_APERTURE_MASK, a)
+#define CDNS_PCIE_HPA_LM_RC_BAR_CFG_BAR1_CTRL_MASK GENMASK(13, 10)
+#define CDNS_PCIE_HPA_LM_RC_BAR_CFG_BAR1_CTRL(c) \
+ FIELD_PREP(CDNS_PCIE_HPA_LM_RC_BAR_CFG_BAR1_CTRL_MASK, c)
+
+#define CDNS_PCIE_HPA_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE BIT(20)
+#define CDNS_PCIE_HPA_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS BIT(21)
+#define CDNS_PCIE_HPA_LM_RC_BAR_CFG_IO_ENABLE BIT(22)
+#define CDNS_PCIE_HPA_LM_RC_BAR_CFG_IO_32BITS BIT(23)
+
+/* BAR control values applicable to both Endpoint Function and Root Complex */
+#define CDNS_PCIE_HPA_LM_BAR_CFG_CTRL_DISABLED 0x0
+#define CDNS_PCIE_HPA_LM_BAR_CFG_CTRL_IO_32BITS 0x3
+#define CDNS_PCIE_HPA_LM_BAR_CFG_CTRL_MEM_32BITS 0x1
+#define CDNS_PCIE_HPA_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS 0x9
+#define CDNS_PCIE_HPA_LM_BAR_CFG_CTRL_MEM_64BITS 0x5
+#define CDNS_PCIE_HPA_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS 0xD
+
+#define HPA_LM_RC_BAR_CFG_CTRL_DISABLED(bar) \
+ (CDNS_PCIE_HPA_LM_BAR_CFG_CTRL_DISABLED << ((bar) * 10))
+#define HPA_LM_RC_BAR_CFG_CTRL_IO_32BITS(bar) \
+ (CDNS_PCIE_HPA_LM_BAR_CFG_CTRL_IO_32BITS << ((bar) * 10))
+#define HPA_LM_RC_BAR_CFG_CTRL_MEM_32BITS(bar) \
+ (CDNS_PCIE_HPA_LM_BAR_CFG_CTRL_MEM_32BITS << ((bar) * 10))
+#define HPA_LM_RC_BAR_CFG_CTRL_PREF_MEM_32BITS(bar) \
+ (CDNS_PCIE_HPA_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS << ((bar) * 10))
+#define HPA_LM_RC_BAR_CFG_CTRL_MEM_64BITS(bar) \
+ (CDNS_PCIE_HPA_LM_BAR_CFG_CTRL_MEM_64BITS << ((bar) * 10))
+#define HPA_LM_RC_BAR_CFG_CTRL_PREF_MEM_64BITS(bar) \
+ (CDNS_PCIE_HPA_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS << ((bar) * 10))
+#define HPA_LM_RC_BAR_CFG_APERTURE(bar, aperture) \
+ (((aperture) - 7) << ((bar) * 10))
+
+#define CDNS_PCIE_HPA_LM_PTM_CTRL 0x0520
+#define CDNS_PCIE_HPA_LM_TPM_CTRL_PTMRSEN BIT(17)
+
+/*
+ * Root Port Registers PCI config space(HPA) for root port function
+ */
+#define CDNS_PCIE_HPA_RP_CAP_OFFSET 0xC0
+
+/*
+ * Region r Outbound AXI to PCIe Address Translation Register 0
+ */
+#define CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR0(r) (0x1010 + ((r) & 0x1F) * 0x0080)
+#define CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR0_NBITS_MASK GENMASK(5, 0)
+#define CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR0_NBITS(nbits) \
+ FIELD_PREP(CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR0_NBITS_MASK, ((nbits) - 1))
+#define CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK GENMASK(23, 16)
+#define CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) \
+ FIELD_PREP(CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK, devfn)
+#define CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR0_BUS_MASK GENMASK(31, 24)
+#define CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR0_BUS(bus) \
+ FIELD_PREP(CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR0_BUS_MASK, bus)
+
+/*
+ * Region r Outbound AXI to PCIe Address Translation Register 1
+ */
+#define CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR1(r) (0x1014 + ((r) & 0x1F) * 0x0080)
+
+/*
+ * Region r Outbound PCIe Descriptor Register 0
+ */
+#define CDNS_PCIE_HPA_AT_OB_REGION_DESC0(r) (0x1008 + ((r) & 0x1F) * 0x0080)
+#define CDNS_PCIE_HPA_AT_OB_REGION_DESC0_TYPE_MASK GENMASK(28, 24)
+#define CDNS_PCIE_HPA_AT_OB_REGION_DESC0_TYPE_MEM \
+ FIELD_PREP(CDNS_PCIE_HPA_AT_OB_REGION_DESC0_TYPE_MASK, 0x0)
+#define CDNS_PCIE_HPA_AT_OB_REGION_DESC0_TYPE_IO \
+ FIELD_PREP(CDNS_PCIE_HPA_AT_OB_REGION_DESC0_TYPE_MASK, 0x2)
+#define CDNS_PCIE_HPA_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0 \
+ FIELD_PREP(CDNS_PCIE_HPA_AT_OB_REGION_DESC0_TYPE_MASK, 0x4)
+#define CDNS_PCIE_HPA_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1 \
+ FIELD_PREP(CDNS_PCIE_HPA_AT_OB_REGION_DESC0_TYPE_MASK, 0x5)
+#define CDNS_PCIE_HPA_AT_OB_REGION_DESC0_TYPE_NORMAL_MSG \
+ FIELD_PREP(CDNS_PCIE_HPA_AT_OB_REGION_DESC0_TYPE_MASK, 0x10)
+
+/*
+ * Region r Outbound PCIe Descriptor Register 1
+ */
+#define CDNS_PCIE_HPA_AT_OB_REGION_DESC1(r) (0x100C + ((r) & 0x1F) * 0x0080)
+#define CDNS_PCIE_HPA_AT_OB_REGION_DESC1_BUS_MASK GENMASK(31, 24)
+#define CDNS_PCIE_HPA_AT_OB_REGION_DESC1_BUS(bus) \
+ FIELD_PREP(CDNS_PCIE_HPA_AT_OB_REGION_DESC1_BUS_MASK, bus)
+#define CDNS_PCIE_HPA_AT_OB_REGION_DESC1_DEVFN_MASK GENMASK(23, 16)
+#define CDNS_PCIE_HPA_AT_OB_REGION_DESC1_DEVFN(devfn) \
+ FIELD_PREP(CDNS_PCIE_HPA_AT_OB_REGION_DESC1_DEVFN_MASK, devfn)
+
+#define CDNS_PCIE_HPA_AT_OB_REGION_CTRL0(r) (0x1018 + ((r) & 0x1F) * 0x0080)
+#define CDNS_PCIE_HPA_AT_OB_REGION_CTRL0_SUPPLY_BUS BIT(26)
+#define CDNS_PCIE_HPA_AT_OB_REGION_CTRL0_SUPPLY_DEV_FN BIT(25)
+
+/*
+ * Region r AXI Region Base Address Register 0
+ */
+#define CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR0(r) (0x1000 + ((r) & 0x1F) * 0x0080)
+#define CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR0_NBITS_MASK GENMASK(5, 0)
+#define CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) \
+ FIELD_PREP(CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR0_NBITS_MASK, ((nbits) - 1))
+
+/*
+ * Region r AXI Region Base Address Register 1
+ */
+#define CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR1(r) (0x1004 + ((r) & 0x1F) * 0x0080)
+
+/*
+ * Root Port BAR Inbound PCIe to AXI Address Translation Register
+ */
+#define CDNS_PCIE_HPA_AT_IB_RP_BAR_ADDR0(bar) (((bar) * 0x0008))
+#define CDNS_PCIE_HPA_AT_IB_RP_BAR_ADDR0_NBITS_MASK GENMASK(5, 0)
+#define CDNS_PCIE_HPA_AT_IB_RP_BAR_ADDR0_NBITS(nbits) \
+ FIELD_PREP(CDNS_PCIE_HPA_AT_IB_RP_BAR_ADDR0_NBITS_MASK, ((nbits) - 1))
+#define CDNS_PCIE_HPA_AT_IB_RP_BAR_ADDR1(bar) (0x04 + ((bar) * 0x0008))
+
+/*
+ * AXI link down register
+ */
+#define CDNS_PCIE_HPA_AT_LINKDOWN 0x04
+
+/*
+ * Physical Layer Configuration Register 0
+ * This register contains the parameters required for functional setup
+ * of Physical Layer.
+ */
+#define CDNS_PCIE_HPA_PHY_LAYER_CFG0 0x0400
+#define CDNS_PCIE_HPA_DETECT_QUIET_MIN_DELAY_MASK GENMASK(26, 24)
+#define CDNS_PCIE_HPA_DETECT_QUIET_MIN_DELAY(delay) \
+ FIELD_PREP(CDNS_PCIE_HPA_DETECT_QUIET_MIN_DELAY_MASK, delay)
+#define CDNS_PCIE_HPA_LINK_TRNG_EN_MASK GENMASK(27, 27)
+
+#define CDNS_PCIE_HPA_PHY_DBG_STS_REG0 0x0420
+
+#define CDNS_PCIE_HPA_RP_MAX_IB 0x3
+#define CDNS_PCIE_HPA_MAX_OB 15
+
+/*
+ * Endpoint Function BAR Inbound PCIe to AXI Address Translation Register(HPA)
+ */
+#define CDNS_PCIE_HPA_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar) (((fn) * 0x0040) + ((bar) * 0x0008))
+#define CDNS_PCIE_HPA_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar) (0x4 + ((fn) * 0x0040) + ((bar) * 0x0008))
+
+#endif /* _PCIE_CADENCE_HPA_REGS_H */
diff --git a/drivers/pci/controller/cadence/pcie-cadence-plat.c b/drivers/pci/controller/cadence/pcie-cadence-plat.c
index c9330aa50a88..ced030cc0fda 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-plat.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-plat.c
@@ -22,10 +22,6 @@ struct cdns_plat_pcie {
struct cdns_pcie *pcie;
};
-struct cdns_plat_pcie_of_data {
- bool is_rc;
-};
-
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)
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
index 79df86117fde..8048bef215d0 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -10,7 +10,9 @@
#include <linux/pci.h>
#include <linux/pci-epf.h>
#include <linux/phy/phy.h>
+#include <linux/bitfield.h>
#include "pcie-cadence-lga-regs.h"
+#include "pcie-cadence-hpa-regs.h"
enum cdns_pcie_rp_bar {
RP_BAR_UNDEFINED = -1,
@@ -25,6 +27,20 @@ struct cdns_pcie_rp_ib_bar {
};
struct cdns_pcie;
+struct cdns_pcie_rc;
+
+enum cdns_pcie_reg_bank {
+ REG_BANK_RP,
+ REG_BANK_IP_REG,
+ REG_BANK_IP_CFG_CTRL_REG,
+ REG_BANK_AXI_MASTER_COMMON,
+ REG_BANK_AXI_MASTER,
+ REG_BANK_AXI_SLAVE,
+ REG_BANK_AXI_HLS,
+ REG_BANK_AXI_RAS,
+ REG_BANK_AXI_DTI,
+ REG_BANKS_MAX,
+};
struct cdns_pcie_ops {
int (*start_link)(struct cdns_pcie *pcie);
@@ -33,6 +49,30 @@ struct cdns_pcie_ops {
u64 (*cpu_addr_fixup)(struct cdns_pcie *pcie, u64 cpu_addr);
};
+/**
+ * struct cdns_plat_pcie_of_data - Register bank offset for a platform
+ * @is_rc: controller is a RC
+ * @ip_reg_bank_offset: ip register bank start offset
+ * @ip_cfg_ctrl_reg_offset: ip config control register start offset
+ * @axi_mstr_common_offset: AXI master common register start offset
+ * @axi_slave_offset: AXI slave start offset
+ * @axi_master_offset: AXI master start offset
+ * @axi_hls_offset: AXI HLS offset start
+ * @axi_ras_offset: AXI RAS offset
+ * @axi_dti_offset: AXI DTI offset
+ */
+struct cdns_plat_pcie_of_data {
+ u32 is_rc:1;
+ u32 ip_reg_bank_offset;
+ u32 ip_cfg_ctrl_reg_offset;
+ u32 axi_mstr_common_offset;
+ u32 axi_slave_offset;
+ u32 axi_master_offset;
+ u32 axi_hls_offset;
+ u32 axi_ras_offset;
+ u32 axi_dti_offset;
+};
+
/**
* struct cdns_pcie - private data for Cadence PCIe controller drivers
* @reg_base: IO mapped register base
@@ -44,16 +84,18 @@ struct cdns_pcie_ops {
* @link: list of pointers to corresponding device link representations
* @ops: Platform-specific ops to control various inputs from Cadence PCIe
* wrapper
+ * @cdns_pcie_reg_offsets: Register bank offsets for different SoC
*/
struct cdns_pcie {
- void __iomem *reg_base;
- struct resource *mem_res;
- struct device *dev;
- bool is_rc;
- int phy_count;
- struct phy **phy;
- struct device_link **link;
- const struct cdns_pcie_ops *ops;
+ void __iomem *reg_base;
+ struct resource *mem_res;
+ struct device *dev;
+ bool is_rc;
+ int phy_count;
+ struct phy **phy;
+ struct device_link **link;
+ const struct cdns_pcie_ops *ops;
+ const struct cdns_plat_pcie_of_data *cdns_pcie_reg_offsets;
};
/**
@@ -131,6 +173,40 @@ struct cdns_pcie_ep {
unsigned int quirk_disable_flr:1;
};
+static inline u32 cdns_reg_bank_to_off(struct cdns_pcie *pcie, enum cdns_pcie_reg_bank bank)
+{
+ u32 offset = 0x0;
+
+ switch (bank) {
+ case REG_BANK_IP_REG:
+ offset = pcie->cdns_pcie_reg_offsets->ip_reg_bank_offset;
+ break;
+ case REG_BANK_IP_CFG_CTRL_REG:
+ offset = pcie->cdns_pcie_reg_offsets->ip_cfg_ctrl_reg_offset;
+ break;
+ case REG_BANK_AXI_MASTER_COMMON:
+ offset = pcie->cdns_pcie_reg_offsets->axi_mstr_common_offset;
+ break;
+ case REG_BANK_AXI_MASTER:
+ offset = pcie->cdns_pcie_reg_offsets->axi_master_offset;
+ break;
+ case REG_BANK_AXI_SLAVE:
+ offset = pcie->cdns_pcie_reg_offsets->axi_slave_offset;
+ break;
+ case REG_BANK_AXI_HLS:
+ offset = pcie->cdns_pcie_reg_offsets->axi_hls_offset;
+ break;
+ case REG_BANK_AXI_RAS:
+ offset = pcie->cdns_pcie_reg_offsets->axi_ras_offset;
+ break;
+ case REG_BANK_AXI_DTI:
+ offset = pcie->cdns_pcie_reg_offsets->axi_dti_offset;
+ break;
+ default:
+ break;
+ };
+ return offset;
+}
/* Register access */
static inline void cdns_pcie_writel(struct cdns_pcie *pcie, u32 reg, u32 value)
@@ -143,6 +219,27 @@ static inline u32 cdns_pcie_readl(struct cdns_pcie *pcie, u32 reg)
return readl(pcie->reg_base + reg);
}
+static inline void cdns_pcie_hpa_writel(struct cdns_pcie *pcie,
+ enum cdns_pcie_reg_bank bank,
+ u32 reg,
+ u32 value)
+{
+ u32 offset = cdns_reg_bank_to_off(pcie, bank);
+
+ reg += offset;
+ writel(value, pcie->reg_base + reg);
+}
+
+static inline u32 cdns_pcie_hpa_readl(struct cdns_pcie *pcie,
+ enum cdns_pcie_reg_bank bank,
+ u32 reg)
+{
+ u32 offset = cdns_reg_bank_to_off(pcie, bank);
+
+ reg += offset;
+ return readl(pcie->reg_base + reg);
+}
+
static inline u32 cdns_pcie_read_sz(void __iomem *addr, int size)
{
void __iomem *aligned_addr = PTR_ALIGN_DOWN(addr, 0x4);
@@ -313,19 +410,17 @@ static inline void cdns_pcie_ep_disable(struct cdns_pcie_ep *ep)
#endif
void cdns_pcie_detect_quiet_min_delay_set(struct cdns_pcie *pcie);
-
void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 busnr, u8 fn,
u32 r, bool is_io,
u64 cpu_addr, u64 pci_addr, size_t size);
-
void cdns_pcie_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie,
u8 busnr, u8 fn,
u32 r, u64 cpu_addr);
-
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);
+int cdns_pcie_enable_phy(struct cdns_pcie *pcie);
+int cdns_pcie_init_phy(struct device *dev, struct cdns_pcie *pcie);
+
extern const struct dev_pm_ops cdns_pcie_pm_ops;
#endif /* _PCIE_CADENCE_H */
--
2.49.0
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH v7 04/13] PCI: cadence: Split PCIe EP support into common and specific functions
2025-08-13 4:23 [PATCH v7 00/13] Enhance the PCIe controller driver for next generation controllers hans.zhang
` (2 preceding siblings ...)
2025-08-13 4:23 ` [PATCH v7 03/13] PCI: cadence: Add register definitions for HPA(High Perf Architecture) hans.zhang
@ 2025-08-13 4:23 ` hans.zhang
2025-08-14 21:41 ` Bjorn Helgaas
2025-08-13 4:23 ` [PATCH v7 05/13] PCI: cadence: Split PCIe RP " hans.zhang
` (9 subsequent siblings)
13 siblings, 1 reply; 40+ messages in thread
From: hans.zhang @ 2025-08-13 4:23 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kw, mani, robh, kwilczynski, krzk+dt,
conor+dt
Cc: mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel,
Hans Zhang
From: Manikandan K Pillai <mpillai@cadence.com>
Split the Cadence PCIe controller EP functionality into common
ibrary functions and functions for legacy PCIe EP controller.
Signed-off-by: Manikandan K Pillai <mpillai@cadence.com>
Co-developed-by: Hans Zhang <hans.zhang@cixtech.com>
Signed-off-by: Hans Zhang <hans.zhang@cixtech.com>
---
drivers/pci/controller/cadence/Makefile | 2 +-
.../cadence/pcie-cadence-ep-common.c | 252 ++++++++++++++++++
.../cadence/pcie-cadence-ep-common.h | 36 +++
.../pci/controller/cadence/pcie-cadence-ep.c | 243 +----------------
4 files changed, 295 insertions(+), 238 deletions(-)
create mode 100644 drivers/pci/controller/cadence/pcie-cadence-ep-common.c
create mode 100644 drivers/pci/controller/cadence/pcie-cadence-ep-common.h
diff --git a/drivers/pci/controller/cadence/Makefile b/drivers/pci/controller/cadence/Makefile
index 9bac5fb2f13d..80c1c4be7e80 100644
--- a/drivers/pci/controller/cadence/Makefile
+++ b/drivers/pci/controller/cadence/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
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_EP) += pcie-cadence-ep-common.o 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/pcie-cadence-ep-common.c b/drivers/pci/controller/cadence/pcie-cadence-ep-common.c
new file mode 100644
index 000000000000..46a1631e54e5
--- /dev/null
+++ b/drivers/pci/controller/cadence/pcie-cadence-ep-common.c
@@ -0,0 +1,252 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2017 Cadence
+// Cadence PCIe endpoint controller driver common
+// Author: Manikandan K Pillai <mpillai@cadence.com>
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/sizes.h>
+
+#include "pcie-cadence.h"
+#include "pcie-cadence-ep-common.h"
+
+u8 cdns_pcie_get_fn_from_vfn(struct cdns_pcie *pcie, u8 fn, u8 vfn)
+{
+ u32 cap = CDNS_PCIE_EP_FUNC_SRIOV_CAP_OFFSET;
+ u32 first_vf_offset, stride;
+
+ if (vfn == 0)
+ return fn;
+
+ first_vf_offset = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_SRIOV_VF_OFFSET);
+ stride = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_SRIOV_VF_STRIDE);
+ fn = fn + first_vf_offset + ((vfn - 1) * stride);
+
+ return fn;
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_get_fn_from_vfn);
+
+int cdns_pcie_ep_write_header(struct pci_epc *epc, u8 fn, u8 vfn,
+ struct pci_epf_header *hdr)
+{
+ struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+ u32 cap = CDNS_PCIE_EP_FUNC_SRIOV_CAP_OFFSET;
+ struct cdns_pcie *pcie = &ep->pcie;
+ u32 reg;
+
+ if (vfn > 1) {
+ dev_err(&epc->dev, "Only Virtual Function #1 has deviceID\n");
+ return -EINVAL;
+ } else if (vfn == 1) {
+ reg = cap + PCI_SRIOV_VF_DID;
+ cdns_pcie_ep_fn_writew(pcie, fn, reg, hdr->deviceid);
+ return 0;
+ }
+
+ 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;
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_ep_write_header);
+
+int cdns_pcie_ep_set_msi(struct pci_epc *epc, u8 fn, u8 vfn, u8 mmc)
+{
+ struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+ struct cdns_pcie *pcie = &ep->pcie;
+ u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET;
+ u16 flags;
+
+ fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn);
+
+ /*
+ * Set the Multiple Message Capable bitfield into the Message Control
+ * register.
+ */
+ flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS);
+ flags = (flags & ~PCI_MSI_FLAGS_QMASK) | (mmc << 1);
+ flags |= PCI_MSI_FLAGS_64BIT;
+ flags &= ~PCI_MSI_FLAGS_MASKBIT;
+ cdns_pcie_ep_fn_writew(pcie, fn, cap + PCI_MSI_FLAGS, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_ep_set_msi);
+
+int cdns_pcie_ep_get_msi(struct pci_epc *epc, u8 fn, u8 vfn)
+{
+ struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+ struct cdns_pcie *pcie = &ep->pcie;
+ u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET;
+ u16 flags, mme;
+
+ fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn);
+
+ /* Validate that the MSI feature is actually enabled. */
+ flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS);
+ if (!(flags & PCI_MSI_FLAGS_ENABLE))
+ return -EINVAL;
+
+ /*
+ * Get the Multiple Message Enable bitfield from the Message Control
+ * register.
+ */
+ mme = FIELD_GET(PCI_MSI_FLAGS_QSIZE, flags);
+
+ return mme;
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_ep_get_msi);
+
+int cdns_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_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;
+
+ func_no = cdns_pcie_get_fn_from_vfn(pcie, func_no, vfunc_no);
+
+ 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;
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_ep_get_msix);
+
+int cdns_pcie_ep_set_msix(struct pci_epc *epc, u8 fn, u8 vfn,
+ 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;
+
+ fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn);
+
+ 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 MSI-X 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 MSI-X 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;
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_ep_set_msix);
+
+int cdns_pcie_ep_map_msi_irq(struct pci_epc *epc, u8 fn, u8 vfn,
+ phys_addr_t addr, u8 interrupt_num,
+ u32 entry_size, u32 *msi_data,
+ u32 *msi_addr_offset)
+{
+ struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+ u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET;
+ struct cdns_pcie *pcie = &ep->pcie;
+ u64 pci_addr, pci_addr_mask = 0xff;
+ u16 flags, mme, data, data_mask;
+ u8 msi_count;
+ int ret;
+ int i;
+
+ fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn);
+
+ /* Check whether the MSI feature has been enabled by the PCI host. */
+ flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS);
+ if (!(flags & PCI_MSI_FLAGS_ENABLE))
+ return -EINVAL;
+
+ /* Get the number of enabled MSIs */
+ mme = FIELD_GET(PCI_MSI_FLAGS_QSIZE, flags);
+ msi_count = 1 << mme;
+ if (!interrupt_num || interrupt_num > msi_count)
+ return -EINVAL;
+
+ /* Compute the data value to be written. */
+ data_mask = msi_count - 1;
+ data = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_DATA_64);
+ data = data & ~data_mask;
+
+ /* Get the PCI address where to write the data into. */
+ pci_addr = cdns_pcie_ep_fn_readl(pcie, fn, cap + PCI_MSI_ADDRESS_HI);
+ pci_addr <<= 32;
+ pci_addr |= cdns_pcie_ep_fn_readl(pcie, fn, cap + PCI_MSI_ADDRESS_LO);
+ pci_addr &= GENMASK_ULL(63, 2);
+
+ for (i = 0; i < interrupt_num; i++) {
+ ret = epc->ops->map_addr(epc, fn, vfn, addr,
+ pci_addr & ~pci_addr_mask,
+ entry_size);
+ if (ret)
+ return ret;
+ addr = addr + entry_size;
+ }
+
+ *msi_data = data;
+ *msi_addr_offset = pci_addr & pci_addr_mask;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_ep_map_msi_irq);
+
+static const struct pci_epc_features cdns_pcie_epc_vf_features = {
+ .linkup_notifier = false,
+ .msi_capable = true,
+ .msix_capable = true,
+ .align = 65536,
+};
+
+static const struct pci_epc_features cdns_pcie_epc_features = {
+ .linkup_notifier = false,
+ .msi_capable = true,
+ .msix_capable = true,
+ .align = 256,
+};
+
+const struct pci_epc_features*
+cdns_pcie_ep_get_features(struct pci_epc *epc, u8 func_no, u8 vfunc_no)
+{
+ if (!vfunc_no)
+ return &cdns_pcie_epc_features;
+
+ return &cdns_pcie_epc_vf_features;
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_ep_get_features);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cadence PCIe controller driver");
+MODULE_AUTHOR("Manikandan K Pillai <mpillai@cadence.com>");
diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep-common.h b/drivers/pci/controller/cadence/pcie-cadence-ep-common.h
new file mode 100644
index 000000000000..a91084bdedd5
--- /dev/null
+++ b/drivers/pci/controller/cadence/pcie-cadence-ep-common.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (c) 2017 Cadence
+// Cadence PCIe Endpoint controller driver.
+// Author: Manikandan K Pillai <mpillai@cadence.com>
+
+#ifndef _PCIE_CADENCE_EP_COMMON_H_
+#define _PCIE_CADENCE_EP_COMMON_H_
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/pci-epf.h>
+#include <linux/pci-epc.h>
+#include "../../pci.h"
+
+#define CDNS_PCIE_EP_MIN_APERTURE 128 /* 128 bytes */
+#define CDNS_PCIE_EP_IRQ_PCI_ADDR_NONE 0x1
+#define CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY 0x3
+
+u8 cdns_pcie_get_fn_from_vfn(struct cdns_pcie *pcie, u8 fn, u8 vfn);
+int cdns_pcie_ep_write_header(struct pci_epc *epc, u8 fn, u8 vfn,
+ struct pci_epf_header *hdr);
+int cdns_pcie_ep_set_msi(struct pci_epc *epc, u8 fn, u8 vfn, u8 mmc);
+int cdns_pcie_ep_get_msi(struct pci_epc *epc, u8 fn, u8 vfn);
+int cdns_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no);
+int cdns_pcie_ep_set_msix(struct pci_epc *epc, u8 fn, u8 vfn,
+ u16 interrupts, enum pci_barno bir,
+ u32 offset);
+int cdns_pcie_ep_map_msi_irq(struct pci_epc *epc, u8 fn, u8 vfn,
+ phys_addr_t addr, u8 interrupt_num,
+ u32 entry_size, u32 *msi_data,
+ u32 *msi_addr_offset);
+const struct pci_epc_features *cdns_pcie_ep_get_features(struct pci_epc *epc,
+ u8 func_no,
+ u8 vfunc_no);
+
+#endif /* _PCIE_CADENCE_EP_COMMON_H_ */
diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c
index 77c5a19b2ab1..83204efaea3f 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-ep.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c
@@ -13,68 +13,7 @@
#include <linux/sizes.h>
#include "pcie-cadence.h"
-#include "../../pci.h"
-
-#define CDNS_PCIE_EP_MIN_APERTURE 128 /* 128 bytes */
-#define CDNS_PCIE_EP_IRQ_PCI_ADDR_NONE 0x1
-#define CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY 0x3
-
-static u8 cdns_pcie_get_fn_from_vfn(struct cdns_pcie *pcie, u8 fn, u8 vfn)
-{
- u32 cap = CDNS_PCIE_EP_FUNC_SRIOV_CAP_OFFSET;
- u32 first_vf_offset, stride;
-
- if (vfn == 0)
- return fn;
-
- first_vf_offset = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_SRIOV_VF_OFFSET);
- stride = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_SRIOV_VF_STRIDE);
- fn = fn + first_vf_offset + ((vfn - 1) * stride);
-
- return fn;
-}
-
-static int cdns_pcie_ep_write_header(struct pci_epc *epc, u8 fn, u8 vfn,
- struct pci_epf_header *hdr)
-{
- struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
- u32 cap = CDNS_PCIE_EP_FUNC_SRIOV_CAP_OFFSET;
- struct cdns_pcie *pcie = &ep->pcie;
- u32 reg;
-
- if (vfn > 1) {
- dev_err(&epc->dev, "Only Virtual Function #1 has deviceID\n");
- return -EINVAL;
- } else if (vfn == 1) {
- reg = cap + PCI_SRIOV_VF_DID;
- cdns_pcie_ep_fn_writew(pcie, fn, reg, hdr->deviceid);
- return 0;
- }
-
- 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;
-}
+#include "pcie-cadence-ep-common.h"
static int cdns_pcie_ep_set_bar(struct pci_epc *epc, u8 fn, u8 vfn,
struct pci_epf_bar *epf_bar)
@@ -222,100 +161,6 @@ static void cdns_pcie_ep_unmap_addr(struct pci_epc *epc, u8 fn, u8 vfn,
clear_bit(r, &ep->ob_region_map);
}
-static int cdns_pcie_ep_set_msi(struct pci_epc *epc, u8 fn, u8 vfn, u8 nr_irqs)
-{
- struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
- struct cdns_pcie *pcie = &ep->pcie;
- u8 mmc = order_base_2(nr_irqs);
- u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET;
- u16 flags;
-
- fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn);
-
- /*
- * Set the Multiple Message Capable bitfield into the Message Control
- * register.
- */
- flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS);
- flags = (flags & ~PCI_MSI_FLAGS_QMASK) | (mmc << 1);
- flags |= PCI_MSI_FLAGS_64BIT;
- flags &= ~PCI_MSI_FLAGS_MASKBIT;
- cdns_pcie_ep_fn_writew(pcie, fn, cap + PCI_MSI_FLAGS, flags);
-
- return 0;
-}
-
-static int cdns_pcie_ep_get_msi(struct pci_epc *epc, u8 fn, u8 vfn)
-{
- struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
- struct cdns_pcie *pcie = &ep->pcie;
- u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET;
- u16 flags, mme;
-
- fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn);
-
- /* Validate that the MSI feature is actually enabled. */
- flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS);
- if (!(flags & PCI_MSI_FLAGS_ENABLE))
- return -EINVAL;
-
- /*
- * Get the Multiple Message Enable bitfield from the Message Control
- * register.
- */
- mme = FIELD_GET(PCI_MSI_FLAGS_QSIZE, flags);
-
- return 1 << mme;
-}
-
-static int cdns_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_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;
-
- func_no = cdns_pcie_get_fn_from_vfn(pcie, func_no, vfunc_no);
-
- 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 + 1;
-}
-
-static int cdns_pcie_ep_set_msix(struct pci_epc *epc, u8 fn, u8 vfn,
- u16 nr_irqs, 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;
-
- fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn);
-
- reg = cap + PCI_MSIX_FLAGS;
- val = cdns_pcie_ep_fn_readw(pcie, fn, reg);
- val &= ~PCI_MSIX_FLAGS_QSIZE;
- val |= nr_irqs - 1; /* encoded as N-1 */
- cdns_pcie_ep_fn_writew(pcie, fn, reg, val);
-
- /* Set MSI-X 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 MSI-X BAR */
- reg = cap + PCI_MSIX_PBA;
- val = (offset + (nr_irqs * 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)
{
@@ -426,59 +271,6 @@ static int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn, u8 vfn,
return 0;
}
-static int cdns_pcie_ep_map_msi_irq(struct pci_epc *epc, u8 fn, u8 vfn,
- phys_addr_t addr, u8 interrupt_num,
- u32 entry_size, u32 *msi_data,
- u32 *msi_addr_offset)
-{
- struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
- u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET;
- struct cdns_pcie *pcie = &ep->pcie;
- u64 pci_addr, pci_addr_mask = 0xff;
- u16 flags, mme, data, data_mask;
- u8 msi_count;
- int ret;
- int i;
-
- fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn);
-
- /* Check whether the MSI feature has been enabled by the PCI host. */
- flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS);
- if (!(flags & PCI_MSI_FLAGS_ENABLE))
- return -EINVAL;
-
- /* Get the number of enabled MSIs */
- mme = FIELD_GET(PCI_MSI_FLAGS_QSIZE, flags);
- msi_count = 1 << mme;
- if (!interrupt_num || interrupt_num > msi_count)
- return -EINVAL;
-
- /* Compute the data value to be written. */
- data_mask = msi_count - 1;
- data = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_DATA_64);
- data = data & ~data_mask;
-
- /* Get the PCI address where to write the data into. */
- pci_addr = cdns_pcie_ep_fn_readl(pcie, fn, cap + PCI_MSI_ADDRESS_HI);
- pci_addr <<= 32;
- pci_addr |= cdns_pcie_ep_fn_readl(pcie, fn, cap + PCI_MSI_ADDRESS_LO);
- pci_addr &= GENMASK_ULL(63, 2);
-
- for (i = 0; i < interrupt_num; i++) {
- ret = cdns_pcie_ep_map_addr(epc, fn, vfn, addr,
- pci_addr & ~pci_addr_mask,
- entry_size);
- if (ret)
- return ret;
- addr = addr + entry_size;
- }
-
- *msi_data = data;
- *msi_addr_offset = pci_addr & pci_addr_mask;
-
- return 0;
-}
-
static int cdns_pcie_ep_send_msix_irq(struct cdns_pcie_ep *ep, u8 fn, u8 vfn,
u16 interrupt_num)
{
@@ -589,12 +381,12 @@ static int cdns_pcie_ep_start(struct pci_epc *epc)
continue;
value = cdns_pcie_ep_fn_readl(pcie, epf,
- CDNS_PCIE_EP_FUNC_DEV_CAP_OFFSET +
- PCI_EXP_DEVCAP);
+ CDNS_PCIE_EP_FUNC_DEV_CAP_OFFSET +
+ PCI_EXP_DEVCAP);
value &= ~PCI_EXP_DEVCAP_FLR;
cdns_pcie_ep_fn_writel(pcie, epf,
- CDNS_PCIE_EP_FUNC_DEV_CAP_OFFSET +
- PCI_EXP_DEVCAP, value);
+ CDNS_PCIE_EP_FUNC_DEV_CAP_OFFSET +
+ PCI_EXP_DEVCAP, value);
}
}
@@ -607,29 +399,6 @@ static int cdns_pcie_ep_start(struct pci_epc *epc)
return 0;
}
-static const struct pci_epc_features cdns_pcie_epc_vf_features = {
- .linkup_notifier = false,
- .msi_capable = true,
- .msix_capable = true,
- .align = 65536,
-};
-
-static const struct pci_epc_features cdns_pcie_epc_features = {
- .linkup_notifier = false,
- .msi_capable = true,
- .msix_capable = true,
- .align = 256,
-};
-
-static const struct pci_epc_features*
-cdns_pcie_ep_get_features(struct pci_epc *epc, u8 func_no, u8 vfunc_no)
-{
- if (!vfunc_no)
- return &cdns_pcie_epc_features;
-
- return &cdns_pcie_epc_vf_features;
-}
-
static const struct pci_epc_ops cdns_pcie_epc_ops = {
.write_header = cdns_pcie_ep_write_header,
.set_bar = cdns_pcie_ep_set_bar,
@@ -759,7 +528,7 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
return 0;
- free_epc_mem:
+free_epc_mem:
pci_epc_mem_exit(epc);
return ret;
--
2.49.0
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH v7 05/13] PCI: cadence: Split PCIe RP support into common and specific functions
2025-08-13 4:23 [PATCH v7 00/13] Enhance the PCIe controller driver for next generation controllers hans.zhang
` (3 preceding siblings ...)
2025-08-13 4:23 ` [PATCH v7 04/13] PCI: cadence: Split PCIe EP support into common and specific functions hans.zhang
@ 2025-08-13 4:23 ` hans.zhang
2025-08-14 21:48 ` Bjorn Helgaas
2025-08-13 4:23 ` [PATCH v7 06/13] PCI: cadence: Split the common functions for PCIe controller support hans.zhang
` (8 subsequent siblings)
13 siblings, 1 reply; 40+ messages in thread
From: hans.zhang @ 2025-08-13 4:23 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kw, mani, robh, kwilczynski, krzk+dt,
conor+dt
Cc: mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel,
Hans Zhang
From: Manikandan K Pillai <mpillai@cadence.com>
Split the Cadence PCIe controller RP functionality into common
functions and functions for legacy PCIe RP controller.
Signed-off-by: Manikandan K Pillai <mpillai@cadence.com>
Co-developed-by: Hans Zhang <hans.zhang@cixtech.com>
Signed-off-by: Hans Zhang <hans.zhang@cixtech.com>
---
drivers/pci/controller/cadence/Makefile | 2 +-
.../cadence/pcie-cadence-ep-common.h | 8 +-
.../cadence/pcie-cadence-host-common.c | 181 ++++++++++++++++++
.../cadence/pcie-cadence-host-common.h | 25 +++
.../controller/cadence/pcie-cadence-host.c | 156 +--------------
5 files changed, 212 insertions(+), 160 deletions(-)
create mode 100644 drivers/pci/controller/cadence/pcie-cadence-host-common.c
create mode 100644 drivers/pci/controller/cadence/pcie-cadence-host-common.h
diff --git a/drivers/pci/controller/cadence/Makefile b/drivers/pci/controller/cadence/Makefile
index 80c1c4be7e80..e45f72388bbb 100644
--- a/drivers/pci/controller/cadence/Makefile
+++ b/drivers/pci/controller/cadence/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_PCIE_CADENCE) += pcie-cadence.o
-obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o
+obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host-common.o pcie-cadence-host.o
obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep-common.o 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/pcie-cadence-ep-common.h b/drivers/pci/controller/cadence/pcie-cadence-ep-common.h
index a91084bdedd5..9cfd0cfa7459 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-ep-common.h
+++ b/drivers/pci/controller/cadence/pcie-cadence-ep-common.h
@@ -1,10 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0 */
// Copyright (c) 2017 Cadence
-// Cadence PCIe Endpoint controller driver.
+// Cadence PCIe Endpoint controller driver
// Author: Manikandan K Pillai <mpillai@cadence.com>
-#ifndef _PCIE_CADENCE_EP_COMMON_H_
-#define _PCIE_CADENCE_EP_COMMON_H_
+#ifndef _PCIE_CADENCE_EP_COMMON_H
+#define _PCIE_CADENCE_EP_COMMON_H
#include <linux/kernel.h>
#include <linux/pci.h>
@@ -33,4 +33,4 @@ const struct pci_epc_features *cdns_pcie_ep_get_features(struct pci_epc *epc,
u8 func_no,
u8 vfunc_no);
-#endif /* _PCIE_CADENCE_EP_COMMON_H_ */
+#endif /* _PCIE_CADENCE_EP_COMMON_H */
diff --git a/drivers/pci/controller/cadence/pcie-cadence-host-common.c b/drivers/pci/controller/cadence/pcie-cadence-host-common.c
new file mode 100644
index 000000000000..5625c64c7974
--- /dev/null
+++ b/drivers/pci/controller/cadence/pcie-cadence-host-common.c
@@ -0,0 +1,181 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2017 Cadence
+// Cadence PCIe host controller driver.
+// Author: Manikandan K Pillai <mpillai@cadence.com>
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/list_sort.h>
+#include <linux/of_address.h>
+#include <linux/of_pci.h>
+#include <linux/platform_device.h>
+
+#include "pcie-cadence.h"
+#include "pcie-cadence-host-common.h"
+
+#define LINK_RETRAIN_TIMEOUT HZ
+
+u64 bar_max_size[] = {
+ [RP_BAR0] = _ULL(128 * SZ_2G),
+ [RP_BAR1] = SZ_2G,
+ [RP_NO_BAR] = _BITULL(63),
+};
+EXPORT_SYMBOL_GPL(bar_max_size);
+
+int cdns_pcie_host_training_complete(struct cdns_pcie *pcie)
+{
+ u32 pcie_cap_off = CDNS_PCIE_RP_CAP_OFFSET;
+ unsigned long end_jiffies;
+ u16 lnk_stat;
+
+ /* Wait for link training to complete. Exit after timeout. */
+ end_jiffies = jiffies + LINK_RETRAIN_TIMEOUT;
+ do {
+ lnk_stat = cdns_pcie_rp_readw(pcie, pcie_cap_off + PCI_EXP_LNKSTA);
+ if (!(lnk_stat & PCI_EXP_LNKSTA_LT))
+ break;
+ usleep_range(0, 1000);
+ } while (time_before(jiffies, end_jiffies));
+
+ if (!(lnk_stat & PCI_EXP_LNKSTA_LT))
+ return 0;
+
+ return -ETIMEDOUT;
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_host_training_complete);
+
+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;
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_host_wait_for_link);
+
+int cdns_pcie_retrain(struct cdns_pcie *pcie)
+{
+ u32 lnk_cap_sls, pcie_cap_off = CDNS_PCIE_RP_CAP_OFFSET;
+ u16 lnk_stat, lnk_ctl;
+ int ret = 0;
+
+ /*
+ * Set retrain bit if current speed is 2.5 GB/s,
+ * but the PCIe root port support is > 2.5 GB/s.
+ */
+
+ lnk_cap_sls = cdns_pcie_readl(pcie, (CDNS_PCIE_RP_BASE + pcie_cap_off +
+ PCI_EXP_LNKCAP));
+ if ((lnk_cap_sls & PCI_EXP_LNKCAP_SLS) <= PCI_EXP_LNKCAP_SLS_2_5GB)
+ return ret;
+
+ lnk_stat = cdns_pcie_rp_readw(pcie, pcie_cap_off + PCI_EXP_LNKSTA);
+ if ((lnk_stat & PCI_EXP_LNKSTA_CLS) == PCI_EXP_LNKSTA_CLS_2_5GB) {
+ lnk_ctl = cdns_pcie_rp_readw(pcie,
+ pcie_cap_off + PCI_EXP_LNKCTL);
+ lnk_ctl |= PCI_EXP_LNKCTL_RL;
+ cdns_pcie_rp_writew(pcie, pcie_cap_off + PCI_EXP_LNKCTL,
+ lnk_ctl);
+
+ ret = cdns_pcie_host_training_complete(pcie);
+ if (ret)
+ return ret;
+
+ ret = cdns_pcie_host_wait_for_link(pcie);
+ }
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_retrain);
+
+int cdns_pcie_host_start_link(struct cdns_pcie_rc *rc)
+{
+ struct cdns_pcie *pcie = &rc->pcie;
+ int ret;
+
+ ret = cdns_pcie_host_wait_for_link(pcie);
+
+ /*
+ * Retrain link for Gen2 training defect
+ * if quirk flag is set.
+ */
+ if (!ret && rc->quirk_retrain_flag)
+ ret = cdns_pcie_retrain(pcie);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_host_start_link);
+
+enum cdns_pcie_rp_bar
+cdns_pcie_host_find_min_bar(struct cdns_pcie_rc *rc, u64 size)
+{
+ enum cdns_pcie_rp_bar bar, sel_bar;
+
+ sel_bar = RP_BAR_UNDEFINED;
+ for (bar = RP_BAR0; bar <= RP_NO_BAR; bar++) {
+ if (!rc->avail_ib_bar[bar])
+ continue;
+
+ if (size <= bar_max_size[bar]) {
+ if (sel_bar == RP_BAR_UNDEFINED) {
+ sel_bar = bar;
+ continue;
+ }
+
+ if (bar_max_size[bar] < bar_max_size[sel_bar])
+ sel_bar = bar;
+ }
+ }
+
+ return sel_bar;
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_host_find_min_bar);
+
+enum cdns_pcie_rp_bar
+cdns_pcie_host_find_max_bar(struct cdns_pcie_rc *rc, u64 size)
+{
+ enum cdns_pcie_rp_bar bar, sel_bar;
+
+ sel_bar = RP_BAR_UNDEFINED;
+ for (bar = RP_BAR0; bar <= RP_NO_BAR; bar++) {
+ if (!rc->avail_ib_bar[bar])
+ continue;
+
+ if (size >= bar_max_size[bar]) {
+ if (sel_bar == RP_BAR_UNDEFINED) {
+ sel_bar = bar;
+ continue;
+ }
+
+ if (bar_max_size[bar] > bar_max_size[sel_bar])
+ sel_bar = bar;
+ }
+ }
+
+ return sel_bar;
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_host_find_max_bar);
+
+int cdns_pcie_host_dma_ranges_cmp(void *priv, const struct list_head *a,
+ const struct list_head *b)
+{
+ struct resource_entry *entry1, *entry2;
+
+ entry1 = container_of(a, struct resource_entry, node);
+ entry2 = container_of(b, struct resource_entry, node);
+
+ return resource_size(entry2->res) - resource_size(entry1->res);
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_host_dma_ranges_cmp);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cadence PCIe controller driver");
+MODULE_AUTHOR("Manikandan K Pillai <mpillai@cadence.com>");
diff --git a/drivers/pci/controller/cadence/pcie-cadence-host-common.h b/drivers/pci/controller/cadence/pcie-cadence-host-common.h
new file mode 100644
index 000000000000..f8eae2e963d8
--- /dev/null
+++ b/drivers/pci/controller/cadence/pcie-cadence-host-common.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (c) 2017 Cadence
+// Cadence PCIe Endpoint controller driver
+// Author: Manikandan K Pillai <mpillai@cadence.com>
+
+#ifndef _PCIE_CADENCE_HOST_COMMON_H
+#define _PCIE_CADENCE_HOST_COMMON_H
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+extern u64 bar_max_size[];
+
+int cdns_pcie_host_training_complete(struct cdns_pcie *pcie);
+int cdns_pcie_host_wait_for_link(struct cdns_pcie *pcie);
+int cdns_pcie_retrain(struct cdns_pcie *pcie);
+int cdns_pcie_host_start_link(struct cdns_pcie_rc *rc);
+enum cdns_pcie_rp_bar
+cdns_pcie_host_find_min_bar(struct cdns_pcie_rc *rc, u64 size);
+enum cdns_pcie_rp_bar
+cdns_pcie_host_find_max_bar(struct cdns_pcie_rc *rc, u64 size);
+int cdns_pcie_host_dma_ranges_cmp(void *priv, const struct list_head *a,
+ const struct list_head *b);
+
+#endif /* _PCIE_CADENCE_HOST_COMMON_H */
diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c
index 59a4631de79f..bfdd0f200cfb 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -12,14 +12,7 @@
#include <linux/platform_device.h>
#include "pcie-cadence.h"
-
-#define LINK_RETRAIN_TIMEOUT HZ
-
-static u64 bar_max_size[] = {
- [RP_BAR0] = _ULL(128 * SZ_2G),
- [RP_BAR1] = SZ_2G,
- [RP_NO_BAR] = _BITULL(63),
-};
+#include "pcie-cadence-host-common.h"
static u8 bar_aperture_mask[] = {
[RP_BAR0] = 0x1F,
@@ -81,77 +74,6 @@ static struct pci_ops cdns_pcie_host_ops = {
.write = pci_generic_config_write,
};
-static int cdns_pcie_host_training_complete(struct cdns_pcie *pcie)
-{
- u32 pcie_cap_off = CDNS_PCIE_RP_CAP_OFFSET;
- unsigned long end_jiffies;
- u16 lnk_stat;
-
- /* Wait for link training to complete. Exit after timeout. */
- end_jiffies = jiffies + LINK_RETRAIN_TIMEOUT;
- do {
- lnk_stat = cdns_pcie_rp_readw(pcie, pcie_cap_off + PCI_EXP_LNKSTA);
- if (!(lnk_stat & PCI_EXP_LNKSTA_LT))
- break;
- usleep_range(0, 1000);
- } while (time_before(jiffies, end_jiffies));
-
- if (!(lnk_stat & PCI_EXP_LNKSTA_LT))
- return 0;
-
- return -ETIMEDOUT;
-}
-
-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;
-}
-
-static int cdns_pcie_retrain(struct cdns_pcie *pcie)
-{
- u32 lnk_cap_sls, pcie_cap_off = CDNS_PCIE_RP_CAP_OFFSET;
- u16 lnk_stat, lnk_ctl;
- int ret = 0;
-
- /*
- * Set retrain bit if current speed is 2.5 GB/s,
- * but the PCIe root port support is > 2.5 GB/s.
- */
-
- lnk_cap_sls = cdns_pcie_readl(pcie, (CDNS_PCIE_RP_BASE + pcie_cap_off +
- PCI_EXP_LNKCAP));
- if ((lnk_cap_sls & PCI_EXP_LNKCAP_SLS) <= PCI_EXP_LNKCAP_SLS_2_5GB)
- return ret;
-
- lnk_stat = cdns_pcie_rp_readw(pcie, pcie_cap_off + PCI_EXP_LNKSTA);
- if ((lnk_stat & PCI_EXP_LNKSTA_CLS) == PCI_EXP_LNKSTA_CLS_2_5GB) {
- lnk_ctl = cdns_pcie_rp_readw(pcie,
- pcie_cap_off + PCI_EXP_LNKCTL);
- lnk_ctl |= PCI_EXP_LNKCTL_RL;
- cdns_pcie_rp_writew(pcie, pcie_cap_off + PCI_EXP_LNKCTL,
- lnk_ctl);
-
- ret = cdns_pcie_host_training_complete(pcie);
- if (ret)
- return ret;
-
- ret = cdns_pcie_host_wait_for_link(pcie);
- }
- return ret;
-}
-
static void cdns_pcie_host_disable_ptm_response(struct cdns_pcie *pcie)
{
u32 val;
@@ -168,23 +90,6 @@ static void cdns_pcie_host_enable_ptm_response(struct cdns_pcie *pcie)
cdns_pcie_writel(pcie, CDNS_PCIE_LM_PTM_CTRL, val | CDNS_PCIE_LM_TPM_CTRL_PTMRSEN);
}
-static int cdns_pcie_host_start_link(struct cdns_pcie_rc *rc)
-{
- struct cdns_pcie *pcie = &rc->pcie;
- int ret;
-
- ret = cdns_pcie_host_wait_for_link(pcie);
-
- /*
- * Retrain link for Gen2 training defect
- * if quirk flag is set.
- */
- if (!ret && rc->quirk_retrain_flag)
- ret = cdns_pcie_retrain(pcie);
-
- return ret;
-}
-
static void cdns_pcie_host_deinit_root_port(struct cdns_pcie_rc *rc)
{
struct cdns_pcie *pcie = &rc->pcie;
@@ -290,54 +195,6 @@ static int cdns_pcie_host_bar_ib_config(struct cdns_pcie_rc *rc,
return 0;
}
-static enum cdns_pcie_rp_bar
-cdns_pcie_host_find_min_bar(struct cdns_pcie_rc *rc, u64 size)
-{
- enum cdns_pcie_rp_bar bar, sel_bar;
-
- sel_bar = RP_BAR_UNDEFINED;
- for (bar = RP_BAR0; bar <= RP_NO_BAR; bar++) {
- if (!rc->avail_ib_bar[bar])
- continue;
-
- if (size <= bar_max_size[bar]) {
- if (sel_bar == RP_BAR_UNDEFINED) {
- sel_bar = bar;
- continue;
- }
-
- if (bar_max_size[bar] < bar_max_size[sel_bar])
- sel_bar = bar;
- }
- }
-
- return sel_bar;
-}
-
-static enum cdns_pcie_rp_bar
-cdns_pcie_host_find_max_bar(struct cdns_pcie_rc *rc, u64 size)
-{
- enum cdns_pcie_rp_bar bar, sel_bar;
-
- sel_bar = RP_BAR_UNDEFINED;
- for (bar = RP_BAR0; bar <= RP_NO_BAR; bar++) {
- if (!rc->avail_ib_bar[bar])
- continue;
-
- if (size >= bar_max_size[bar]) {
- if (sel_bar == RP_BAR_UNDEFINED) {
- sel_bar = bar;
- continue;
- }
-
- if (bar_max_size[bar] > bar_max_size[sel_bar])
- sel_bar = bar;
- }
- }
-
- return sel_bar;
-}
-
static int cdns_pcie_host_bar_config(struct cdns_pcie_rc *rc,
struct resource_entry *entry)
{
@@ -410,17 +267,6 @@ static int cdns_pcie_host_bar_config(struct cdns_pcie_rc *rc,
return 0;
}
-static int cdns_pcie_host_dma_ranges_cmp(void *priv, const struct list_head *a,
- const struct list_head *b)
-{
- struct resource_entry *entry1, *entry2;
-
- entry1 = container_of(a, struct resource_entry, node);
- entry2 = container_of(b, struct resource_entry, node);
-
- return resource_size(entry2->res) - resource_size(entry1->res);
-}
-
static void cdns_pcie_host_unmap_dma_ranges(struct cdns_pcie_rc *rc)
{
struct cdns_pcie *pcie = &rc->pcie;
--
2.49.0
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH v7 06/13] PCI: cadence: Split the common functions for PCIe controller support
2025-08-13 4:23 [PATCH v7 00/13] Enhance the PCIe controller driver for next generation controllers hans.zhang
` (4 preceding siblings ...)
2025-08-13 4:23 ` [PATCH v7 05/13] PCI: cadence: Split PCIe RP " hans.zhang
@ 2025-08-13 4:23 ` hans.zhang
2025-08-13 4:23 ` [PATCH v7 07/13] PCI: cadence: Add support for High Performance Arch(HPA) controller hans.zhang
` (7 subsequent siblings)
13 siblings, 0 replies; 40+ messages in thread
From: hans.zhang @ 2025-08-13 4:23 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kw, mani, robh, kwilczynski, krzk+dt,
conor+dt
Cc: mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel,
Hans Zhang
From: Manikandan K Pillai <mpillai@cadence.com>
Separate the functions for platform specific tasks and common
library tasks into different files.
Signed-off-by: Manikandan K Pillai <mpillai@cadence.com>
Co-developed-by: Hans Zhang <hans.zhang@cixtech.com>
Signed-off-by: Hans Zhang <hans.zhang@cixtech.com>
---
drivers/pci/controller/cadence/Makefile | 2 +-
.../controller/cadence/pcie-cadence-common.c | 142 ++++++++++++++++++
drivers/pci/controller/cadence/pcie-cadence.c | 129 ----------------
3 files changed, 143 insertions(+), 130 deletions(-)
create mode 100644 drivers/pci/controller/cadence/pcie-cadence-common.c
diff --git a/drivers/pci/controller/cadence/Makefile b/drivers/pci/controller/cadence/Makefile
index e45f72388bbb..b104562fb86a 100644
--- a/drivers/pci/controller/cadence/Makefile
+++ b/drivers/pci/controller/cadence/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_PCIE_CADENCE) += pcie-cadence.o
+obj-$(CONFIG_PCIE_CADENCE) += pcie-cadence-common.o pcie-cadence.o
obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host-common.o pcie-cadence-host.o
obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep-common.o pcie-cadence-ep.o
obj-$(CONFIG_PCIE_CADENCE_PLAT) += pcie-cadence-plat.o
diff --git a/drivers/pci/controller/cadence/pcie-cadence-common.c b/drivers/pci/controller/cadence/pcie-cadence-common.c
new file mode 100644
index 000000000000..23c5ab6637fb
--- /dev/null
+++ b/drivers/pci/controller/cadence/pcie-cadence-common.c
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2017 Cadence
+// Cadence PCIe controller driver.
+// Author: Manikandan K Pillai <mpillai@cadence.com>
+
+#include <linux/kernel.h>
+#include <linux/of.h>
+
+#include "pcie-cadence.h"
+
+void cdns_pcie_disable_phy(struct cdns_pcie *pcie)
+{
+ int i = pcie->phy_count;
+
+ while (i--) {
+ phy_power_off(pcie->phy[i]);
+ phy_exit(pcie->phy[i]);
+ }
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_disable_phy);
+
+int cdns_pcie_enable_phy(struct cdns_pcie *pcie)
+{
+ int ret;
+ int i;
+
+ for (i = 0; i < pcie->phy_count; i++) {
+ ret = phy_init(pcie->phy[i]);
+ if (ret < 0)
+ goto err_phy;
+
+ ret = phy_power_on(pcie->phy[i]);
+ if (ret < 0) {
+ phy_exit(pcie->phy[i]);
+ goto err_phy;
+ }
+ }
+
+ return 0;
+
+err_phy:
+ while (--i >= 0) {
+ phy_power_off(pcie->phy[i]);
+ phy_exit(pcie->phy[i]);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_enable_phy);
+
+int cdns_pcie_init_phy(struct device *dev, struct cdns_pcie *pcie)
+{
+ struct device_node *np = dev->of_node;
+ int phy_count;
+ struct phy **phy;
+ struct device_link **link;
+ int i;
+ int ret;
+ const char *name;
+
+ phy_count = of_property_count_strings(np, "phy-names");
+ if (phy_count < 1) {
+ dev_info(dev, "no \"phy-names\" property found; PHY will not be initialized\n");
+ pcie->phy_count = 0;
+ return 0;
+ }
+
+ phy = devm_kcalloc(dev, phy_count, sizeof(*phy), GFP_KERNEL);
+ if (!phy)
+ return -ENOMEM;
+
+ link = devm_kcalloc(dev, phy_count, sizeof(*link), GFP_KERNEL);
+ if (!link)
+ return -ENOMEM;
+
+ for (i = 0; i < phy_count; i++) {
+ of_property_read_string_index(np, "phy-names", i, &name);
+ phy[i] = devm_phy_get(dev, name);
+ if (IS_ERR(phy[i])) {
+ ret = PTR_ERR(phy[i]);
+ goto err_phy;
+ }
+ link[i] = device_link_add(dev, &phy[i]->dev, DL_FLAG_STATELESS);
+ if (!link[i]) {
+ devm_phy_put(dev, phy[i]);
+ ret = -EINVAL;
+ goto err_phy;
+ }
+ }
+
+ pcie->phy_count = phy_count;
+ pcie->phy = phy;
+ pcie->link = link;
+
+ ret = cdns_pcie_enable_phy(pcie);
+ if (ret)
+ goto err_phy;
+
+ return 0;
+
+err_phy:
+ while (--i >= 0) {
+ device_link_del(link[i]);
+ devm_phy_put(dev, phy[i]);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_init_phy);
+
+static int cdns_pcie_suspend_noirq(struct device *dev)
+{
+ struct cdns_pcie *pcie = dev_get_drvdata(dev);
+
+ cdns_pcie_disable_phy(pcie);
+
+ return 0;
+}
+
+static int cdns_pcie_resume_noirq(struct device *dev)
+{
+ struct cdns_pcie *pcie = dev_get_drvdata(dev);
+ int ret;
+
+ ret = cdns_pcie_enable_phy(pcie);
+ if (ret) {
+ dev_err(dev, "failed to enable PHY\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+const struct dev_pm_ops cdns_pcie_pm_ops = {
+ NOIRQ_SYSTEM_SLEEP_PM_OPS(cdns_pcie_suspend_noirq,
+ cdns_pcie_resume_noirq)
+};
+EXPORT_SYMBOL_GPL(cdns_pcie_pm_ops);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cadence PCIe controller driver");
+MODULE_AUTHOR("Manikandan K Pillai <mpillai@cadence.com>");
diff --git a/drivers/pci/controller/cadence/pcie-cadence.c b/drivers/pci/controller/cadence/pcie-cadence.c
index 5603f214f4c7..51c9bc4eb174 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.c
+++ b/drivers/pci/controller/cadence/pcie-cadence.c
@@ -152,135 +152,6 @@ void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r)
}
EXPORT_SYMBOL_GPL(cdns_pcie_reset_outbound_region);
-void cdns_pcie_disable_phy(struct cdns_pcie *pcie)
-{
- int i = pcie->phy_count;
-
- while (i--) {
- phy_power_off(pcie->phy[i]);
- phy_exit(pcie->phy[i]);
- }
-}
-EXPORT_SYMBOL_GPL(cdns_pcie_disable_phy);
-
-int cdns_pcie_enable_phy(struct cdns_pcie *pcie)
-{
- int ret;
- int i;
-
- for (i = 0; i < pcie->phy_count; i++) {
- ret = phy_init(pcie->phy[i]);
- if (ret < 0)
- goto err_phy;
-
- ret = phy_power_on(pcie->phy[i]);
- if (ret < 0) {
- phy_exit(pcie->phy[i]);
- goto err_phy;
- }
- }
-
- return 0;
-
-err_phy:
- while (--i >= 0) {
- phy_power_off(pcie->phy[i]);
- phy_exit(pcie->phy[i]);
- }
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(cdns_pcie_enable_phy);
-
-int cdns_pcie_init_phy(struct device *dev, struct cdns_pcie *pcie)
-{
- struct device_node *np = dev->of_node;
- int phy_count;
- struct phy **phy;
- struct device_link **link;
- int i;
- int ret;
- const char *name;
-
- phy_count = of_property_count_strings(np, "phy-names");
- if (phy_count < 1) {
- dev_info(dev, "no \"phy-names\" property found; PHY will not be initialized\n");
- pcie->phy_count = 0;
- return 0;
- }
-
- phy = devm_kcalloc(dev, phy_count, sizeof(*phy), GFP_KERNEL);
- if (!phy)
- return -ENOMEM;
-
- link = devm_kcalloc(dev, phy_count, sizeof(*link), GFP_KERNEL);
- if (!link)
- return -ENOMEM;
-
- for (i = 0; i < phy_count; i++) {
- of_property_read_string_index(np, "phy-names", i, &name);
- phy[i] = devm_phy_get(dev, name);
- if (IS_ERR(phy[i])) {
- ret = PTR_ERR(phy[i]);
- goto err_phy;
- }
- link[i] = device_link_add(dev, &phy[i]->dev, DL_FLAG_STATELESS);
- if (!link[i]) {
- devm_phy_put(dev, phy[i]);
- ret = -EINVAL;
- goto err_phy;
- }
- }
-
- pcie->phy_count = phy_count;
- pcie->phy = phy;
- pcie->link = link;
-
- ret = cdns_pcie_enable_phy(pcie);
- if (ret)
- goto err_phy;
-
- return 0;
-
-err_phy:
- while (--i >= 0) {
- device_link_del(link[i]);
- devm_phy_put(dev, phy[i]);
- }
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(cdns_pcie_init_phy);
-
-static int cdns_pcie_suspend_noirq(struct device *dev)
-{
- struct cdns_pcie *pcie = dev_get_drvdata(dev);
-
- cdns_pcie_disable_phy(pcie);
-
- return 0;
-}
-
-static int cdns_pcie_resume_noirq(struct device *dev)
-{
- struct cdns_pcie *pcie = dev_get_drvdata(dev);
- int ret;
-
- ret = cdns_pcie_enable_phy(pcie);
- if (ret) {
- dev_err(dev, "failed to enable PHY\n");
- return ret;
- }
-
- return 0;
-}
-
-const struct dev_pm_ops cdns_pcie_pm_ops = {
- NOIRQ_SYSTEM_SLEEP_PM_OPS(cdns_pcie_suspend_noirq,
- cdns_pcie_resume_noirq)
-};
-EXPORT_SYMBOL_GPL(cdns_pcie_pm_ops);
-
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Cadence PCIe controller driver");
MODULE_AUTHOR("Cyrille Pitchen <cyrille.pitchen@free-electrons.com>");
--
2.49.0
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH v7 07/13] PCI: cadence: Add support for High Performance Arch(HPA) controller
2025-08-13 4:23 [PATCH v7 00/13] Enhance the PCIe controller driver for next generation controllers hans.zhang
` (5 preceding siblings ...)
2025-08-13 4:23 ` [PATCH v7 06/13] PCI: cadence: Split the common functions for PCIe controller support hans.zhang
@ 2025-08-13 4:23 ` hans.zhang
2025-08-14 22:14 ` Bjorn Helgaas
2025-08-13 4:23 ` [PATCH v7 08/13] dt-bindings: PCI: Add CIX Sky1 PCIe Root Complex bindings hans.zhang
` (6 subsequent siblings)
13 siblings, 1 reply; 40+ messages in thread
From: hans.zhang @ 2025-08-13 4:23 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kw, mani, robh, kwilczynski, krzk+dt,
conor+dt
Cc: mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel,
Hans Zhang
From: Manikandan K Pillai <mpillai@cadence.com>
Add support for Cadence PCIe RP and EP configuration for High
Performance Architecture(HPA) controllers
Signed-off-by: Manikandan K Pillai <mpillai@cadence.com>
Co-developed-by: Hans Zhang <hans.zhang@cixtech.com>
Signed-off-by: Hans Zhang <hans.zhang@cixtech.com>
---
drivers/pci/controller/cadence/Makefile | 10 +-
.../controller/cadence/pcie-cadence-ep-hpa.c | 528 ++++++++++++++++
.../cadence/pcie-cadence-host-hpa.c | 586 ++++++++++++++++++
.../pci/controller/cadence/pcie-cadence-hpa.c | 207 +++++++
.../controller/cadence/pcie-cadence-plat.c | 20 +-
drivers/pci/controller/cadence/pcie-cadence.c | 11 +
drivers/pci/controller/cadence/pcie-cadence.h | 91 ++-
7 files changed, 1438 insertions(+), 15 deletions(-)
create mode 100644 drivers/pci/controller/cadence/pcie-cadence-ep-hpa.c
create mode 100644 drivers/pci/controller/cadence/pcie-cadence-host-hpa.c
create mode 100644 drivers/pci/controller/cadence/pcie-cadence-hpa.c
diff --git a/drivers/pci/controller/cadence/Makefile b/drivers/pci/controller/cadence/Makefile
index b104562fb86a..de4ddae7aca4 100644
--- a/drivers/pci/controller/cadence/Makefile
+++ b/drivers/pci/controller/cadence/Makefile
@@ -1,6 +1,10 @@
# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_PCIE_CADENCE) += pcie-cadence-common.o pcie-cadence.o
-obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host-common.o pcie-cadence-host.o
-obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep-common.o pcie-cadence-ep.o
+pcie-cadence-mod-y := pcie-cadence-hpa.o pcie-cadence-common.o pcie-cadence.o
+pcie-cadence-host-mod-y := pcie-cadence-host-common.o pcie-cadence-host.o pcie-cadence-host-hpa.o
+pcie-cadence-ep-mod-y := pcie-cadence-ep-common.o pcie-cadence-ep.o pcie-cadence-ep-hpa.o
+
+obj-$(CONFIG_PCIE_CADENCE) = pcie-cadence-mod.o
+obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host-mod.o
+obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep-mod.o
obj-$(CONFIG_PCIE_CADENCE_PLAT) += pcie-cadence-plat.o
obj-$(CONFIG_PCI_J721E) += pci-j721e.o
diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep-hpa.c b/drivers/pci/controller/cadence/pcie-cadence-ep-hpa.c
new file mode 100644
index 000000000000..36f757820f61
--- /dev/null
+++ b/drivers/pci/controller/cadence/pcie-cadence-ep-hpa.c
@@ -0,0 +1,528 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2017 Cadence
+// Cadence PCIe endpoint controller driver.
+// Author: Manikandan K Pillai <mpillai@cadence.com>
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/pci-epc.h>
+#include <linux/platform_device.h>
+#include <linux/sizes.h>
+
+#include "pcie-cadence.h"
+#include "pcie-cadence-ep-common.h"
+
+static int cdns_pcie_hpa_ep_map_addr(struct pci_epc *epc, u8 fn, u8 vfn,
+ phys_addr_t addr, u64 pci_addr, size_t size)
+{
+ struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+ struct cdns_pcie *pcie = &ep->pcie;
+ u32 r;
+
+ r = find_first_zero_bit(&ep->ob_region_map, BITS_PER_LONG);
+ if (r >= ep->max_regions - 1) {
+ dev_err(&epc->dev, "no free outbound region\n");
+ return -EINVAL;
+ }
+
+ fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn);
+ cdns_pcie_hpa_set_outbound_region(pcie, 0, fn, r, false, addr, pci_addr, size);
+
+ set_bit(r, &ep->ob_region_map);
+ ep->ob_addr[r] = addr;
+
+ return 0;
+}
+
+static void cdns_pcie_hpa_ep_unmap_addr(struct pci_epc *epc, u8 fn, u8 vfn,
+ phys_addr_t addr)
+{
+ struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+ struct cdns_pcie *pcie = &ep->pcie;
+ u32 r;
+
+ for (r = 0; r < ep->max_regions - 1; r++)
+ if (ep->ob_addr[r] == addr)
+ break;
+
+ if (r == ep->max_regions - 1)
+ return;
+
+ cdns_pcie_hpa_reset_outbound_region(pcie, r);
+
+ ep->ob_addr[r] = 0;
+ clear_bit(r, &ep->ob_region_map);
+}
+
+static void cdns_pcie_hpa_ep_assert_intx(struct cdns_pcie_ep *ep, u8 fn, u8 intx,
+ bool is_asserted)
+{
+ struct cdns_pcie *pcie = &ep->pcie;
+ unsigned long flags;
+ u32 offset;
+ u16 status;
+ u8 msg_code;
+
+ intx &= 3;
+
+ /* Set the outbound region if needed. */
+ if (unlikely(ep->irq_pci_addr != CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY ||
+ ep->irq_pci_fn != fn)) {
+ /* First region was reserved for IRQ writes. */
+ cdns_pcie_hpa_set_outbound_region_for_normal_msg(pcie, 0, fn, 0, ep->irq_phys_addr);
+ ep->irq_pci_addr = CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY;
+ ep->irq_pci_fn = fn;
+ }
+
+ if (is_asserted) {
+ ep->irq_pending |= BIT(intx);
+ msg_code = PCIE_MSG_CODE_ASSERT_INTA + intx;
+ } else {
+ ep->irq_pending &= ~BIT(intx);
+ msg_code = PCIE_MSG_CODE_DEASSERT_INTA + intx;
+ }
+
+ spin_lock_irqsave(&ep->lock, flags);
+ status = cdns_pcie_ep_fn_readw(pcie, fn, PCI_STATUS);
+ if (((status & PCI_STATUS_INTERRUPT) != 0) ^ (ep->irq_pending != 0)) {
+ status ^= PCI_STATUS_INTERRUPT;
+ cdns_pcie_ep_fn_writew(pcie, fn, PCI_STATUS, status);
+ }
+ spin_unlock_irqrestore(&ep->lock, flags);
+
+ offset = CDNS_PCIE_NORMAL_MSG_ROUTING(MSG_ROUTING_LOCAL) |
+ CDNS_PCIE_NORMAL_MSG_CODE(msg_code);
+ writel(0, ep->irq_cpu_addr + offset);
+}
+
+static int cdns_pcie_hpa_ep_send_intx_irq(struct cdns_pcie_ep *ep, u8 fn, u8 vfn,
+ u8 intx)
+{
+ u16 cmd;
+
+ cmd = cdns_pcie_ep_fn_readw(&ep->pcie, fn, PCI_COMMAND);
+ if (cmd & PCI_COMMAND_INTX_DISABLE)
+ return -EINVAL;
+
+ cdns_pcie_hpa_ep_assert_intx(ep, fn, intx, true);
+
+ /* The mdelay() value was taken from dra7xx_pcie_raise_intx_irq() */
+ mdelay(1);
+ cdns_pcie_hpa_ep_assert_intx(ep, fn, intx, false);
+ return 0;
+}
+
+static int cdns_pcie_hpa_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn, u8 vfn,
+ u8 interrupt_num)
+{
+ struct cdns_pcie *pcie = &ep->pcie;
+ u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET;
+ u16 flags, mme, data, data_mask;
+ u8 msi_count;
+ u64 pci_addr, pci_addr_mask = 0xff;
+
+ fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn);
+
+ /* Check whether the MSI feature has been enabled by the PCI host. */
+ flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS);
+ if (!(flags & PCI_MSI_FLAGS_ENABLE))
+ return -EINVAL;
+
+ /* Get the number of enabled MSIs */
+ mme = FIELD_GET(PCI_MSI_FLAGS_QSIZE, flags);
+ msi_count = 1 << mme;
+ if (!interrupt_num || interrupt_num > msi_count)
+ return -EINVAL;
+
+ /* Compute the data value to be written. */
+ data_mask = msi_count - 1;
+ data = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_DATA_64);
+ data = (data & ~data_mask) | ((interrupt_num - 1) & data_mask);
+
+ /* Get the PCI address where to write the data into. */
+ pci_addr = cdns_pcie_ep_fn_readl(pcie, fn, cap + PCI_MSI_ADDRESS_HI);
+ pci_addr <<= 32;
+ pci_addr |= cdns_pcie_ep_fn_readl(pcie, fn, cap + PCI_MSI_ADDRESS_LO);
+ pci_addr &= GENMASK_ULL(63, 2);
+
+ /* Set the outbound region if needed. */
+ if (unlikely(ep->irq_pci_addr != (pci_addr & ~pci_addr_mask) ||
+ ep->irq_pci_fn != fn)) {
+ /* First region was reserved for IRQ writes. */
+ cdns_pcie_hpa_set_outbound_region(pcie, 0, fn, 0,
+ false,
+ ep->irq_phys_addr,
+ pci_addr & ~pci_addr_mask,
+ pci_addr_mask + 1);
+ ep->irq_pci_addr = (pci_addr & ~pci_addr_mask);
+ ep->irq_pci_fn = fn;
+ }
+ writel(data, ep->irq_cpu_addr + (pci_addr & pci_addr_mask));
+
+ return 0;
+}
+
+static int cdns_pcie_hpa_ep_send_msix_irq(struct cdns_pcie_ep *ep, u8 fn, u8 vfn,
+ u16 interrupt_num)
+{
+ u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
+ u32 tbl_offset, msg_data, reg;
+ struct cdns_pcie *pcie = &ep->pcie;
+ struct pci_epf_msix_tbl *msix_tbl;
+ struct cdns_pcie_epf *epf;
+ u64 pci_addr_mask = 0xff;
+ u64 msg_addr;
+ u16 flags;
+ u8 bir;
+
+ epf = &ep->epf[fn];
+ if (vfn > 0)
+ epf = &epf->epf[vfn - 1];
+
+ fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn);
+
+ /* 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 = FIELD_GET(PCI_MSIX_TABLE_BIR, tbl_offset);
+ tbl_offset &= PCI_MSIX_TABLE_OFFSET;
+
+ msix_tbl = epf->epf_bar[bir]->addr + tbl_offset;
+ msg_addr = msix_tbl[(interrupt_num - 1)].msg_addr;
+ msg_data = msix_tbl[(interrupt_num - 1)].msg_data;
+
+ /* 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_hpa_set_outbound_region(pcie, 0, 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_hpa_ep_raise_irq(struct pci_epc *epc, u8 fn, u8 vfn,
+ unsigned int type, u16 interrupt_num)
+{
+ struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+ struct cdns_pcie *pcie = &ep->pcie;
+ struct device *dev = pcie->dev;
+
+ switch (type) {
+ case PCI_IRQ_INTX:
+ if (vfn > 0) {
+ dev_err(dev, "Cannot raise INTX interrupts for VF\n");
+ return -EINVAL;
+ }
+ return cdns_pcie_hpa_ep_send_intx_irq(ep, fn, vfn, 0);
+
+ case PCI_IRQ_MSI:
+ return cdns_pcie_hpa_ep_send_msi_irq(ep, fn, vfn, interrupt_num);
+
+ case PCI_IRQ_MSIX:
+ return cdns_pcie_hpa_ep_send_msix_irq(ep, fn, vfn, interrupt_num);
+
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int cdns_pcie_hpa_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;
+ int max_epfs = sizeof(epc->function_num_map) * 8;
+ int ret, epf, last_fn;
+ u32 reg, value;
+
+ /*
+ * BIT(0) is hardwired to 1, hence function 0 is always enabled
+ * and can't be disabled anyway.
+ */
+ cdns_pcie_hpa_writel(pcie, REG_BANK_IP_REG,
+ CDNS_PCIE_HPA_LM_EP_FUNC_CFG, epc->function_num_map);
+
+ /*
+ * Next function field in ARI_CAP_AND_CTR register for last function
+ * should be 0. Clear Next Function Number field for the last
+ * function used.
+ */
+ last_fn = find_last_bit(&epc->function_num_map, BITS_PER_LONG);
+ reg = CDNS_PCIE_CORE_PF_I_ARI_CAP_AND_CTRL(last_fn);
+ value = cdns_pcie_readl(pcie, reg);
+ value &= ~CDNS_PCIE_ARI_CAP_NFN_MASK;
+ cdns_pcie_writel(pcie, reg, value);
+
+ if (ep->quirk_disable_flr) {
+ for (epf = 0; epf < max_epfs; epf++) {
+ if (!(epc->function_num_map & BIT(epf)))
+ continue;
+
+ value = cdns_pcie_ep_fn_readl(pcie, epf,
+ CDNS_PCIE_EP_FUNC_DEV_CAP_OFFSET +
+ PCI_EXP_DEVCAP);
+ value &= ~PCI_EXP_DEVCAP_FLR;
+ cdns_pcie_ep_fn_writel(pcie, epf,
+ CDNS_PCIE_EP_FUNC_DEV_CAP_OFFSET +
+ PCI_EXP_DEVCAP, value);
+ }
+ }
+
+ ret = cdns_pcie_start_link(pcie);
+ if (ret) {
+ dev_err(dev, "Failed to start link\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int cdns_pcie_hpa_ep_set_bar(struct pci_epc *epc, u8 fn, u8 vfn,
+ 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;
+ int flags = epf_bar->flags;
+ u32 addr0, addr1, reg, cfg, b, aperture, ctrl;
+ u64 sz;
+
+ /* BAR size is 2^(aperture + 7) */
+ sz = max_t(size_t, epf_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);
+
+ /* 128B -> 0, 256B -> 1, 512B -> 2, ... */
+ aperture = ilog2(sz) - 7;
+
+ if ((flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
+ ctrl = CDNS_PCIE_HPA_LM_BAR_CFG_CTRL_IO_32BITS;
+ } else {
+ bool is_prefetch = !!(flags & PCI_BASE_ADDRESS_MEM_PREFETCH);
+ bool is_64bits = !!(flags & PCI_BASE_ADDRESS_MEM_TYPE_64);
+
+ if (is_64bits && (bar & 1))
+ return -EINVAL;
+
+ if (is_64bits && is_prefetch)
+ ctrl = CDNS_PCIE_HPA_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS;
+ else if (is_prefetch)
+ ctrl = CDNS_PCIE_HPA_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS;
+ else if (is_64bits)
+ ctrl = CDNS_PCIE_HPA_LM_BAR_CFG_CTRL_MEM_64BITS;
+ else
+ ctrl = CDNS_PCIE_HPA_LM_BAR_CFG_CTRL_MEM_32BITS;
+ }
+
+ addr0 = lower_32_bits(bar_phys);
+ addr1 = upper_32_bits(bar_phys);
+
+ if (vfn == 1)
+ reg = CDNS_PCIE_HPA_LM_EP_VFUNC_BAR_CFG(bar, fn);
+ else
+ reg = CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG(bar, fn);
+ b = (bar < BAR_4) ? bar : bar - BAR_4;
+
+ if (vfn == 0 || vfn == 1) {
+ cfg = cdns_pcie_hpa_readl(pcie, REG_BANK_IP_CFG_CTRL_REG, reg);
+ cfg &= ~(CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) |
+ CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b));
+ cfg |= (CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG_BAR_APERTURE(b, aperture) |
+ CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl));
+ cdns_pcie_hpa_writel(pcie, REG_BANK_IP_CFG_CTRL_REG, reg, cfg);
+ }
+
+ fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_MASTER_COMMON,
+ CDNS_PCIE_HPA_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar), addr0);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_MASTER_COMMON,
+ CDNS_PCIE_HPA_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar), addr1);
+
+ if (vfn > 0)
+ epf = &epf->epf[vfn - 1];
+ epf->epf_bar[bar] = epf_bar;
+
+ return 0;
+}
+
+static void cdns_pcie_hpa_ep_clear_bar(struct pci_epc *epc, u8 fn, u8 vfn,
+ 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;
+
+ if (vfn == 1)
+ reg = CDNS_PCIE_HPA_LM_EP_VFUNC_BAR_CFG(bar, fn);
+ else
+ reg = CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG(bar, fn);
+ b = (bar < BAR_4) ? bar : bar - BAR_4;
+
+ if (vfn == 0 || vfn == 1) {
+ ctrl = CDNS_PCIE_HPA_LM_BAR_CFG_CTRL_DISABLED;
+ cfg = cdns_pcie_hpa_readl(pcie, REG_BANK_IP_CFG_CTRL_REG, reg);
+ cfg &= ~(CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) |
+ CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b));
+ cfg |= CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_IP_CFG_CTRL_REG, reg, cfg);
+ }
+
+ fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_MASTER_COMMON,
+ CDNS_PCIE_HPA_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar), 0);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_MASTER_COMMON,
+ CDNS_PCIE_HPA_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar), 0);
+
+ if (vfn > 0)
+ epf = &epf->epf[vfn - 1];
+ epf->epf_bar[bar] = NULL;
+}
+
+static const struct pci_epc_ops cdns_pcie_hpa_epc_ops = {
+ .write_header = cdns_pcie_ep_write_header,
+ .set_bar = cdns_pcie_hpa_ep_set_bar,
+ .clear_bar = cdns_pcie_hpa_ep_clear_bar,
+ .map_addr = cdns_pcie_hpa_ep_map_addr,
+ .unmap_addr = cdns_pcie_hpa_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_hpa_ep_raise_irq,
+ .map_msi_irq = cdns_pcie_ep_map_msi_irq,
+ .start = cdns_pcie_hpa_ep_start,
+ .get_features = cdns_pcie_ep_get_features,
+};
+
+int cdns_pcie_hpa_ep_setup(struct cdns_pcie_ep *ep)
+{
+ struct device *dev = ep->pcie.dev;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct device_node *np = dev->of_node;
+ struct cdns_pcie *pcie = &ep->pcie;
+ struct cdns_pcie_epf *epf;
+ struct resource *res;
+ struct pci_epc *epc;
+ int ret;
+ int i;
+
+ pcie->is_rc = false;
+
+ pcie->reg_base = devm_platform_ioremap_resource_byname(pdev, "reg");
+ if (IS_ERR(pcie->reg_base)) {
+ dev_err(dev, "missing \"reg\"\n");
+ return PTR_ERR(pcie->reg_base);
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem");
+ if (!res) {
+ dev_err(dev, "missing \"mem\"\n");
+ return -EINVAL;
+ }
+ pcie->mem_res = res;
+
+ ep->max_regions = CDNS_PCIE_MAX_OB;
+ of_property_read_u32(np, "cdns,max-outbound-regions", &ep->max_regions);
+
+ ep->ob_addr = devm_kcalloc(dev,
+ ep->max_regions, sizeof(*ep->ob_addr),
+ GFP_KERNEL);
+ if (!ep->ob_addr)
+ return -ENOMEM;
+
+ epc = devm_pci_epc_create(dev, &cdns_pcie_hpa_epc_ops);
+ if (IS_ERR(epc)) {
+ dev_err(dev, "failed to create epc device\n");
+ return PTR_ERR(epc);
+ }
+
+ epc_set_drvdata(epc, 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;
+
+ epc->max_vfs = devm_kcalloc(dev, epc->max_functions,
+ sizeof(*epc->max_vfs), GFP_KERNEL);
+ if (!epc->max_vfs)
+ return -ENOMEM;
+
+ ret = of_property_read_u8_array(np, "max-virtual-functions",
+ epc->max_vfs, epc->max_functions);
+ if (ret == 0) {
+ for (i = 0; i < epc->max_functions; i++) {
+ epf = &ep->epf[i];
+ if (epc->max_vfs[i] == 0)
+ continue;
+ epf->epf = devm_kcalloc(dev, epc->max_vfs[i],
+ sizeof(*ep->epf), GFP_KERNEL);
+ if (!epf->epf)
+ return -ENOMEM;
+ }
+ }
+
+ ret = pci_epc_mem_init(epc, pcie->mem_res->start,
+ resource_size(pcie->mem_res), PAGE_SIZE);
+ if (ret < 0) {
+ dev_err(dev, "failed to initialize the memory space\n");
+ return ret;
+ }
+
+ ep->irq_cpu_addr = pci_epc_mem_alloc_addr(epc, &ep->irq_phys_addr,
+ SZ_128K);
+ if (!ep->irq_cpu_addr) {
+ dev_err(dev, "failed to reserve memory space for MSI\n");
+ ret = -ENOMEM;
+ goto free_epc_mem;
+ }
+ ep->irq_pci_addr = CDNS_PCIE_EP_IRQ_PCI_ADDR_NONE;
+ /* Reserve region 0 for IRQs */
+ set_bit(0, &ep->ob_region_map);
+
+ if (ep->quirk_detect_quiet_flag)
+ cdns_pcie_hpa_detect_quiet_min_delay_set(&ep->pcie);
+
+ spin_lock_init(&ep->lock);
+
+ pci_epc_init_notify(epc);
+
+ return 0;
+
+ free_epc_mem:
+ pci_epc_mem_exit(epc);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_hpa_ep_setup);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cadence PCIe controller driver");
+MODULE_AUTHOR("Manikandan K Pillai <mpillai@cadence.com>");
diff --git a/drivers/pci/controller/cadence/pcie-cadence-host-hpa.c b/drivers/pci/controller/cadence/pcie-cadence-host-hpa.c
new file mode 100644
index 000000000000..f930b745bc33
--- /dev/null
+++ b/drivers/pci/controller/cadence/pcie-cadence-host-hpa.c
@@ -0,0 +1,586 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2017 Cadence
+// Cadence PCIe host controller driver.
+// Author: Manikandan K Pillai <mpillai@cadence.com>
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/list_sort.h>
+#include <linux/of_address.h>
+#include <linux/of_pci.h>
+#include <linux/platform_device.h>
+
+#include "pcie-cadence.h"
+#include "pcie-cadence-host-common.h"
+
+static u8 bar_aperture_mask[] = {
+ [RP_BAR0] = 0x1F,
+ [RP_BAR1] = 0xF,
+};
+
+void __iomem *cdns_pci_hpa_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);
+ struct cdns_pcie *pcie = &rc->pcie;
+ unsigned int busn = bus->number;
+ u32 addr0, desc0, desc1, ctrl0;
+ u32 regval;
+
+ if (pci_is_root_bus(bus)) {
+ /*
+ * Only the root port (devfn == 0) is connected to this bus.
+ * All other PCI devices are behind some bridge hence on another
+ * bus.
+ */
+ if (devfn)
+ return NULL;
+
+ return pcie->reg_base + (where & 0xfff);
+ }
+
+ /* Clear AXI link-down status */
+ regval = cdns_pcie_hpa_readl(pcie, REG_BANK_AXI_SLAVE, CDNS_PCIE_HPA_AT_LINKDOWN);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE, CDNS_PCIE_HPA_AT_LINKDOWN,
+ (regval & ~GENMASK(0, 0)));
+
+ desc0 = 0;
+ desc1 = 0;
+ ctrl0 = 0;
+
+ /* Update Output registers for AXI region 0. */
+ addr0 = CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR0_NBITS(12) |
+ CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) |
+ CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR0_BUS(busn);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR0(0), addr0);
+
+ desc1 = cdns_pcie_hpa_readl(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_DESC1(0));
+ desc1 &= ~CDNS_PCIE_HPA_AT_OB_REGION_DESC1_DEVFN_MASK;
+ desc1 |= CDNS_PCIE_HPA_AT_OB_REGION_DESC1_DEVFN(0);
+ ctrl0 = CDNS_PCIE_HPA_AT_OB_REGION_CTRL0_SUPPLY_BUS |
+ CDNS_PCIE_HPA_AT_OB_REGION_CTRL0_SUPPLY_DEV_FN;
+
+ if (busn == bridge->busnr + 1)
+ desc0 |= CDNS_PCIE_HPA_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0;
+ else
+ desc0 |= CDNS_PCIE_HPA_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1;
+
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_DESC0(0), desc0);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_DESC1(0), desc1);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_CTRL0(0), ctrl0);
+
+ return rc->cfg_base + (where & 0xfff);
+}
+
+int cdns_pcie_hpa_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;
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_hpa_host_wait_for_link);
+
+int cdns_pcie_hpa_host_start_link(struct cdns_pcie_rc *rc)
+{
+ struct cdns_pcie *pcie = &rc->pcie;
+ int ret;
+
+ ret = cdns_pcie_host_wait_for_link(pcie);
+
+ /*
+ * Retrain link for Gen2 training defect
+ * if quirk flag is set.
+ */
+ if (!ret && rc->quirk_retrain_flag)
+ ret = cdns_pcie_retrain(pcie);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_hpa_host_start_link);
+
+static struct pci_ops cdns_pcie_hpa_host_ops = {
+ .map_bus = cdns_pci_hpa_map_bus,
+ .read = pci_generic_config_read,
+ .write = pci_generic_config_write,
+};
+
+static void cdns_pcie_hpa_host_enable_ptm_response(struct cdns_pcie *pcie)
+{
+ u32 val;
+
+ val = cdns_pcie_hpa_readl(pcie, REG_BANK_IP_REG, CDNS_PCIE_HPA_LM_PTM_CTRL);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_IP_REG, CDNS_PCIE_HPA_LM_PTM_CTRL,
+ val | CDNS_PCIE_HPA_LM_TPM_CTRL_PTMRSEN);
+}
+
+static int cdns_pcie_hpa_host_bar_ib_config(struct cdns_pcie_rc *rc,
+ enum cdns_pcie_rp_bar bar,
+ u64 cpu_addr, u64 size,
+ unsigned long flags)
+{
+ struct cdns_pcie *pcie = &rc->pcie;
+ u32 addr0, addr1, aperture, value;
+
+ if (!rc->avail_ib_bar[bar])
+ return -EBUSY;
+
+ rc->avail_ib_bar[bar] = false;
+
+ aperture = ilog2(size);
+ addr0 = CDNS_PCIE_HPA_AT_IB_RP_BAR_ADDR0_NBITS(aperture) |
+ (lower_32_bits(cpu_addr) & GENMASK(31, 8));
+ addr1 = upper_32_bits(cpu_addr);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_MASTER,
+ CDNS_PCIE_HPA_AT_IB_RP_BAR_ADDR0(bar), addr0);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_MASTER,
+ CDNS_PCIE_HPA_AT_IB_RP_BAR_ADDR1(bar), addr1);
+
+ if (bar == RP_NO_BAR)
+ return 0;
+
+ value = cdns_pcie_hpa_readl(pcie, REG_BANK_IP_CFG_CTRL_REG, CDNS_PCIE_HPA_LM_RC_BAR_CFG);
+ value &= ~(HPA_LM_RC_BAR_CFG_CTRL_MEM_64BITS(bar) |
+ HPA_LM_RC_BAR_CFG_CTRL_PREF_MEM_64BITS(bar) |
+ HPA_LM_RC_BAR_CFG_CTRL_MEM_32BITS(bar) |
+ HPA_LM_RC_BAR_CFG_CTRL_PREF_MEM_32BITS(bar) |
+ HPA_LM_RC_BAR_CFG_APERTURE(bar, bar_aperture_mask[bar] + 2));
+ if (size + cpu_addr >= SZ_4G) {
+ if (!(flags & IORESOURCE_PREFETCH))
+ value |= HPA_LM_RC_BAR_CFG_CTRL_MEM_64BITS(bar);
+ value |= HPA_LM_RC_BAR_CFG_CTRL_PREF_MEM_64BITS(bar);
+ } else {
+ if (!(flags & IORESOURCE_PREFETCH))
+ value |= HPA_LM_RC_BAR_CFG_CTRL_MEM_32BITS(bar);
+ value |= HPA_LM_RC_BAR_CFG_CTRL_PREF_MEM_32BITS(bar);
+ }
+
+ value |= HPA_LM_RC_BAR_CFG_APERTURE(bar, aperture);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_IP_CFG_CTRL_REG, CDNS_PCIE_HPA_LM_RC_BAR_CFG, value);
+
+ return 0;
+}
+
+static int cdns_pcie_hpa_host_bar_config(struct cdns_pcie_rc *rc,
+ struct resource_entry *entry)
+{
+ u64 cpu_addr, pci_addr, size, winsize;
+ struct cdns_pcie *pcie = &rc->pcie;
+ struct device *dev = pcie->dev;
+ enum cdns_pcie_rp_bar bar;
+ unsigned long flags;
+ int ret;
+
+ cpu_addr = entry->res->start;
+ pci_addr = entry->res->start - entry->offset;
+ flags = entry->res->flags;
+ size = resource_size(entry->res);
+
+ if (entry->offset) {
+ dev_err(dev, "PCI addr: %llx must be equal to CPU addr: %llx\n",
+ pci_addr, cpu_addr);
+ return -EINVAL;
+ }
+
+ while (size > 0) {
+ /*
+ * Try to find a minimum BAR whose size is greater than
+ * or equal to the remaining resource_entry size. This will
+ * fail if the size of each of the available BARs is less than
+ * the remaining resource_entry size.
+ * If a minimum BAR is found, IB ATU will be configured and
+ * exited.
+ */
+ bar = cdns_pcie_host_find_min_bar(rc, size);
+ if (bar != RP_BAR_UNDEFINED) {
+ ret = cdns_pcie_hpa_host_bar_ib_config(rc, bar, cpu_addr,
+ size, flags);
+ if (ret)
+ dev_err(dev, "IB BAR: %d config failed\n", bar);
+ return ret;
+ }
+
+ /*
+ * If the control reaches here, it would mean the remaining
+ * resource_entry size cannot be fitted in a single BAR. So we
+ * find a maximum BAR whose size is less than or equal to the
+ * remaining resource_entry size and split the resource entry
+ * so that part of resource entry is fitted inside the maximum
+ * BAR. The remaining size would be fitted during the next
+ * iteration of the loop.
+ * If a maximum BAR is not found, there is no way we can fit
+ * this resource_entry, so we error out.
+ */
+ bar = cdns_pcie_host_find_max_bar(rc, size);
+ if (bar == RP_BAR_UNDEFINED) {
+ dev_err(dev, "No free BAR to map cpu_addr %llx\n",
+ cpu_addr);
+ return -EINVAL;
+ }
+
+ winsize = bar_max_size[bar];
+ ret = cdns_pcie_hpa_host_bar_ib_config(rc, bar, cpu_addr, winsize, flags);
+ if (ret) {
+ dev_err(dev, "IB BAR: %d config failed\n", bar);
+ return ret;
+ }
+
+ size -= winsize;
+ cpu_addr += winsize;
+ }
+
+ return 0;
+}
+
+static int cdns_pcie_hpa_host_map_dma_ranges(struct cdns_pcie_rc *rc)
+{
+ struct cdns_pcie *pcie = &rc->pcie;
+ struct device *dev = pcie->dev;
+ struct device_node *np = dev->of_node;
+ struct pci_host_bridge *bridge;
+ struct resource_entry *entry;
+ u32 no_bar_nbits = 32;
+ int err;
+
+ bridge = pci_host_bridge_from_priv(rc);
+ if (!bridge)
+ return -ENOMEM;
+
+ if (list_empty(&bridge->dma_ranges)) {
+ of_property_read_u32(np, "cdns,no-bar-match-nbits",
+ &no_bar_nbits);
+ err = cdns_pcie_hpa_host_bar_ib_config(rc, RP_NO_BAR, 0x0,
+ (u64)1 << no_bar_nbits, 0);
+ if (err)
+ dev_err(dev, "IB BAR: %d config failed\n", RP_NO_BAR);
+ return err;
+ }
+
+ list_sort(NULL, &bridge->dma_ranges, cdns_pcie_host_dma_ranges_cmp);
+
+ resource_list_for_each_entry(entry, &bridge->dma_ranges) {
+ err = cdns_pcie_hpa_host_bar_config(rc, entry);
+ if (err) {
+ dev_err(dev, "Fail to configure IB using dma-ranges\n");
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int cdns_pcie_hpa_host_init_root_port(struct cdns_pcie_rc *rc)
+{
+ struct cdns_pcie *pcie = &rc->pcie;
+ u32 value, ctrl;
+
+ /*
+ * Set the root complex BAR configuration register:
+ * - disable both BAR0 and BAR1.
+ * - enable Prefetchable Memory Base and Limit registers in type 1
+ * config space (64 bits).
+ * - enable IO Base and Limit registers in type 1 config
+ * space (32 bits).
+ */
+
+ ctrl = CDNS_PCIE_HPA_LM_BAR_CFG_CTRL_DISABLED;
+ value = CDNS_PCIE_HPA_LM_RC_BAR_CFG_BAR0_CTRL(ctrl) |
+ CDNS_PCIE_HPA_LM_RC_BAR_CFG_BAR1_CTRL(ctrl) |
+ CDNS_PCIE_HPA_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE |
+ CDNS_PCIE_HPA_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS |
+ CDNS_PCIE_HPA_LM_RC_BAR_CFG_IO_ENABLE |
+ CDNS_PCIE_HPA_LM_RC_BAR_CFG_IO_32BITS;
+ cdns_pcie_hpa_writel(pcie, REG_BANK_IP_CFG_CTRL_REG,
+ CDNS_PCIE_HPA_LM_RC_BAR_CFG, value);
+
+ if (rc->vendor_id != 0xffff)
+ cdns_pcie_hpa_rp_writew(pcie, PCI_VENDOR_ID, rc->vendor_id);
+
+ if (rc->device_id != 0xffff)
+ cdns_pcie_hpa_rp_writew(pcie, PCI_DEVICE_ID, rc->device_id);
+
+ cdns_pcie_hpa_rp_writeb(pcie, PCI_CLASS_REVISION, 0);
+ cdns_pcie_hpa_rp_writeb(pcie, PCI_CLASS_PROG, 0);
+ cdns_pcie_hpa_rp_writew(pcie, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI);
+
+ return 0;
+}
+
+static void cdns_pcie_hpa_create_region_for_ecam(struct cdns_pcie_rc *rc)
+{
+ struct pci_host_bridge *bridge = pci_host_bridge_from_priv(rc);
+ struct resource *cfg_res = rc->cfg_res;
+ struct cdns_pcie *pcie = &rc->pcie;
+ u32 value, root_port_req_id_reg, pcie_bus_number_reg;
+ u32 ecam_addr_0, region_size_0, request_id_0;
+ int busnr = 0, secbus = 0, subbus = 0;
+ struct resource_entry *entry;
+ resource_size_t size;
+ u32 axi_address_low;
+ int nbits;
+ u64 sz;
+
+ entry = resource_list_first_type(&bridge->windows, IORESOURCE_BUS);
+ if (entry) {
+ busnr = entry->res->start;
+ secbus = (busnr < 0xff) ? (busnr + 1) : 0xff;
+ subbus = entry->res->end;
+ }
+ size = resource_size(cfg_res);
+ sz = 1ULL << fls64(size - 1);
+ nbits = ilog2(sz);
+ if (nbits < 8)
+ nbits = 8;
+
+ root_port_req_id_reg = ((busnr & 0xff) << 8);
+ pcie_bus_number_reg = ((subbus & 0xff) << 16) | ((secbus & 0xff) << 8) |
+ (busnr & 0xff);
+ ecam_addr_0 = cfg_res->start;
+ region_size_0 = nbits - 1;
+ request_id_0 = ((busnr & 0xff) << 8);
+
+#define CDNS_PCIE_HPA_TAG_MANAGEMENT (0x0)
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_TAG_MANAGEMENT, 0x200000);
+
+ /* Taking slave err as OKAY */
+#define CDNS_PCIE_HPA_SLAVE_RESP (0x100)
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE, CDNS_PCIE_HPA_SLAVE_RESP,
+ 0x0);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_SLAVE_RESP + 0x4, 0x0);
+
+ /* Program the register "i_root_port_req_id_reg" with RP's BDF */
+#define I_ROOT_PORT_REQ_ID_REG (0x141c)
+ cdns_pcie_hpa_writel(pcie, REG_BANK_IP_REG, I_ROOT_PORT_REQ_ID_REG,
+ root_port_req_id_reg);
+
+ /**
+ * Program the register "i_pcie_bus_numbers" with Primary(RP's bus number),
+ * secondary and subordinate bus numbers
+ */
+#define I_PCIE_BUS_NUMBERS (CDNS_PCIE_HPA_RP_BASE + 0x18)
+ cdns_pcie_hpa_writel(pcie, REG_BANK_RP, I_PCIE_BUS_NUMBERS,
+ pcie_bus_number_reg);
+
+ /* Program the register "lm_hal_sbsa_ctrl[0]" to enable the sbsa */
+#define LM_HAL_SBSA_CTRL (0x1170)
+ value = cdns_pcie_hpa_readl(pcie, REG_BANK_IP_REG, LM_HAL_SBSA_CTRL);
+ value |= BIT(0);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_IP_REG, LM_HAL_SBSA_CTRL, value);
+
+ /* Program region[0] for ECAM */
+ axi_address_low = (ecam_addr_0 & 0xfff00000) | region_size_0;
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR0(0),
+ axi_address_low);
+
+ /* rc0-high-axi-address */
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR1(0), 0x0);
+ /* Type-1 CFG */
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_DESC0(0), 0x05000000);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_DESC1(0),
+ (request_id_0 << 16));
+
+ /* All AXI bits pass through PCIe */
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR0(0), 0x1b);
+ /* PCIe address-high */
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR1(0), 0);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_CTRL0(0), 0x06000000);
+}
+
+static void cdns_pcie_hpa_create_region_for_cfg(struct cdns_pcie_rc *rc)
+{
+ struct cdns_pcie *pcie = &rc->pcie;
+ struct pci_host_bridge *bridge = pci_host_bridge_from_priv(rc);
+ struct resource *cfg_res = rc->cfg_res;
+ struct resource_entry *entry;
+ u64 cpu_addr = cfg_res->start;
+ u32 addr0, addr1, desc1;
+ int busnr = 0;
+
+ entry = resource_list_first_type(&bridge->windows, IORESOURCE_BUS);
+ if (entry)
+ busnr = entry->res->start;
+
+ /*
+ * Reserve region 0 for PCI configure space accesses:
+ * OB_REGION_PCI_ADDR0 and OB_REGION_DESC0 are updated dynamically by
+ * cdns_pci_map_bus(), other region registers are set here once for all.
+ */
+ addr1 = 0;
+ desc1 = CDNS_PCIE_HPA_AT_OB_REGION_DESC1_BUS(busnr);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR1(0), addr1);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_DESC1(0), desc1);
+
+ addr0 = CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR0_NBITS(12) |
+ (lower_32_bits(cpu_addr) & GENMASK(31, 8));
+ addr1 = upper_32_bits(cpu_addr);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR0(0), addr0);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR1(0), addr1);
+}
+
+static int cdns_pcie_hpa_host_init_address_translation(struct cdns_pcie_rc *rc)
+{
+ struct cdns_pcie *pcie = &rc->pcie;
+ struct pci_host_bridge *bridge = pci_host_bridge_from_priv(rc);
+ struct resource_entry *entry;
+ int r = 0, busnr = 0;
+
+ if (rc->ecam_support_flag)
+ cdns_pcie_hpa_create_region_for_ecam(rc);
+ else
+ cdns_pcie_hpa_create_region_for_cfg(rc);
+
+ entry = resource_list_first_type(&bridge->windows, IORESOURCE_BUS);
+ if (entry)
+ busnr = entry->res->start;
+
+ r++;
+ if (pcie->msg_res)
+ cdns_pcie_hpa_set_outbound_region_for_normal_msg(pcie, busnr, 0, r,
+ pcie->msg_res->start);
+
+ r++;
+ resource_list_for_each_entry(entry, &bridge->windows) {
+ struct resource *res = entry->res;
+ u64 pci_addr = res->start - entry->offset;
+
+ if (resource_type(res) == IORESOURCE_IO)
+ cdns_pcie_hpa_set_outbound_region(pcie, busnr, 0, r,
+ true,
+ pci_pio_to_address(res->start),
+ pci_addr,
+ resource_size(res));
+ else
+ cdns_pcie_hpa_set_outbound_region(pcie, busnr, 0, r,
+ false,
+ res->start,
+ pci_addr,
+ resource_size(res));
+
+ r++;
+ }
+
+ if (rc->no_inbound_flag)
+ return 0;
+ else
+ return cdns_pcie_hpa_host_map_dma_ranges(rc);
+}
+
+int cdns_pcie_hpa_host_init(struct cdns_pcie_rc *rc)
+{
+ int err;
+
+ err = cdns_pcie_hpa_host_init_root_port(rc);
+ if (err)
+ return err;
+
+ return cdns_pcie_hpa_host_init_address_translation(rc);
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_hpa_host_init);
+
+int cdns_pcie_hpa_host_link_setup(struct cdns_pcie_rc *rc)
+{
+ struct cdns_pcie *pcie = &rc->pcie;
+ struct device *dev = rc->pcie.dev;
+ int ret;
+
+ if (rc->quirk_detect_quiet_flag)
+ cdns_pcie_hpa_detect_quiet_min_delay_set(&rc->pcie);
+
+ cdns_pcie_hpa_host_enable_ptm_response(pcie);
+
+ ret = cdns_pcie_start_link(pcie);
+ if (ret) {
+ dev_err(dev, "Failed to start link\n");
+ return ret;
+ }
+
+ ret = cdns_pcie_hpa_host_start_link(rc);
+ if (ret)
+ dev_dbg(dev, "PCIe link never came up\n");
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_hpa_host_link_setup);
+
+int cdns_pcie_hpa_host_setup(struct cdns_pcie_rc *rc)
+{
+ struct device *dev = rc->pcie.dev;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct pci_host_bridge *bridge;
+ enum cdns_pcie_rp_bar bar;
+ struct cdns_pcie *pcie;
+ struct resource *res;
+ int ret;
+
+ bridge = pci_host_bridge_from_priv(rc);
+ if (!bridge)
+ return -ENOMEM;
+
+ pcie = &rc->pcie;
+ pcie->is_rc = true;
+
+ if (!pcie->reg_base) {
+ pcie->reg_base = devm_platform_ioremap_resource_byname(pdev, "reg");
+ if (IS_ERR(pcie->reg_base)) {
+ dev_err(dev, "missing \"reg\"\n");
+ return PTR_ERR(pcie->reg_base);
+ }
+ }
+
+ /* ECAM config space is remapped at glue layer */
+ if (!rc->cfg_base) {
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
+ rc->cfg_base = devm_pci_remap_cfg_resource(dev, res);
+ if (IS_ERR(rc->cfg_base))
+ return PTR_ERR(rc->cfg_base);
+ rc->cfg_res = res;
+ }
+
+ ret = cdns_pcie_hpa_host_link_setup(rc);
+ if (ret)
+ return ret;
+
+ for (bar = RP_BAR0; bar <= RP_NO_BAR; bar++)
+ rc->avail_ib_bar[bar] = true;
+
+ ret = cdns_pcie_hpa_host_init(rc);
+ if (ret)
+ return ret;
+
+ if (!bridge->ops)
+ bridge->ops = &cdns_pcie_hpa_host_ops;
+
+ return pci_host_probe(bridge);
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_hpa_host_setup);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cadence PCIe controller driver");
+MODULE_AUTHOR("Manikandan K Pillai <mpillai@cadence.com>");
diff --git a/drivers/pci/controller/cadence/pcie-cadence-hpa.c b/drivers/pci/controller/cadence/pcie-cadence-hpa.c
new file mode 100644
index 000000000000..1152d2dcae77
--- /dev/null
+++ b/drivers/pci/controller/cadence/pcie-cadence-hpa.c
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2017 Cadence
+// Cadence PCIe controller driver
+// Author: Manikandan K Pillai <mpillai@cadence.com>
+
+#include <linux/kernel.h>
+#include <linux/of.h>
+
+#include "pcie-cadence.h"
+
+bool cdns_pcie_hpa_link_up(struct cdns_pcie *pcie)
+{
+ u32 pl_reg_val;
+
+ pl_reg_val = cdns_pcie_hpa_readl(pcie, REG_BANK_IP_REG, CDNS_PCIE_HPA_PHY_DBG_STS_REG0);
+ if (pl_reg_val & GENMASK(0, 0))
+ return true;
+ return false;
+}
+
+int cdns_pcie_hpa_start_link(struct cdns_pcie *pcie)
+{
+ u32 pl_reg_val;
+
+ pl_reg_val = cdns_pcie_hpa_readl(pcie, REG_BANK_IP_REG, CDNS_PCIE_HPA_PHY_LAYER_CFG0);
+ pl_reg_val |= CDNS_PCIE_HPA_LINK_TRNG_EN_MASK;
+ cdns_pcie_hpa_writel(pcie, REG_BANK_IP_REG, CDNS_PCIE_HPA_PHY_LAYER_CFG0, pl_reg_val);
+ return 0;
+}
+
+void cdns_pcie_hpa_stop_link(struct cdns_pcie *pcie)
+{
+ u32 pl_reg_val;
+
+ pl_reg_val = cdns_pcie_hpa_readl(pcie, REG_BANK_IP_REG, CDNS_PCIE_HPA_PHY_LAYER_CFG0);
+ pl_reg_val &= ~CDNS_PCIE_HPA_LINK_TRNG_EN_MASK;
+ cdns_pcie_hpa_writel(pcie, REG_BANK_IP_REG, CDNS_PCIE_HPA_PHY_LAYER_CFG0, pl_reg_val);
+}
+
+void cdns_pcie_hpa_detect_quiet_min_delay_set(struct cdns_pcie *pcie)
+{
+ u32 delay = 0x3;
+ u32 ltssm_control_cap;
+
+ /*
+ * Set the LTSSM Detect Quiet state min. delay to 2ms.
+ */
+ ltssm_control_cap = cdns_pcie_hpa_readl(pcie, REG_BANK_IP_REG,
+ CDNS_PCIE_HPA_PHY_LAYER_CFG0);
+ ltssm_control_cap = ((ltssm_control_cap &
+ ~CDNS_PCIE_HPA_DETECT_QUIET_MIN_DELAY_MASK) |
+ CDNS_PCIE_HPA_DETECT_QUIET_MIN_DELAY(delay));
+
+ cdns_pcie_hpa_writel(pcie, REG_BANK_IP_REG,
+ CDNS_PCIE_HPA_PHY_LAYER_CFG0, ltssm_control_cap);
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_hpa_detect_quiet_min_delay_set);
+
+void cdns_pcie_hpa_set_outbound_region(struct cdns_pcie *pcie, u8 busnr, u8 fn,
+ u32 r, bool is_io,
+ u64 cpu_addr, u64 pci_addr, size_t size)
+{
+ /*
+ * roundup_pow_of_two() returns an unsigned long, which is not suited
+ * for 64bit values.
+ */
+ u64 sz = 1ULL << fls64(size - 1);
+ int nbits = ilog2(sz);
+ u32 addr0, addr1, desc0, desc1, ctrl0;
+
+ if (nbits < 8)
+ nbits = 8;
+
+ /* Set the PCI address */
+ addr0 = CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR0_NBITS(nbits) |
+ (lower_32_bits(pci_addr) & GENMASK(31, 8));
+ addr1 = upper_32_bits(pci_addr);
+
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR0(r), addr0);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR1(r), addr1);
+
+ /* Set the PCIe header descriptor */
+ if (is_io)
+ desc0 = CDNS_PCIE_HPA_AT_OB_REGION_DESC0_TYPE_IO;
+ else
+ desc0 = CDNS_PCIE_HPA_AT_OB_REGION_DESC0_TYPE_MEM;
+ desc1 = 0;
+ ctrl0 = 0;
+
+ /*
+ * Whether Bit [26] is set or not inside DESC0 register of the outbound
+ * PCIe descriptor, the PCI function number must be set into
+ * Bits [31:24] of DESC1 anyway.
+ *
+ * In Root Complex mode, the function number is always 0 but in Endpoint
+ * mode, the PCIe controller may support more than one function. This
+ * function number needs to be set properly into the outbound PCIe
+ * descriptor.
+ *
+ * Besides, setting Bit [26] is mandatory when in Root Complex mode:
+ * then the driver must provide the bus, resp. device, number in
+ * Bits [31:24] of DESC1, resp. Bits[23:16] of DESC0. Like the function
+ * number, the device number is always 0 in Root Complex mode.
+ *
+ * However when in Endpoint mode, we can clear Bit [26] of DESC0, hence
+ * the PCIe controller will use the captured values for the bus and
+ * device numbers.
+ */
+ if (pcie->is_rc) {
+ /* The device and function numbers are always 0. */
+ desc1 = CDNS_PCIE_HPA_AT_OB_REGION_DESC1_BUS(busnr) |
+ CDNS_PCIE_HPA_AT_OB_REGION_DESC1_DEVFN(0);
+ ctrl0 = CDNS_PCIE_HPA_AT_OB_REGION_CTRL0_SUPPLY_BUS |
+ CDNS_PCIE_HPA_AT_OB_REGION_CTRL0_SUPPLY_DEV_FN;
+ } else {
+ /*
+ * Use captured values for bus and device numbers but still
+ * need to set the function number.
+ */
+ desc1 |= CDNS_PCIE_HPA_AT_OB_REGION_DESC1_DEVFN(fn);
+ }
+
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_DESC0(r), desc0);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_DESC1(r), desc1);
+
+ addr0 = CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) |
+ (lower_32_bits(cpu_addr) & GENMASK(31, 8));
+ addr1 = upper_32_bits(cpu_addr);
+
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR0(r), addr0);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR1(r), addr1);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_CTRL0(r), ctrl0);
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_hpa_set_outbound_region);
+
+void cdns_pcie_hpa_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie,
+ u8 busnr, u8 fn,
+ u32 r, u64 cpu_addr)
+{
+ u32 addr0, addr1, desc0, desc1, ctrl0;
+
+ desc0 = CDNS_PCIE_HPA_AT_OB_REGION_DESC0_TYPE_NORMAL_MSG;
+ desc1 = 0;
+ ctrl0 = 0;
+
+ /*
+ * See cdns_pcie_set_outbound_region() comments above.
+ */
+ if (pcie->is_rc) {
+ desc1 = CDNS_PCIE_HPA_AT_OB_REGION_DESC1_BUS(busnr) |
+ CDNS_PCIE_HPA_AT_OB_REGION_DESC1_DEVFN(0);
+ ctrl0 = CDNS_PCIE_HPA_AT_OB_REGION_CTRL0_SUPPLY_BUS |
+ CDNS_PCIE_HPA_AT_OB_REGION_CTRL0_SUPPLY_DEV_FN;
+ } else {
+ desc1 |= CDNS_PCIE_HPA_AT_OB_REGION_DESC1_DEVFN(fn);
+ }
+
+ addr0 = CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR0_NBITS(17) |
+ (lower_32_bits(cpu_addr) & GENMASK(31, 8));
+ addr1 = upper_32_bits(cpu_addr);
+
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR0(r), 0);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR1(r), 0);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_DESC0(r), desc0);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_DESC1(r), desc1);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR0(r), addr0);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR1(r), addr1);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_CTRL0(r), ctrl0);
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_hpa_set_outbound_region_for_normal_msg);
+
+void cdns_pcie_hpa_reset_outbound_region(struct cdns_pcie *pcie, u32 r)
+{
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR0(r), 0);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR1(r), 0);
+
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_DESC0(r), 0);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_DESC1(r), 0);
+
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR0(r), 0);
+ cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
+ CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR1(r), 0);
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_hpa_reset_outbound_region);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cadence PCIe controller driver");
+MODULE_AUTHOR("Manikandan K Pillai <mpillai@cadence.com>");
diff --git a/drivers/pci/controller/cadence/pcie-cadence-plat.c b/drivers/pci/controller/cadence/pcie-cadence-plat.c
index ced030cc0fda..6ce18a0cf564 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-plat.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-plat.c
@@ -12,8 +12,7 @@
#include <linux/pm_runtime.h>
#include "pcie-cadence.h"
-#define CDNS_PLAT_CPU_TO_BUS_ADDR 0x0FFFFFFF
-
+void cdns_pcie_disable_phy(struct cdns_pcie *pcie);
/**
* struct cdns_plat_pcie - private data for this PCIe platform driver
* @pcie: Cadence PCIe controller
@@ -24,13 +23,8 @@ struct cdns_plat_pcie {
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,
+ .link_up = cdns_pcie_linkup,
};
static int cdns_plat_pcie_probe(struct platform_device *pdev)
@@ -68,6 +62,11 @@ 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;
+ rc->pcie.is_rc = data->is_rc;
+
+ /* Store the register bank offsets pointer */
+ rc->pcie.cdns_pcie_reg_offsets = data;
+
cdns_plat_pcie->pcie = &rc->pcie;
ret = cdns_pcie_init_phy(dev, cdns_plat_pcie->pcie);
@@ -95,6 +94,11 @@ static int cdns_plat_pcie_probe(struct platform_device *pdev)
ep->pcie.dev = dev;
ep->pcie.ops = &cdns_plat_ops;
+ ep->pcie.is_rc = data->is_rc;
+
+ /* Store the register bank offset pointer */
+ ep->pcie.cdns_pcie_reg_offsets = data;
+
cdns_plat_pcie->pcie = &ep->pcie;
ret = cdns_pcie_init_phy(dev, cdns_plat_pcie->pcie);
diff --git a/drivers/pci/controller/cadence/pcie-cadence.c b/drivers/pci/controller/cadence/pcie-cadence.c
index 51c9bc4eb174..aaf921ea70e0 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.c
+++ b/drivers/pci/controller/cadence/pcie-cadence.c
@@ -9,6 +9,17 @@
#include "pcie-cadence.h"
+bool cdns_pcie_linkup(struct cdns_pcie *pcie)
+{
+ u32 pl_reg_val;
+
+ pl_reg_val = cdns_pcie_readl(pcie, CDNS_PCIE_LM_BASE);
+ if (pl_reg_val & GENMASK(0, 0))
+ return true;
+ return false;
+}
+EXPORT_SYMBOL_GPL(cdns_pcie_linkup);
+
void cdns_pcie_detect_quiet_min_delay_set(struct cdns_pcie *pcie)
{
u32 delay = 0x3;
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
index 8048bef215d0..3e0fd6bb21b1 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -7,10 +7,12 @@
#define _PCIE_CADENCE_H
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pci-epf.h>
#include <linux/phy/phy.h>
#include <linux/bitfield.h>
+
#include "pcie-cadence-lga-regs.h"
#include "pcie-cadence-hpa-regs.h"
@@ -29,6 +31,26 @@ struct cdns_pcie_rp_ib_bar {
struct cdns_pcie;
struct cdns_pcie_rc;
+enum cdns_pcie_msg_routing {
+ /* Route to Root Complex */
+ MSG_ROUTING_TO_RC,
+
+ /* Use Address Routing */
+ MSG_ROUTING_BY_ADDR,
+
+ /* Use ID Routing */
+ MSG_ROUTING_BY_ID,
+
+ /* Route as Broadcast Message from Root Complex */
+ MSG_ROUTING_BCAST,
+
+ /* Local message; terminate at receiver (INTx messages) */
+ MSG_ROUTING_LOCAL,
+
+ /* Gather & route to Root Complex (PME_TO_Ack message) */
+ MSG_ROUTING_GATHER,
+};
+
enum cdns_pcie_reg_bank {
REG_BANK_RP,
REG_BANK_IP_REG,
@@ -43,9 +65,9 @@ enum cdns_pcie_reg_bank {
};
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);
+ 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);
};
@@ -77,6 +99,7 @@ struct cdns_plat_pcie_of_data {
* struct cdns_pcie - private data for Cadence PCIe controller drivers
* @reg_base: IO mapped register base
* @mem_res: start/end offsets in the physical system memory to map PCI accesses
+ * @msg_res: Region for send message to map PCI accesses
* @dev: PCIe controller
* @is_rc: tell whether the PCIe controller mode is Root Complex or Endpoint.
* @phy_count: number of supported PHY devices
@@ -89,6 +112,7 @@ struct cdns_plat_pcie_of_data {
struct cdns_pcie {
void __iomem *reg_base;
struct resource *mem_res;
+ struct resource *msg_res;
struct device *dev;
bool is_rc;
int phy_count;
@@ -111,6 +135,7 @@ struct cdns_pcie {
* available
* @quirk_retrain_flag: Retrain link as quirk for PCIe Gen2
* @quirk_detect_quiet_flag: LTSSM Detect Quiet min delay set as quirk
+ * @ecam_support_flag: Whether the ECAM flag is supported
*/
struct cdns_pcie_rc {
struct cdns_pcie pcie;
@@ -121,6 +146,8 @@ struct cdns_pcie_rc {
bool avail_ib_bar[CDNS_PCIE_RP_MAX_IB];
unsigned int quirk_retrain_flag:1;
unsigned int quirk_detect_quiet_flag:1;
+ unsigned int ecam_support_flag:1;
+ unsigned int no_inbound_flag:1;
};
/**
@@ -304,6 +331,29 @@ static inline u16 cdns_pcie_rp_readw(struct cdns_pcie *pcie, u32 reg)
return cdns_pcie_read_sz(addr, 0x2);
}
+static inline void cdns_pcie_hpa_rp_writeb(struct cdns_pcie *pcie,
+ u32 reg, u8 value)
+{
+ void __iomem *addr = pcie->reg_base + CDNS_PCIE_HPA_RP_BASE + reg;
+
+ cdns_pcie_write_sz(addr, 0x1, value);
+}
+
+static inline void cdns_pcie_hpa_rp_writew(struct cdns_pcie *pcie,
+ u32 reg, u16 value)
+{
+ void __iomem *addr = pcie->reg_base + CDNS_PCIE_HPA_RP_BASE + reg;
+
+ cdns_pcie_write_sz(addr, 0x2, value);
+}
+
+static inline u16 cdns_pcie_hpa_rp_readw(struct cdns_pcie *pcie, u32 reg)
+{
+ void __iomem *addr = pcie->reg_base + CDNS_PCIE_HPA_RP_BASE + reg;
+
+ return cdns_pcie_read_sz(addr, 0x2);
+}
+
/* Endpoint Function register access */
static inline void cdns_pcie_ep_fn_writeb(struct cdns_pcie *pcie, u8 fn,
u32 reg, u8 value)
@@ -368,6 +418,7 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc);
void cdns_pcie_host_disable(struct cdns_pcie_rc *rc);
void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
int where);
+int cdns_pcie_hpa_host_setup(struct cdns_pcie_rc *rc);
#else
static inline int cdns_pcie_host_link_setup(struct cdns_pcie_rc *rc)
{
@@ -384,6 +435,11 @@ static inline int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
return 0;
}
+static inline int cdns_pcie_hpa_host_setup(struct cdns_pcie_rc *rc)
+{
+ return 0;
+}
+
static inline void cdns_pcie_host_disable(struct cdns_pcie_rc *rc)
{
}
@@ -398,17 +454,25 @@ static inline void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int d
#if IS_ENABLED(CONFIG_PCIE_CADENCE_EP)
int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep);
void cdns_pcie_ep_disable(struct cdns_pcie_ep *ep);
+int cdns_pcie_hpa_ep_setup(struct cdns_pcie_ep *ep);
#else
static inline int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
{
return 0;
}
+static inline int cdns_pcie_hpa_ep_setup(struct cdns_pcie_ep *ep)
+{
+ return 0;
+}
+
static inline void cdns_pcie_ep_disable(struct cdns_pcie_ep *ep)
{
}
#endif
-
+bool cdns_pcie_linkup(struct cdns_pcie *pcie);
+int cdns_pcie_host_wait_for_link(struct cdns_pcie *pcie);
+int cdns_pcie_host_start_link(struct cdns_pcie_rc *rc);
void cdns_pcie_detect_quiet_min_delay_set(struct cdns_pcie *pcie);
void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 busnr, u8 fn,
u32 r, bool is_io,
@@ -421,6 +485,25 @@ 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);
+void cdns_pcie_hpa_detect_quiet_min_delay_set(struct cdns_pcie *pcie);
+void cdns_pcie_hpa_set_outbound_region(struct cdns_pcie *pcie, u8 busnr, u8 fn,
+ u32 r, bool is_io,
+ u64 cpu_addr, u64 pci_addr, size_t size);
+void cdns_pcie_hpa_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie,
+ u8 busnr, u8 fn,
+ u32 r, u64 cpu_addr);
+void cdns_pcie_hpa_reset_outbound_region(struct cdns_pcie *pcie, u32 r);
+int cdns_pcie_hpa_host_link_setup(struct cdns_pcie_rc *rc);
+int cdns_pcie_hpa_host_init(struct cdns_pcie_rc *rc);
+void __iomem *cdns_pci_hpa_map_bus(struct pci_bus *bus, unsigned int devfn,
+ int where);
+int cdns_pcie_hpa_host_wait_for_link(struct cdns_pcie *pcie);
+int cdns_pcie_hpa_host_start_link(struct cdns_pcie_rc *rc);
+
+int cdns_pcie_hpa_start_link(struct cdns_pcie *pcie);
+void cdns_pcie_hpa_stop_link(struct cdns_pcie *pcie);
+bool cdns_pcie_hpa_link_up(struct cdns_pcie *pcie);
+
extern const struct dev_pm_ops cdns_pcie_pm_ops;
#endif /* _PCIE_CADENCE_H */
--
2.49.0
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH v7 08/13] dt-bindings: PCI: Add CIX Sky1 PCIe Root Complex bindings
2025-08-13 4:23 [PATCH v7 00/13] Enhance the PCIe controller driver for next generation controllers hans.zhang
` (6 preceding siblings ...)
2025-08-13 4:23 ` [PATCH v7 07/13] PCI: cadence: Add support for High Performance Arch(HPA) controller hans.zhang
@ 2025-08-13 4:23 ` hans.zhang
2025-08-13 8:31 ` Rob Herring (Arm)
2025-08-13 15:44 ` Rob Herring
2025-08-13 4:23 ` [PATCH v7 09/13] PCI: Add Cix Technology Vendor and Device ID hans.zhang
` (5 subsequent siblings)
13 siblings, 2 replies; 40+ messages in thread
From: hans.zhang @ 2025-08-13 4:23 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kw, mani, robh, kwilczynski, krzk+dt,
conor+dt
Cc: mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel,
Hans Zhang
From: Hans Zhang <hans.zhang@cixtech.com>
Document the bindings for CIX Sky1 PCIe Controller configured in
root complex mode with five root port.
Supports 4 INTx, MSI and MSI-x interrupts from the ARM GICv3 controller.
Signed-off-by: Hans Zhang <hans.zhang@cixtech.com>
---
.../bindings/pci/cix,sky1-pcie-host.yaml | 79 +++++++++++++++++++
1 file changed, 79 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.yaml
diff --git a/Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.yaml b/Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.yaml
new file mode 100644
index 000000000000..2bd66603ac24
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.yaml
@@ -0,0 +1,79 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pci/cix,sky1-pcie-host.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: CIX Sky1 PCIe Root Complex
+
+maintainers:
+ - Hans Zhang <hans.zhang@cixtech.com>
+
+description:
+ PCIe root complex controller based on the Cadence PCIe core.
+
+allOf:
+ - $ref: /schemas/pci/pci-host-bridge.yaml#
+
+properties:
+ compatible:
+ const: cix,sky1-pcie-host
+
+ reg:
+ items:
+ - description: PCIe controller registers.
+ - description: ECAM registers.
+ - description: Remote CIX System Unit registers.
+ - description: Region for sending messages registers.
+
+ reg-names:
+ items:
+ - const: reg
+ - const: cfg
+ - const: rcsu
+ - const: msg
+
+ ranges:
+ maxItems: 3
+
+required:
+ - compatible
+ - ranges
+ - bus-range
+ - device_type
+ - interrupt-map
+ - interrupt-map-mask
+ - msi-map
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ / {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ pcie@a010000 {
+ compatible = "cix,sky1-pcie-host";
+ reg = <0x00 0x0a010000 0x00 0x10000>,
+ <0x00 0x2c000000 0x00 0x4000000>,
+ <0x00 0x0a000000 0x00 0x10000>,
+ <0x00 0x60000000 0x00 0x00100000>;
+ reg-names = "reg", "cfg", "rcsu", "msg";
+ ranges = <0x01000000 0x00 0x60100000 0x00 0x60100000 0x00 0x00100000>,
+ <0x02000000 0x00 0x60200000 0x00 0x60200000 0x00 0x1fe00000>,
+ <0x43000000 0x18 0x00000000 0x18 0x00000000 0x04 0x00000000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ bus-range = <0xc0 0xff>;
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0x7>;
+ interrupt-map = <0 0 0 1 &gic 0 0 GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH 0>,
+ <0 0 0 2 &gic 0 0 GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH 0>,
+ <0 0 0 3 &gic 0 0 GIC_SPI 409 IRQ_TYPE_LEVEL_HIGH 0>,
+ <0 0 0 4 &gic 0 0 GIC_SPI 410 IRQ_TYPE_LEVEL_HIGH 0>;
+ msi-map = <0xc000 &gic_its 0xc000 0x4000>;
+ };
+ };
--
2.49.0
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH v7 09/13] PCI: Add Cix Technology Vendor and Device ID
2025-08-13 4:23 [PATCH v7 00/13] Enhance the PCIe controller driver for next generation controllers hans.zhang
` (7 preceding siblings ...)
2025-08-13 4:23 ` [PATCH v7 08/13] dt-bindings: PCI: Add CIX Sky1 PCIe Root Complex bindings hans.zhang
@ 2025-08-13 4:23 ` hans.zhang
2025-08-14 22:23 ` Bjorn Helgaas
2025-08-13 4:23 ` [PATCH v7 10/13] PCI: sky1: Add PCIe host support for CIX Sky1 hans.zhang
` (4 subsequent siblings)
13 siblings, 1 reply; 40+ messages in thread
From: hans.zhang @ 2025-08-13 4:23 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kw, mani, robh, kwilczynski, krzk+dt,
conor+dt
Cc: mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel,
Hans Zhang
From: Hans Zhang <hans.zhang@cixtech.com>
Add Cixtech P1 (internal name sky1) as a vendor and device ID for PCI
devices. This ID will be used by the CIX Sky1 PCIe host controller driver.
Signed-off-by: Hans Zhang <hans.zhang@cixtech.com>
---
include/linux/pci_ids.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 92ffc4373f6d..24b04d085920 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -2631,6 +2631,9 @@
#define PCI_VENDOR_ID_CXL 0x1e98
+#define PCI_VENDOR_ID_CIX 0x1f6c
+#define PCI_DEVICE_ID_CIX_SKY1 0x0001
+
#define PCI_VENDOR_ID_TEHUTI 0x1fc9
#define PCI_DEVICE_ID_TEHUTI_3009 0x3009
#define PCI_DEVICE_ID_TEHUTI_3010 0x3010
--
2.49.0
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH v7 10/13] PCI: sky1: Add PCIe host support for CIX Sky1
2025-08-13 4:23 [PATCH v7 00/13] Enhance the PCIe controller driver for next generation controllers hans.zhang
` (8 preceding siblings ...)
2025-08-13 4:23 ` [PATCH v7 09/13] PCI: Add Cix Technology Vendor and Device ID hans.zhang
@ 2025-08-13 4:23 ` hans.zhang
2025-08-13 19:16 ` Krzysztof Kozlowski
2025-08-14 22:46 ` Bjorn Helgaas
2025-08-13 4:23 ` [PATCH v7 11/13] MAINTAINERS: add entry for CIX Sky1 PCIe driver hans.zhang
` (3 subsequent siblings)
13 siblings, 2 replies; 40+ messages in thread
From: hans.zhang @ 2025-08-13 4:23 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kw, mani, robh, kwilczynski, krzk+dt,
conor+dt
Cc: mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel,
Hans Zhang
From: Hans Zhang <hans.zhang@cixtech.com>
Add driver for the CIX Sky1 SoC PCIe Gen4 16 GT/s controller based
on the Cadence PCIe core.
Supports MSI/MSI-x via GICv3, Single Virtual Channel, Single Function.
Signed-off-by: Hans Zhang <hans.zhang@cixtech.com>
---
drivers/pci/controller/cadence/Kconfig | 13 +
drivers/pci/controller/cadence/Makefile | 1 +
drivers/pci/controller/cadence/pci-sky1.c | 294 ++++++++++++++++++++++
3 files changed, 308 insertions(+)
create mode 100644 drivers/pci/controller/cadence/pci-sky1.c
diff --git a/drivers/pci/controller/cadence/Kconfig b/drivers/pci/controller/cadence/Kconfig
index 117677a23d68..1716b7300fa1 100644
--- a/drivers/pci/controller/cadence/Kconfig
+++ b/drivers/pci/controller/cadence/Kconfig
@@ -67,4 +67,17 @@ config PCI_J721E_EP
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.
+
+config PCI_SKY1_HOST
+ tristate "CIX SKY1 PCIe controller (host mode)"
+ depends on OF
+ select PCIE_CADENCE_HOST
+ select PCI_ECAM
+ help
+ Say Y here if you want to support the CIX SKY1 PCIe platform
+ controller in host mode. CIX SKY1 PCIe controller uses Cadence HPA(High
+ Performance Architecture IP[Second generation of cadence PCIe IP])
+
+ This driver requires Cadence PCIe core infrastructure (PCIE_CADENCE_HOST)
+ and hardware platform adaptation layer to function.
endmenu
diff --git a/drivers/pci/controller/cadence/Makefile b/drivers/pci/controller/cadence/Makefile
index de4ddae7aca4..40d7c6e98b4d 100644
--- a/drivers/pci/controller/cadence/Makefile
+++ b/drivers/pci/controller/cadence/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host-mod.o
obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep-mod.o
obj-$(CONFIG_PCIE_CADENCE_PLAT) += pcie-cadence-plat.o
obj-$(CONFIG_PCI_J721E) += pci-j721e.o
+obj-$(CONFIG_PCI_SKY1_HOST) += pci-sky1.o
diff --git a/drivers/pci/controller/cadence/pci-sky1.c b/drivers/pci/controller/cadence/pci-sky1.c
new file mode 100644
index 000000000000..36267d0bb5b6
--- /dev/null
+++ b/drivers/pci/controller/cadence/pci-sky1.c
@@ -0,0 +1,294 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PCIe controller driver for CIX's sky1 SoCs
+ *
+ * Author: Hans Zhang <hans.zhang@cixtech.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pci.h>
+#include <linux/pci-ecam.h>
+#include <linux/pci_ids.h>
+
+#include "pcie-cadence.h"
+#include "pcie-cadence-host-common.h"
+
+#define STRAP_REG(n) ((n) * 0x04)
+#define STATUS_REG(n) ((n) * 0x04)
+
+#define RCSU_STRAP_REG 0x300
+#define RCSU_STATUS_REG 0x400
+
+#define SKY1_IP_REG_BANK_OFFSET 0x1000
+#define SKY1_IP_CFG_CTRL_REG_BANK_OFFSET 0x4c00
+#define SKY1_IP_AXI_MASTER_COMMON_OFFSET 0xf000
+#define SKY1_AXI_SLAVE_OFFSET 0x9000
+#define SKY1_AXI_MASTER_OFFSET 0xb000
+#define SKY1_AXI_HLS_REGISTERS_OFFSET 0xc000
+#define SKY1_AXI_RAS_REGISTERS_OFFSET 0xe000
+#define SKY1_DTI_REGISTERS_OFFSET 0xd000
+
+#define IP_REG_I_DBG_STS_0 0x420
+
+#define LINK_TRAINING_ENABLE BIT(0)
+#define LINK_COMPLETE BIT(0)
+
+enum cix_soc_type {
+ CIX_SKY1,
+};
+
+struct sky1_pcie_data {
+ struct cdns_plat_pcie_of_data reg_off;
+ enum cix_soc_type soc_type;
+};
+
+struct sky1_pcie {
+ struct device *dev;
+ const struct sky1_pcie_data *data;
+ struct cdns_pcie *cdns_pcie;
+ struct cdns_pcie_rc *cdns_pcie_rc;
+
+ struct resource *cfg_res;
+ struct resource *msg_res;
+ struct pci_config_window *cfg;
+ void __iomem *rcsu_base;
+ void __iomem *strap_base;
+ void __iomem *status_base;
+ void __iomem *reg_base;
+ void __iomem *cfg_base;
+ void __iomem *msg_base;
+};
+
+static void sky1_pcie_clear_and_set_dword(void __iomem *addr, u32 clear,
+ u32 set)
+{
+ u32 val;
+
+ val = readl(addr);
+ val &= ~clear;
+ val |= set;
+ writel(val, addr);
+}
+
+static void sky1_pcie_init_bases(struct sky1_pcie *pcie)
+{
+ pcie->strap_base = pcie->rcsu_base + RCSU_STRAP_REG;
+ pcie->status_base = pcie->rcsu_base + RCSU_STATUS_REG;
+}
+
+static int sky1_pcie_parse_mem(struct sky1_pcie *pcie)
+{
+ struct device *dev = pcie->dev;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct resource *res;
+ void __iomem *base;
+ int ret = 0;
+
+ base = devm_platform_ioremap_resource_byname(pdev, "reg");
+ if (IS_ERR(base)) {
+ dev_err(dev, "Parse \"reg\" resource err\n");
+ return PTR_ERR(base);
+ }
+ pcie->reg_base = base;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
+ if (!res) {
+ dev_err(dev, "Parse \"cfg\" resource err\n");
+ return -ENXIO;
+ }
+ pcie->cfg_res = res;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rcsu");
+ if (!res) {
+ dev_err(dev, "Parse \"rcsu\" resource err\n");
+ return -ENXIO;
+ }
+ pcie->rcsu_base = devm_ioremap(dev, res->start, resource_size(res));
+ if (!pcie->rcsu_base) {
+ dev_err(dev, "ioremap failed for resource %pR\n", res);
+ return -ENOMEM;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "msg");
+ if (!res) {
+ dev_err(dev, "Parse \"msg\" resource err\n");
+ return -ENXIO;
+ }
+ pcie->msg_res = res;
+ pcie->msg_base = devm_ioremap(dev, res->start, resource_size(res));
+ if (!pcie->msg_base) {
+ dev_err(dev, "ioremap failed for resource %pR\n", res);
+ return -ENOMEM;
+ }
+
+ return ret;
+}
+
+static int sky1_pcie_parse_property(struct platform_device *pdev,
+ struct sky1_pcie *pcie)
+{
+ int ret = 0;
+
+ ret = sky1_pcie_parse_mem(pcie);
+ if (ret < 0)
+ return ret;
+
+ sky1_pcie_init_bases(pcie);
+
+ return ret;
+}
+
+static int sky1_pcie_start_link(struct cdns_pcie *cdns_pcie)
+{
+ struct sky1_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
+
+ sky1_pcie_clear_and_set_dword(pcie->strap_base + STRAP_REG(1),
+ 0, LINK_TRAINING_ENABLE);
+
+ return 0;
+}
+
+static void sky1_pcie_stop_link(struct cdns_pcie *cdns_pcie)
+{
+ struct sky1_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
+
+ sky1_pcie_clear_and_set_dword(pcie->strap_base + STRAP_REG(1),
+ LINK_TRAINING_ENABLE, 0);
+}
+
+
+static bool sky1_pcie_link_up(struct cdns_pcie *cdns_pcie)
+{
+ u32 val;
+
+ val = cdns_pcie_hpa_readl(cdns_pcie, REG_BANK_IP_REG,
+ IP_REG_I_DBG_STS_0);
+ return val & LINK_COMPLETE;
+}
+
+static const struct cdns_pcie_ops sky1_pcie_ops = {
+ .start_link = sky1_pcie_start_link,
+ .stop_link = sky1_pcie_stop_link,
+ .link_up = sky1_pcie_link_up,
+};
+
+static int sky1_pcie_probe(struct platform_device *pdev)
+{
+ const struct sky1_pcie_data *data;
+ struct device *dev = &pdev->dev;
+ struct pci_host_bridge *bridge;
+ struct cdns_pcie *cdns_pcie;
+ struct resource_entry *bus;
+ struct cdns_pcie_rc *rc;
+ struct sky1_pcie *pcie;
+ int ret;
+
+ pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
+ if (!pcie)
+ return -ENOMEM;
+
+ data = of_device_get_match_data(dev);
+ if (!data)
+ return -EINVAL;
+
+ pcie->data = data;
+ pcie->dev = dev;
+ dev_set_drvdata(dev, pcie);
+
+ bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
+ if (!bridge)
+ return -ENOMEM;
+
+ bus = resource_list_first_type(&bridge->windows, IORESOURCE_BUS);
+ if (!bus)
+ return -ENODEV;
+
+ ret = sky1_pcie_parse_property(pdev, pcie);
+ if (ret < 0)
+ return -ENXIO;
+
+ pcie->cfg = pci_ecam_create(dev, pcie->cfg_res, bus->res,
+ &pci_generic_ecam_ops);
+ if (IS_ERR(pcie->cfg))
+ return PTR_ERR(pcie->cfg);
+
+ bridge->ops = (struct pci_ops *)&pci_generic_ecam_ops.pci_ops;
+ rc = pci_host_bridge_priv(bridge);
+ rc->ecam_support_flag = 1;
+ rc->cfg_base = pcie->cfg->win;
+ rc->cfg_res = &pcie->cfg->res;
+
+ cdns_pcie = &rc->pcie;
+ cdns_pcie->dev = dev;
+ cdns_pcie->ops = &sky1_pcie_ops;
+ cdns_pcie->reg_base = pcie->reg_base;
+ cdns_pcie->msg_res = pcie->msg_res;
+ cdns_pcie->cdns_pcie_reg_offsets = &data->reg_off;
+ cdns_pcie->is_rc = data->reg_off.is_rc;
+
+ pcie->cdns_pcie = cdns_pcie;
+ pcie->cdns_pcie_rc = rc;
+ pcie->cfg_base = rc->cfg_base;
+ bridge->sysdata = pcie->cfg;
+
+ if (data->soc_type == CIX_SKY1) {
+ rc->vendor_id = PCI_VENDOR_ID_CIX;
+ rc->device_id = PCI_DEVICE_ID_CIX_SKY1;
+ rc->no_inbound_flag = 1;
+ }
+
+ ret = cdns_pcie_hpa_host_setup(rc);
+ if (ret < 0) {
+ pci_ecam_free(pcie->cfg);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct sky1_pcie_data sky1_pcie_rc_data = {
+ .reg_off = {
+ .is_rc = true,
+ .ip_reg_bank_offset = SKY1_IP_REG_BANK_OFFSET,
+ .ip_cfg_ctrl_reg_offset = SKY1_IP_CFG_CTRL_REG_BANK_OFFSET,
+ .axi_mstr_common_offset = SKY1_IP_AXI_MASTER_COMMON_OFFSET,
+ .axi_slave_offset = SKY1_AXI_SLAVE_OFFSET,
+ .axi_master_offset = SKY1_AXI_MASTER_OFFSET,
+ .axi_hls_offset = SKY1_AXI_HLS_REGISTERS_OFFSET,
+ .axi_ras_offset = SKY1_AXI_RAS_REGISTERS_OFFSET,
+ .axi_dti_offset = SKY1_DTI_REGISTERS_OFFSET,
+ },
+ .soc_type = CIX_SKY1,
+};
+
+static const struct of_device_id of_sky1_pcie_match[] = {
+ {
+ .compatible = "cix,sky1-pcie-host",
+ .data = &sky1_pcie_rc_data,
+ },
+ {},
+};
+
+static void sky1_pcie_remove(struct platform_device *pdev)
+{
+ struct sky1_pcie *pcie = platform_get_drvdata(pdev);
+
+ pci_ecam_free(pcie->cfg);
+}
+
+static struct platform_driver sky1_pcie_driver = {
+ .probe = sky1_pcie_probe,
+ .remove = sky1_pcie_remove,
+ .driver = {
+ .name = "sky1-pcie",
+ .of_match_table = of_sky1_pcie_match,
+ },
+};
+module_platform_driver(sky1_pcie_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PCIe controller driver for CIX's sky1 SoCs");
+MODULE_AUTHOR("Hans Zhang <hans.zhang@cixtech.com>");
--
2.49.0
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH v7 11/13] MAINTAINERS: add entry for CIX Sky1 PCIe driver
2025-08-13 4:23 [PATCH v7 00/13] Enhance the PCIe controller driver for next generation controllers hans.zhang
` (9 preceding siblings ...)
2025-08-13 4:23 ` [PATCH v7 10/13] PCI: sky1: Add PCIe host support for CIX Sky1 hans.zhang
@ 2025-08-13 4:23 ` hans.zhang
2025-08-13 4:23 ` [PATCH v7 12/13] arm64: dts: cix: Add PCIe Root Complex on sky1 hans.zhang
` (2 subsequent siblings)
13 siblings, 0 replies; 40+ messages in thread
From: hans.zhang @ 2025-08-13 4:23 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kw, mani, robh, kwilczynski, krzk+dt,
conor+dt
Cc: mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel,
Hans Zhang
From: Hans Zhang <hans.zhang@cixtech.com>
Add myself as maintainer of Sky1 PCIe host driver
Signed-off-by: Hans Zhang <hans.zhang@cixtech.com>
---
MAINTAINERS | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index fe168477caa4..d84062b632c8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19253,6 +19253,13 @@ S: Orphan
F: Documentation/devicetree/bindings/pci/cdns,*
F: drivers/pci/controller/cadence/*cadence*
+PCI DRIVER FOR CIX Sky1
+M: Hans Zhang <hans.zhang@cixtech.com>
+L: linux-pci@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/pci/cix,sky1-pcie-*.yaml
+F: drivers/pci/controller/cadence/*sky1*
+
PCI DRIVER FOR FREESCALE LAYERSCAPE
M: Minghuan Lian <minghuan.Lian@nxp.com>
M: Mingkai Hu <mingkai.hu@nxp.com>
--
2.49.0
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH v7 12/13] arm64: dts: cix: Add PCIe Root Complex on sky1
2025-08-13 4:23 [PATCH v7 00/13] Enhance the PCIe controller driver for next generation controllers hans.zhang
` (10 preceding siblings ...)
2025-08-13 4:23 ` [PATCH v7 11/13] MAINTAINERS: add entry for CIX Sky1 PCIe driver hans.zhang
@ 2025-08-13 4:23 ` hans.zhang
2025-08-13 4:23 ` [PATCH v7 13/13] arm64: dts: cix: Enable PCIe on the Orion O6 board hans.zhang
2025-08-13 19:14 ` [PATCH v7 00/13] Enhance the PCIe controller driver for next generation controllers Krzysztof Kozlowski
13 siblings, 0 replies; 40+ messages in thread
From: hans.zhang @ 2025-08-13 4:23 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kw, mani, robh, kwilczynski, krzk+dt,
conor+dt
Cc: mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel,
Hans Zhang
From: Hans Zhang <hans.zhang@cixtech.com>
Add pcie_x*_rc node to support Sky1 PCIe driver based on the
Cadence PCIe core.
Supports Gen1/Gen2/Gen3/Gen4, 1/2/4/8 lane, MSI/MSI-x interrupts
using the ARM GICv3.
Signed-off-by: Hans Zhang <hans.zhang@cixtech.com>
---
arch/arm64/boot/dts/cix/sky1.dtsi | 121 ++++++++++++++++++++++++++++++
1 file changed, 121 insertions(+)
diff --git a/arch/arm64/boot/dts/cix/sky1.dtsi b/arch/arm64/boot/dts/cix/sky1.dtsi
index 7dfe7677e649..04ba80d4fc06 100644
--- a/arch/arm64/boot/dts/cix/sky1.dtsi
+++ b/arch/arm64/boot/dts/cix/sky1.dtsi
@@ -288,6 +288,127 @@ mbox_ap2sfh: mailbox@80a0000 {
cix,mbox-dir = "tx";
};
+ pcie_x8_rc: pcie@a010000 {
+ compatible = "cix,sky1-pcie-host";
+ reg = <0x00 0x0a010000 0x00 0x10000>,
+ <0x00 0x2c000000 0x00 0x4000000>,
+ <0x00 0x0a000000 0x00 0x10000>,
+ <0x00 0x60000000 0x00 0x00100000>;
+ reg-names = "reg", "cfg", "rcsu", "msg";
+ ranges = <0x01000000 0x0 0x60100000 0x0 0x60100000 0x0 0x00100000>,
+ <0x02000000 0x0 0x60200000 0x0 0x60200000 0x0 0x1fe00000>,
+ <0x43000000 0x18 0x00000000 0x18 0x00000000 0x04 0x00000000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ bus-range = <0xc0 0xff>;
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0x7>;
+ interrupt-map = <0 0 0 1 &gic 0 0 GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH 0>,
+ <0 0 0 2 &gic 0 0 GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH 0>,
+ <0 0 0 3 &gic 0 0 GIC_SPI 409 IRQ_TYPE_LEVEL_HIGH 0>,
+ <0 0 0 4 &gic 0 0 GIC_SPI 410 IRQ_TYPE_LEVEL_HIGH 0>;
+ msi-map = <0xc000 &gic_its 0xc000 0x4000>;
+ status = "disabled";
+ };
+
+ pcie_x4_rc: pcie@a070000 {
+ compatible = "cix,sky1-pcie-host";
+ reg = <0x00 0x0a070000 0x00 0x10000>,
+ <0x00 0x29000000 0x00 0x3000000>,
+ <0x00 0x0a060000 0x00 0x10000>,
+ <0x00 0x50000000 0x00 0x00100000>;
+ reg-names = "reg", "cfg", "rcsu", "msg";
+ ranges = <0x01000000 0x00 0x50100000 0x00 0x50100000 0x00 0x00100000>,
+ <0x02000000 0x00 0x50200000 0x00 0x50200000 0x00 0x0fe00000>,
+ <0x43000000 0x14 0x00000000 0x14 0x00000000 0x04 0x00000000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ bus-range = <0x90 0xbf>;
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0x7>;
+ interrupt-map = <0 0 0 1 &gic 0 0 GIC_SPI 417 IRQ_TYPE_LEVEL_HIGH 0>,
+ <0 0 0 2 &gic 0 0 GIC_SPI 418 IRQ_TYPE_LEVEL_HIGH 0>,
+ <0 0 0 3 &gic 0 0 GIC_SPI 419 IRQ_TYPE_LEVEL_HIGH 0>,
+ <0 0 0 4 &gic 0 0 GIC_SPI 420 IRQ_TYPE_LEVEL_HIGH 0>;
+ msi-map = <0x9000 &gic_its 0x9000 0x3000>;
+ status = "disabled";
+ };
+
+ pcie_x2_rc: pcie@a0c0000 {
+ compatible = "cix,sky1-pcie-host";
+ reg = <0x00 0x0a0c0000 0x00 0x10000>,
+ <0x00 0x26000000 0x00 0x3000000>,
+ <0x00 0x0a060040 0x00 0x10000>,
+ <0x00 0x40000000 0x00 0x00100000>;
+ reg-names = "reg", "cfg", "rcsu", "msg";
+ ranges = <0x01000000 0x0 0x40100000 0x0 0x40100000 0x0 0x00100000>,
+ <0x02000000 0x0 0x40200000 0x0 0x40200000 0x0 0x0fe00000>,
+ <0x43000000 0x10 0x00000000 0x10 0x00000000 0x04 0x00000000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ bus-range = <0x60 0x8f>;
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0x7>;
+ interrupt-map = <0 0 0 1 &gic 0 0 GIC_SPI 427 IRQ_TYPE_LEVEL_HIGH 0>,
+ <0 0 0 2 &gic 0 0 GIC_SPI 428 IRQ_TYPE_LEVEL_HIGH 0>,
+ <0 0 0 3 &gic 0 0 GIC_SPI 429 IRQ_TYPE_LEVEL_HIGH 0>,
+ <0 0 0 4 &gic 0 0 GIC_SPI 430 IRQ_TYPE_LEVEL_HIGH 0>;
+ msi-map = <0x6000 &gic_its 0x6000 0x3000>;
+ status = "disabled";
+ };
+
+ pcie_x1_0_rc: pcie@a0d0000 {
+ compatible = "cix,sky1-pcie-host";
+ reg = <0x00 0x0a0d0000 0x00 0x10000>,
+ <0x00 0x20000000 0x00 0x3000000>,
+ <0x00 0x0a060060 0x00 0x10000>,
+ <0x00 0x30000000 0x00 0x00100000>;
+ reg-names = "reg", "cfg", "rcsu", "msg";
+ ranges = <0x01000000 0x0 0x30100000 0x0 0x30100000 0x0 0x00100000>,
+ <0x02000000 0x0 0x30200000 0x0 0x30200000 0x0 0x07e00000>,
+ <0x43000000 0x08 0x00000000 0x08 0x00000000 0x04 0x00000000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ bus-range = <0x00 0x2f>;
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0x7>;
+ interrupt-map = <0 0 0 1 &gic 0 0 GIC_SPI 436 IRQ_TYPE_LEVEL_HIGH 0>,
+ <0 0 0 2 &gic 0 0 GIC_SPI 437 IRQ_TYPE_LEVEL_HIGH 0>,
+ <0 0 0 3 &gic 0 0 GIC_SPI 438 IRQ_TYPE_LEVEL_HIGH 0>,
+ <0 0 0 4 &gic 0 0 GIC_SPI 439 IRQ_TYPE_LEVEL_HIGH 0>;
+ msi-map = <0x0000 &gic_its 0x0000 0x3000>;
+ status = "disabled";
+ };
+
+ pcie_x1_1_rc: pcie@a0e0000 {
+ compatible = "cix,sky1-pcie-host";
+ reg = <0x00 0x0a0e0000 0x00 0x10000>,
+ <0x00 0x23000000 0x00 0x3000000>,
+ <0x00 0x0a060080 0x00 0x10000>,
+ <0x00 0x38000000 0x00 0x00100000>;
+ reg-names = "reg", "cfg", "rcsu", "msg";
+ ranges = <0x01000000 0x0 0x38100000 0x0 0x38100000 0x0 0x00100000>,
+ <0x02000000 0x0 0x38200000 0x0 0x38200000 0x0 0x07e00000>,
+ <0x43000000 0x0C 0x00000000 0x0C 0x00000000 0x04 0x00000000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ bus-range = <0x30 0x5f>;
+ device_type = "pci";
+
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0x7>;
+ interrupt-map = <0 0 0 1 &gic 0 0 GIC_SPI 445 IRQ_TYPE_LEVEL_HIGH 0>,
+ <0 0 0 2 &gic 0 0 GIC_SPI 446 IRQ_TYPE_LEVEL_HIGH 0>,
+ <0 0 0 3 &gic 0 0 GIC_SPI 447 IRQ_TYPE_LEVEL_HIGH 0>,
+ <0 0 0 4 &gic 0 0 GIC_SPI 448 IRQ_TYPE_LEVEL_HIGH 0>;
+ msi-map = <0x3000 &gic_its 0x3000 0x3000>;
+ status = "disabled";
+ };
+
gic: interrupt-controller@e010000 {
compatible = "arm,gic-v3";
reg = <0x0 0x0e010000 0 0x10000>, /* GICD */
--
2.49.0
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH v7 13/13] arm64: dts: cix: Enable PCIe on the Orion O6 board
2025-08-13 4:23 [PATCH v7 00/13] Enhance the PCIe controller driver for next generation controllers hans.zhang
` (11 preceding siblings ...)
2025-08-13 4:23 ` [PATCH v7 12/13] arm64: dts: cix: Add PCIe Root Complex on sky1 hans.zhang
@ 2025-08-13 4:23 ` hans.zhang
2025-08-13 19:14 ` [PATCH v7 00/13] Enhance the PCIe controller driver for next generation controllers Krzysztof Kozlowski
13 siblings, 0 replies; 40+ messages in thread
From: hans.zhang @ 2025-08-13 4:23 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kw, mani, robh, kwilczynski, krzk+dt,
conor+dt
Cc: mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel,
Hans Zhang
From: Hans Zhang <hans.zhang@cixtech.com>
Add PCIe RC support on Orion O6 board.
Signed-off-by: Hans Zhang <hans.zhang@cixtech.com>
---
Dear Krzysztof,
Due to the fact that the GPIO, PINCTRL and other modules of our platform are
not yet ready for upstream. Attributes that PCIe depends on, such as reset-gpios
and pinctrl*, have not been added for the time being. It will be added gradually
in the future.
The following are Arnd's previous comments. We can go to upsteam separately.
https://lore.kernel.org/all/422deb4d-db29-48c1-b0c9-7915951df500@app.fastmail.com/
---
arch/arm64/boot/dts/cix/sky1-orion-o6.dts | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/arch/arm64/boot/dts/cix/sky1-orion-o6.dts b/arch/arm64/boot/dts/cix/sky1-orion-o6.dts
index d74964d53c3b..be3ec4f5d11e 100644
--- a/arch/arm64/boot/dts/cix/sky1-orion-o6.dts
+++ b/arch/arm64/boot/dts/cix/sky1-orion-o6.dts
@@ -34,6 +34,26 @@ linux,cma {
};
+&pcie_x8_rc {
+ status = "okay";
+};
+
+&pcie_x4_rc {
+ status = "okay";
+};
+
+&pcie_x2_rc {
+ status = "okay";
+};
+
+&pcie_x1_0_rc {
+ status = "okay";
+};
+
+&pcie_x1_1_rc {
+ status = "okay";
+};
+
&uart2 {
status = "okay";
};
--
2.49.0
^ permalink raw reply related [flat|nested] 40+ messages in thread
* Re: [PATCH v7 08/13] dt-bindings: PCI: Add CIX Sky1 PCIe Root Complex bindings
2025-08-13 4:23 ` [PATCH v7 08/13] dt-bindings: PCI: Add CIX Sky1 PCIe Root Complex bindings hans.zhang
@ 2025-08-13 8:31 ` Rob Herring (Arm)
2025-08-13 9:12 ` Hans Zhang
2025-08-13 15:44 ` Rob Herring
1 sibling, 1 reply; 40+ messages in thread
From: Rob Herring (Arm) @ 2025-08-13 8:31 UTC (permalink / raw)
To: hans.zhang
Cc: mpillai, cix-kernel-upstream, lpieralisi, bhelgaas, devicetree,
conor+dt, linux-pci, mani, kw, kwilczynski, krzk+dt, fugang.duan,
guoyin.chen, peter.chen, linux-kernel
On Wed, 13 Aug 2025 12:23:26 +0800, hans.zhang@cixtech.com wrote:
> From: Hans Zhang <hans.zhang@cixtech.com>
>
> Document the bindings for CIX Sky1 PCIe Controller configured in
> root complex mode with five root port.
>
> Supports 4 INTx, MSI and MSI-x interrupts from the ARM GICv3 controller.
>
> Signed-off-by: Hans Zhang <hans.zhang@cixtech.com>
> ---
> .../bindings/pci/cix,sky1-pcie-host.yaml | 79 +++++++++++++++++++
> 1 file changed, 79 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.yaml
>
My bot found errors running 'make dt_binding_check' on your patch:
yamllint warnings/errors:
dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.example.dtb: /: 'compatible' is a required property
from schema $id: http://devicetree.org/schemas/root-node.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.example.dtb: /: 'model' is a required property
from schema $id: http://devicetree.org/schemas/root-node.yaml#
doc reference errors (make refcheckdocs):
See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20250813042331.1258272-9-hans.zhang@cixtech.com
The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v7 08/13] dt-bindings: PCI: Add CIX Sky1 PCIe Root Complex bindings
2025-08-13 8:31 ` Rob Herring (Arm)
@ 2025-08-13 9:12 ` Hans Zhang
2025-08-13 15:43 ` Rob Herring
2025-08-13 19:08 ` Krzysztof Kozlowski
0 siblings, 2 replies; 40+ messages in thread
From: Hans Zhang @ 2025-08-13 9:12 UTC (permalink / raw)
To: Rob Herring (Arm)
Cc: mpillai, cix-kernel-upstream, lpieralisi, bhelgaas, devicetree,
conor+dt, linux-pci, mani, kw, kwilczynski, krzk+dt, fugang.duan,
guoyin.chen, peter.chen, linux-kernel
On 2025/8/13 16:31, Rob Herring (Arm) wrote:
> EXTERNAL EMAIL
>
> On Wed, 13 Aug 2025 12:23:26 +0800, hans.zhang@cixtech.com wrote:
>> From: Hans Zhang <hans.zhang@cixtech.com>
>>
>> Document the bindings for CIX Sky1 PCIe Controller configured in
>> root complex mode with five root port.
>>
>> Supports 4 INTx, MSI and MSI-x interrupts from the ARM GICv3 controller.
>>
>> Signed-off-by: Hans Zhang <hans.zhang@cixtech.com>
>> ---
>> .../bindings/pci/cix,sky1-pcie-host.yaml | 79 +++++++++++++++++++
>> 1 file changed, 79 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.yaml
>>
>
> My bot found errors running 'make dt_binding_check' on your patch:
>
> yamllint warnings/errors:
>
> dtschema/dtc warnings/errors:
> /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.example.dtb: /: 'compatible' is a required property
> from schema $id: http://devicetree.org/schemas/root-node.yaml#
> /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.example.dtb: /: 'model' is a required property
> from schema $id: http://devicetree.org/schemas/root-node.yaml#
>
> doc reference errors (make refcheckdocs):
>
> See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20250813042331.1258272-9-hans.zhang@cixtech.com
>
> The base for the series is generally the latest rc1. A different dependency
> should be noted in *this* patch.
>
> If you already ran 'make dt_binding_check' and didn't see the above
> error(s), then make sure 'yamllint' is installed and dt-schema is up to
> date:
>
> pip3 install dtschema --upgrade
>
> Please check and re-submit after running the above command yourself. Note
> that DT_SCHEMA_FILES can be set to your schema file to speed up checking
> your schema. However, it must be unset to test all examples with your schema.
>
Dear Rob,
I'm very sorry. No errors were detected on my PC. I'll check my local
environment and fix this issue in the next version.
If I have done anything wrong, please remind me.
hans@hans:~/code/kernel_org/linux$ export
CROSS_COMPILE=/home/hans/cix/bringup_master/tools/gcc/arm-gnu-toolchain-12.3.rel1-x86_64-aarch64-none-linux-gnu/arm-gnu-toolchain-12.3.rel1-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-
hans@hans:~/code/kernel_org/linux$ export ARCH=arm64
hans@hans:~/code/kernel_org/linux$ make dt_binding_check
DT_SCHEMA_FILES=Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.yaml
SCHEMA Documentation/devicetree/bindings/processed-schema.json
CHKDT ./Documentation/devicetree/bindings
LINT ./Documentation/devicetree/bindings
DTEX
Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.example.dts
DTC [C]
Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.example.dtb
hans@hans:~/code/kernel_org/linux$ make W=1 dt_binding_check
DT_SCHEMA_FILES=Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.yaml
hans@hans:~/code/kernel_org/linux$ pip3 install dtschema --upgrade
Defaulting to user installation because normal site-packages is not
writeable
Requirement already satisfied: dtschema in
/home/hans/.local/lib/python3.10/site-packages (2025.6.1)
Collecting dtschema
Downloading dtschema-2025.8-py3-none-any.whl.metadata (7.9 kB)
Requirement already satisfied: ruamel.yaml>0.15.69 in
/home/hans/.local/lib/python3.10/site-packages (from dtschema) (0.18.14)
Requirement already satisfied: jsonschema<4.18,>=4.1.2 in
/home/hans/.local/lib/python3.10/site-packages (from dtschema) (4.17.3)
Requirement already satisfied: rfc3987 in
/home/hans/.local/lib/python3.10/site-packages (from dtschema) (1.3.8)
Requirement already satisfied: pylibfdt in
/home/hans/.local/lib/python3.10/site-packages (from dtschema) (1.7.2.post1)
Requirement already satisfied: attrs>=17.4.0 in
/home/hans/.local/lib/python3.10/site-packages (from
jsonschema<4.18,>=4.1.2->dtschema) (25.3.0)
Requirement already satisfied:
pyrsistent!=0.17.0,!=0.17.1,!=0.17.2,>=0.14.0 in
/home/hans/.local/lib/python3.10/site-packages (from
jsonschema<4.18,>=4.1.2->dtschema) (0.20.0)
Requirement already satisfied: ruamel.yaml.clib>=0.2.7 in
/home/hans/.local/lib/python3.10/site-packages (from
ruamel.yaml>0.15.69->dtschema) (0.2.12)
Downloading dtschema-2025.8-py3-none-any.whl (120 kB)
Installing collected packages: dtschema
Attempting uninstall: dtschema
Found existing installation: dtschema 2025.6.1
Uninstalling dtschema-2025.6.1:
Successfully uninstalled dtschema-2025.6.1
Successfully installed dtschema-2025.8
[notice] A new release of pip is available: 25.1.1 -> 25.2
[notice] To update, run: python3 -m pip install --upgrade pip
hans@hans:~/code/kernel_org/linux$ make dt_binding_check
DT_SCHEMA_FILES=Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.yaml
hans@hans:~/code/kernel_org/linux$ make refcheckdocs
Documentation/userspace-api/netlink/netlink-raw.rst:
:doc:`rt-link<../../networking/netlink_spec/rt-link>`
Documentation/userspace-api/netlink/netlink-raw.rst:
:doc:`tc<../../networking/netlink_spec/tc>`
Documentation/userspace-api/netlink/netlink-raw.rst:
:doc:`tc<../../networking/netlink_spec/tc>`
Documentation/devicetree/bindings/regulator/siliconmitus,sm5703-regulator.yaml:
Documentation/devicetree/bindings/mfd/siliconmitus,sm5703.yaml
Documentation/devicetree/bindings/remoteproc/ti,keystone-rproc.txt:
Documentation/devicetree/bindings/gpio/gpio-dsp-keystone.txt
Documentation/hwmon/g762.rst:
Documentation/devicetree/bindings/hwmon/g762.txt
Documentation/trace/rv/da_monitor_instrumentation.rst:
Documentation/trace/rv/da_monitor_synthesis.rst
Documentation/translations/ja_JP/SubmittingPatches:
linux-2.6.12-vanilla/Documentation/dontdiff
Documentation/translations/ja_JP/process/submit-checklist.rst:
Documentation/translations/ja_JP/SubmitChecklist
Documentation/translations/zh_CN/admin-guide/README.rst:
Documentation/dev-tools/kgdb.rst
Documentation/translations/zh_CN/dev-tools/gdb-kernel-debugging.rst:
Documentation/dev-tools/gdb-kernel-debugging.rst
Documentation/translations/zh_CN/how-to.rst: Documentation/xxx/xxx.rst
Documentation/translations/zh_TW/admin-guide/README.rst:
Documentation/dev-tools/kgdb.rst
Documentation/translations/zh_TW/dev-tools/gdb-kernel-debugging.rst:
Documentation/dev-tools/gdb-kernel-debugging.rst
Documentation/userspace-api/netlink/index.rst:
Documentation/networking/netlink_spec/index.rst
Documentation/userspace-api/netlink/specs.rst:
Documentation/networking/netlink_spec/index.rst
arch/riscv/kernel/kexec_image.c: Documentation/riscv/boot-image-header.rst
drivers/clocksource/timer-armada-370-xp.c:
Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt
include/rv/da_monitor.h: Documentation/trace/rv/da_monitor_synthesis.rst
Best regards,
Hans
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v7 08/13] dt-bindings: PCI: Add CIX Sky1 PCIe Root Complex bindings
2025-08-13 9:12 ` Hans Zhang
@ 2025-08-13 15:43 ` Rob Herring
2025-08-14 1:22 ` Hans Zhang
2025-08-13 19:08 ` Krzysztof Kozlowski
1 sibling, 1 reply; 40+ messages in thread
From: Rob Herring @ 2025-08-13 15:43 UTC (permalink / raw)
To: Hans Zhang
Cc: mpillai, cix-kernel-upstream, lpieralisi, bhelgaas, devicetree,
conor+dt, linux-pci, mani, kw, kwilczynski, krzk+dt, fugang.duan,
guoyin.chen, peter.chen, linux-kernel
On Wed, Aug 13, 2025 at 05:12:57PM +0800, Hans Zhang wrote:
>
>
> On 2025/8/13 16:31, Rob Herring (Arm) wrote:
> > EXTERNAL EMAIL
> >
> > On Wed, 13 Aug 2025 12:23:26 +0800, hans.zhang@cixtech.com wrote:
> > > From: Hans Zhang <hans.zhang@cixtech.com>
> > >
> > > Document the bindings for CIX Sky1 PCIe Controller configured in
> > > root complex mode with five root port.
> > >
> > > Supports 4 INTx, MSI and MSI-x interrupts from the ARM GICv3 controller.
> > >
> > > Signed-off-by: Hans Zhang <hans.zhang@cixtech.com>
> > > ---
> > > .../bindings/pci/cix,sky1-pcie-host.yaml | 79 +++++++++++++++++++
> > > 1 file changed, 79 insertions(+)
> > > create mode 100644 Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.yaml
> > >
> >
> > My bot found errors running 'make dt_binding_check' on your patch:
> >
> > yamllint warnings/errors:
> >
> > dtschema/dtc warnings/errors:
> > /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.example.dtb: /: 'compatible' is a required property
> > from schema $id: http://devicetree.org/schemas/root-node.yaml#
> > /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.example.dtb: /: 'model' is a required property
> > from schema $id: http://devicetree.org/schemas/root-node.yaml#
> >
> > doc reference errors (make refcheckdocs):
> >
> > See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20250813042331.1258272-9-hans.zhang@cixtech.com
> >
> > The base for the series is generally the latest rc1. A different dependency
> > should be noted in *this* patch.
> >
> > If you already ran 'make dt_binding_check' and didn't see the above
> > error(s), then make sure 'yamllint' is installed and dt-schema is up to
> > date:
> >
> > pip3 install dtschema --upgrade
> >
> > Please check and re-submit after running the above command yourself. Note
> > that DT_SCHEMA_FILES can be set to your schema file to speed up checking
> > your schema. However, it must be unset to test all examples with your schema.
> >
>
> Dear Rob,
>
> I'm very sorry. No errors were detected on my PC. I'll check my local
> environment and fix this issue in the next version.
>
> If I have done anything wrong, please remind me.
>
>
>
> hans@hans:~/code/kernel_org/linux$ export CROSS_COMPILE=/home/hans/cix/bringup_master/tools/gcc/arm-gnu-toolchain-12.3.rel1-x86_64-aarch64-none-linux-gnu/arm-gnu-toolchain-12.3.rel1-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-
> hans@hans:~/code/kernel_org/linux$ export ARCH=arm64
> hans@hans:~/code/kernel_org/linux$ make dt_binding_check
> DT_SCHEMA_FILES=Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.yaml
> SCHEMA Documentation/devicetree/bindings/processed-schema.json
> CHKDT ./Documentation/devicetree/bindings
> LINT ./Documentation/devicetree/bindings
> DTEX Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.example.dts
> DTC [C]
> Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.example.dtb
> hans@hans:~/code/kernel_org/linux$ make W=1 dt_binding_check
> DT_SCHEMA_FILES=Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.yaml
DT_SCHEMA_FILES limits testing to only the matching pattern.
Ultimately, you have to test without it.
Rob
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v7 08/13] dt-bindings: PCI: Add CIX Sky1 PCIe Root Complex bindings
2025-08-13 4:23 ` [PATCH v7 08/13] dt-bindings: PCI: Add CIX Sky1 PCIe Root Complex bindings hans.zhang
2025-08-13 8:31 ` Rob Herring (Arm)
@ 2025-08-13 15:44 ` Rob Herring
2025-08-14 1:23 ` Hans Zhang
1 sibling, 1 reply; 40+ messages in thread
From: Rob Herring @ 2025-08-13 15:44 UTC (permalink / raw)
To: hans.zhang
Cc: bhelgaas, lpieralisi, kw, mani, kwilczynski, krzk+dt, conor+dt,
mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel
On Wed, Aug 13, 2025 at 12:23:26PM +0800, hans.zhang@cixtech.com wrote:
> From: Hans Zhang <hans.zhang@cixtech.com>
>
> Document the bindings for CIX Sky1 PCIe Controller configured in
> root complex mode with five root port.
>
> Supports 4 INTx, MSI and MSI-x interrupts from the ARM GICv3 controller.
>
> Signed-off-by: Hans Zhang <hans.zhang@cixtech.com>
> ---
> .../bindings/pci/cix,sky1-pcie-host.yaml | 79 +++++++++++++++++++
> 1 file changed, 79 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.yaml
>
> diff --git a/Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.yaml b/Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.yaml
> new file mode 100644
> index 000000000000..2bd66603ac24
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.yaml
> @@ -0,0 +1,79 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/pci/cix,sky1-pcie-host.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: CIX Sky1 PCIe Root Complex
> +
> +maintainers:
> + - Hans Zhang <hans.zhang@cixtech.com>
> +
> +description:
> + PCIe root complex controller based on the Cadence PCIe core.
> +
> +allOf:
> + - $ref: /schemas/pci/pci-host-bridge.yaml#
> +
> +properties:
> + compatible:
> + const: cix,sky1-pcie-host
> +
> + reg:
> + items:
> + - description: PCIe controller registers.
> + - description: ECAM registers.
> + - description: Remote CIX System Unit registers.
> + - description: Region for sending messages registers.
> +
> + reg-names:
> + items:
> + - const: reg
> + - const: cfg
> + - const: rcsu
> + - const: msg
> +
> + ranges:
> + maxItems: 3
> +
> +required:
> + - compatible
> + - ranges
> + - bus-range
> + - device_type
> + - interrupt-map
> + - interrupt-map-mask
> + - msi-map
> +
> +unevaluatedProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/interrupt-controller/arm-gic.h>
> + / {
bus {
> + #address-cells = <2>;
> + #size-cells = <2>;
> +
> + pcie@a010000 {
> + compatible = "cix,sky1-pcie-host";
> + reg = <0x00 0x0a010000 0x00 0x10000>,
> + <0x00 0x2c000000 0x00 0x4000000>,
> + <0x00 0x0a000000 0x00 0x10000>,
> + <0x00 0x60000000 0x00 0x00100000>;
> + reg-names = "reg", "cfg", "rcsu", "msg";
> + ranges = <0x01000000 0x00 0x60100000 0x00 0x60100000 0x00 0x00100000>,
> + <0x02000000 0x00 0x60200000 0x00 0x60200000 0x00 0x1fe00000>,
> + <0x43000000 0x18 0x00000000 0x18 0x00000000 0x04 0x00000000>;
> + #address-cells = <3>;
> + #size-cells = <2>;
> + bus-range = <0xc0 0xff>;
> + device_type = "pci";
> + #interrupt-cells = <1>;
> + interrupt-map-mask = <0 0 0 0x7>;
> + interrupt-map = <0 0 0 1 &gic 0 0 GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH 0>,
> + <0 0 0 2 &gic 0 0 GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH 0>,
> + <0 0 0 3 &gic 0 0 GIC_SPI 409 IRQ_TYPE_LEVEL_HIGH 0>,
> + <0 0 0 4 &gic 0 0 GIC_SPI 410 IRQ_TYPE_LEVEL_HIGH 0>;
> + msi-map = <0xc000 &gic_its 0xc000 0x4000>;
> + };
> + };
> --
> 2.49.0
>
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v7 08/13] dt-bindings: PCI: Add CIX Sky1 PCIe Root Complex bindings
2025-08-13 9:12 ` Hans Zhang
2025-08-13 15:43 ` Rob Herring
@ 2025-08-13 19:08 ` Krzysztof Kozlowski
2025-08-14 1:26 ` Hans Zhang
1 sibling, 1 reply; 40+ messages in thread
From: Krzysztof Kozlowski @ 2025-08-13 19:08 UTC (permalink / raw)
To: Hans Zhang, Rob Herring (Arm)
Cc: mpillai, cix-kernel-upstream, lpieralisi, bhelgaas, devicetree,
conor+dt, linux-pci, mani, kw, kwilczynski, krzk+dt, fugang.duan,
guoyin.chen, peter.chen, linux-kernel
On 13/08/2025 11:12, Hans Zhang wrote:
>
>
> On 2025/8/13 16:31, Rob Herring (Arm) wrote:
>> EXTERNAL EMAIL
>>
>> On Wed, 13 Aug 2025 12:23:26 +0800, hans.zhang@cixtech.com wrote:
>>> From: Hans Zhang <hans.zhang@cixtech.com>
>>>
>>> Document the bindings for CIX Sky1 PCIe Controller configured in
>>> root complex mode with five root port.
>>>
>>> Supports 4 INTx, MSI and MSI-x interrupts from the ARM GICv3 controller.
>>>
>>> Signed-off-by: Hans Zhang <hans.zhang@cixtech.com>
>>> ---
>>> .../bindings/pci/cix,sky1-pcie-host.yaml | 79 +++++++++++++++++++
>>> 1 file changed, 79 insertions(+)
>>> create mode 100644 Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.yaml
>>>
>>
>> My bot found errors running 'make dt_binding_check' on your patch:
>>
>> yamllint warnings/errors:
>>
>> dtschema/dtc warnings/errors:
>> /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.example.dtb: /: 'compatible' is a required property
>> from schema $id: http://devicetree.org/schemas/root-node.yaml#
>> /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.example.dtb: /: 'model' is a required property
>> from schema $id: http://devicetree.org/schemas/root-node.yaml#
>>
>> doc reference errors (make refcheckdocs):
>>
>> See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20250813042331.1258272-9-hans.zhang@cixtech.com
>>
>> The base for the series is generally the latest rc1. A different dependency
>> should be noted in *this* patch.
>>
>> If you already ran 'make dt_binding_check' and didn't see the above
>> error(s), then make sure 'yamllint' is installed and dt-schema is up to
>> date:
>>
>> pip3 install dtschema --upgrade
>>
>> Please check and re-submit after running the above command yourself. Note
>> that DT_SCHEMA_FILES can be set to your schema file to speed up checking
>> your schema. However, it must be unset to test all examples with your schema.
>>
>
> Dear Rob,
>
> I'm very sorry. No errors were detected on my PC. I'll check my local
> environment and fix this issue in the next version.
>
> If I have done anything wrong, please remind me.
Your code is not correct. You are not supposed to have there root node.
Please open ANY (most recent preferably) other binding and look how it
is done there.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v7 00/13] Enhance the PCIe controller driver for next generation controllers
2025-08-13 4:23 [PATCH v7 00/13] Enhance the PCIe controller driver for next generation controllers hans.zhang
` (12 preceding siblings ...)
2025-08-13 4:23 ` [PATCH v7 13/13] arm64: dts: cix: Enable PCIe on the Orion O6 board hans.zhang
@ 2025-08-13 19:14 ` Krzysztof Kozlowski
2025-08-14 1:37 ` Hans Zhang
13 siblings, 1 reply; 40+ messages in thread
From: Krzysztof Kozlowski @ 2025-08-13 19:14 UTC (permalink / raw)
To: hans.zhang, bhelgaas, lpieralisi, kw, mani, robh, kwilczynski,
krzk+dt, conor+dt
Cc: mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel
On 13/08/2025 06:23, hans.zhang@cixtech.com wrote:
> From: Hans Zhang <hans.zhang@cixtech.com>
>
> ---
> Dear Maintainers,
>
> This series is Cadence's HPA PCIe IP and the Root Port driver of our
> CIX sky1. Please help review. Thank you very much.
> ---
>
> Enhances the exiting Cadence PCIe controller drivers to support
> HPA (High Performance Architecture) Cadence PCIe controllers.
>
> The patch set enhances the Cadence PCIe driver for HPA support.
> The header files are separated out for legacy and high performance
> register maps, register address and bit definitions. The driver
> read register and write register functions for HPA take the
> updated offset stored from the platform driver to access the registers.
> As part of refactoring of the code, few new files are added to the
> driver by splitting the existing files.
> This helps SoC vendor who change the address map within PCIe controller
> in their designs. Setting the menuconfig appropriately will allow
> selection between RP and/or EP PCIe controller support. The support
> will include Legacy and HPA for the selected configuration.
>
> The TI SoC continues to be supported with the changes incorporated.
>
> The changes address the review comments in the previous patches where
> the need to move away from "ops" pointers used in current implementation
> and separate out the Legacy and HPA driver implementation was stressed.
>
> The scripts/checkpatch.pl has been run on the patches with and without
> --strict. With the --strict option, 4 checks are generated on 2 patch,
> which can be ignored. There are no code fixes required for these checks.
> All other checks generated by ./scripts/checkpatch.pl --strict can be
> ignored.
>
> ---
> Changes for v7
> - Rebase to v6.17-rc1.
> - Fixed the error issue of cix,sky1-pcie-host.yaml make dt_binding_check.
> - CIX SKY1 Root Port driver compilation error issue: Add header
> file, Kconfig select PCI_ECAM.
>
Where are lore links to all previous versions?
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v7 10/13] PCI: sky1: Add PCIe host support for CIX Sky1
2025-08-13 4:23 ` [PATCH v7 10/13] PCI: sky1: Add PCIe host support for CIX Sky1 hans.zhang
@ 2025-08-13 19:16 ` Krzysztof Kozlowski
2025-08-14 1:29 ` Hans Zhang
2025-08-14 22:46 ` Bjorn Helgaas
1 sibling, 1 reply; 40+ messages in thread
From: Krzysztof Kozlowski @ 2025-08-13 19:16 UTC (permalink / raw)
To: hans.zhang, bhelgaas, lpieralisi, kw, mani, robh, kwilczynski,
krzk+dt, conor+dt
Cc: mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel
On 13/08/2025 06:23, hans.zhang@cixtech.com wrote:
> +static int sky1_pcie_parse_mem(struct sky1_pcie *pcie)
> +{
> + struct device *dev = pcie->dev;
> + struct platform_device *pdev = to_platform_device(dev);
> + struct resource *res;
> + void __iomem *base;
> + int ret = 0;
> +
> + base = devm_platform_ioremap_resource_byname(pdev, "reg");
> + if (IS_ERR(base)) {
> + dev_err(dev, "Parse \"reg\" resource err\n");
Syntax is return dev_err_probe, and without \" so grepping works
correctly (see coding style).
> + return PTR_ERR(base);
> + }
> + pcie->reg_base = base;
> +
> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
> + if (!res) {
> + dev_err(dev, "Parse \"cfg\" resource err\n");
> + return -ENXIO;
> + }
> + pcie->cfg_res = res;
> +
> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rcsu");
> + if (!res) {
> + dev_err(dev, "Parse \"rcsu\" resource err\n");
> + return -ENXIO;
> + }
> + pcie->rcsu_base = devm_ioremap(dev, res->start, resource_size(res));
Why aren't you using wrapper over get_resource and ioremap? Isn't
devm_platform_ioremap_resource_byname exactly what you want?
And if argument from previous versions was - you need to backport it for
ancient 3.10 kernel - then it would be a no go.
> + if (!pcie->rcsu_base) {
> + dev_err(dev, "ioremap failed for resource %pR\n", res);
> + return -ENOMEM;
> + }
> +
> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "msg");
> + if (!res) {
> + dev_err(dev, "Parse \"msg\" resource err\n");
> + return -ENXIO;
> + }
> + pcie->msg_res = res;
> + pcie->msg_base = devm_ioremap(dev, res->start, resource_size(res));
> + if (!pcie->msg_base) {
> + dev_err(dev, "ioremap failed for resource %pR\n", res);
> + return -ENOMEM;
> + }
> +
> + return ret;
> +}
> +
> +static int sky1_pcie_parse_property(struct platform_device *pdev,
> + struct sky1_pcie *pcie)
> +{
> + int ret = 0;
> +
> + ret = sky1_pcie_parse_mem(pcie);
> + if (ret < 0)
> + return ret;
> +
> + sky1_pcie_init_bases(pcie);
> +
> + return ret;
> +}
> +
> +static int sky1_pcie_start_link(struct cdns_pcie *cdns_pcie)
> +{
> + struct sky1_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
> +
> + sky1_pcie_clear_and_set_dword(pcie->strap_base + STRAP_REG(1),
> + 0, LINK_TRAINING_ENABLE);
> +
> + return 0;
> +}
> +
> +static void sky1_pcie_stop_link(struct cdns_pcie *cdns_pcie)
> +{
> + struct sky1_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
> +
> + sky1_pcie_clear_and_set_dword(pcie->strap_base + STRAP_REG(1),
> + LINK_TRAINING_ENABLE, 0);
> +}
> +
> +
> +static bool sky1_pcie_link_up(struct cdns_pcie *cdns_pcie)
> +{
> + u32 val;
> +
> + val = cdns_pcie_hpa_readl(cdns_pcie, REG_BANK_IP_REG,
> + IP_REG_I_DBG_STS_0);
> + return val & LINK_COMPLETE;
> +}
> +
> +static const struct cdns_pcie_ops sky1_pcie_ops = {
> + .start_link = sky1_pcie_start_link,
> + .stop_link = sky1_pcie_stop_link,
> + .link_up = sky1_pcie_link_up,
> +};
> +
> +static int sky1_pcie_probe(struct platform_device *pdev)
> +{
> + const struct sky1_pcie_data *data;
> + struct device *dev = &pdev->dev;
> + struct pci_host_bridge *bridge;
> + struct cdns_pcie *cdns_pcie;
> + struct resource_entry *bus;
> + struct cdns_pcie_rc *rc;
> + struct sky1_pcie *pcie;
> + int ret;
> +
> + pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
> + if (!pcie)
> + return -ENOMEM;
> +
> + data = of_device_get_match_data(dev);
> + if (!data)
> + return -EINVAL;
> +
> + pcie->data = data;
> + pcie->dev = dev;
> + dev_set_drvdata(dev, pcie);
> +
> + bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
> + if (!bridge)
> + return -ENOMEM;
> +
> + bus = resource_list_first_type(&bridge->windows, IORESOURCE_BUS);
> + if (!bus)
> + return -ENODEV;
> +
> + ret = sky1_pcie_parse_property(pdev, pcie);
> + if (ret < 0)
> + return -ENXIO;
> +
> + pcie->cfg = pci_ecam_create(dev, pcie->cfg_res, bus->res,
> + &pci_generic_ecam_ops);
> + if (IS_ERR(pcie->cfg))
> + return PTR_ERR(pcie->cfg);
> +
> + bridge->ops = (struct pci_ops *)&pci_generic_ecam_ops.pci_ops;
> + rc = pci_host_bridge_priv(bridge);
> + rc->ecam_support_flag = 1;
> + rc->cfg_base = pcie->cfg->win;
> + rc->cfg_res = &pcie->cfg->res;
> +
> + cdns_pcie = &rc->pcie;
> + cdns_pcie->dev = dev;
> + cdns_pcie->ops = &sky1_pcie_ops;
> + cdns_pcie->reg_base = pcie->reg_base;
> + cdns_pcie->msg_res = pcie->msg_res;
> + cdns_pcie->cdns_pcie_reg_offsets = &data->reg_off;
> + cdns_pcie->is_rc = data->reg_off.is_rc;
> +
> + pcie->cdns_pcie = cdns_pcie;
> + pcie->cdns_pcie_rc = rc;
> + pcie->cfg_base = rc->cfg_base;
> + bridge->sysdata = pcie->cfg;
> +
> + if (data->soc_type == CIX_SKY1) {
Dead code or rather if (true) code. Don't do it, it's more difficult to
read.
> + rc->vendor_id = PCI_VENDOR_ID_CIX;
> + rc->device_id = PCI_DEVICE_ID_CIX_SKY1;
> + rc->no_inbound_flag = 1;
> + }
> +
> + ret = cdns_pcie_hpa_host_setup(rc);
> + if (ret < 0) {
> + pci_ecam_free(pcie->cfg);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static const struct sky1_pcie_data sky1_pcie_rc_data = {
> + .reg_off = {
> + .is_rc = true,
> + .ip_reg_bank_offset = SKY1_IP_REG_BANK_OFFSET,
> + .ip_cfg_ctrl_reg_offset = SKY1_IP_CFG_CTRL_REG_BANK_OFFSET,
> + .axi_mstr_common_offset = SKY1_IP_AXI_MASTER_COMMON_OFFSET,
> + .axi_slave_offset = SKY1_AXI_SLAVE_OFFSET,
> + .axi_master_offset = SKY1_AXI_MASTER_OFFSET,
> + .axi_hls_offset = SKY1_AXI_HLS_REGISTERS_OFFSET,
> + .axi_ras_offset = SKY1_AXI_RAS_REGISTERS_OFFSET,
> + .axi_dti_offset = SKY1_DTI_REGISTERS_OFFSET,
> + },
> + .soc_type = CIX_SKY1,
You have only one device variant, so this entire pcie_data feels redundant.
> +};
> +
> +static const struct of_device_id of_sky1_pcie_match[] = {
> + {
> + .compatible = "cix,sky1-pcie-host",
> + .data = &sky1_pcie_rc_data,
> + },
> + {},
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v7 03/13] PCI: cadence: Add register definitions for HPA(High Perf Architecture)
2025-08-13 4:23 ` [PATCH v7 03/13] PCI: cadence: Add register definitions for HPA(High Perf Architecture) hans.zhang
@ 2025-08-13 19:17 ` Krzysztof Kozlowski
2025-08-14 1:29 ` Manikandan Karunakaran Pillai
2025-08-14 21:35 ` Bjorn Helgaas
1 sibling, 1 reply; 40+ messages in thread
From: Krzysztof Kozlowski @ 2025-08-13 19:17 UTC (permalink / raw)
To: hans.zhang, bhelgaas, lpieralisi, kw, mani, robh, kwilczynski,
krzk+dt, conor+dt
Cc: mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel
On 13/08/2025 06:23, hans.zhang@cixtech.com wrote:
> static inline u32 cdns_pcie_read_sz(void __iomem *addr, int size)
> {
> void __iomem *aligned_addr = PTR_ALIGN_DOWN(addr, 0x4);
> @@ -313,19 +410,17 @@ static inline void cdns_pcie_ep_disable(struct cdns_pcie_ep *ep)
> #endif
>
> void cdns_pcie_detect_quiet_min_delay_set(struct cdns_pcie *pcie);
> -
> void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 busnr, u8 fn,
> u32 r, bool is_io,
> u64 cpu_addr, u64 pci_addr, size_t size);
> -
> void cdns_pcie_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie,
> u8 busnr, u8 fn,
> u32 r, u64 cpu_addr);
> -
> 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);
> +int cdns_pcie_enable_phy(struct cdns_pcie *pcie);
> +int cdns_pcie_init_phy(struct device *dev, struct cdns_pcie *pcie);
I don't understand how this (and many other pieces here) is related to
"add register definitions".
This is not a register definition.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v7 08/13] dt-bindings: PCI: Add CIX Sky1 PCIe Root Complex bindings
2025-08-13 15:43 ` Rob Herring
@ 2025-08-14 1:22 ` Hans Zhang
0 siblings, 0 replies; 40+ messages in thread
From: Hans Zhang @ 2025-08-14 1:22 UTC (permalink / raw)
To: Rob Herring
Cc: mpillai, cix-kernel-upstream, lpieralisi, bhelgaas, devicetree,
conor+dt, linux-pci, mani, kw, kwilczynski, krzk+dt, fugang.duan,
guoyin.chen, peter.chen, linux-kernel
On 2025/8/13 23:43, Rob Herring wrote:
> EXTERNAL EMAIL
>
> On Wed, Aug 13, 2025 at 05:12:57PM +0800, Hans Zhang wrote:
>>
>>
>> On 2025/8/13 16:31, Rob Herring (Arm) wrote:
>>> EXTERNAL EMAIL
>>>
>>> On Wed, 13 Aug 2025 12:23:26 +0800, hans.zhang@cixtech.com wrote:
>>>> From: Hans Zhang <hans.zhang@cixtech.com>
>>>>
>>>> Document the bindings for CIX Sky1 PCIe Controller configured in
>>>> root complex mode with five root port.
>>>>
>>>> Supports 4 INTx, MSI and MSI-x interrupts from the ARM GICv3 controller.
>>>>
>>>> Signed-off-by: Hans Zhang <hans.zhang@cixtech.com>
>>>> ---
>>>> .../bindings/pci/cix,sky1-pcie-host.yaml | 79 +++++++++++++++++++
>>>> 1 file changed, 79 insertions(+)
>>>> create mode 100644 Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.yaml
>>>>
>>>
>>> My bot found errors running 'make dt_binding_check' on your patch:
>>>
>>> yamllint warnings/errors:
>>>
>>> dtschema/dtc warnings/errors:
>>> /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.example.dtb: /: 'compatible' is a required property
>>> from schema $id: http://devicetree.org/schemas/root-node.yaml#
>>> /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.example.dtb: /: 'model' is a required property
>>> from schema $id: http://devicetree.org/schemas/root-node.yaml#
>>>
>>> doc reference errors (make refcheckdocs):
>>>
>>> See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20250813042331.1258272-9-hans.zhang@cixtech.com
>>>
>>> The base for the series is generally the latest rc1. A different dependency
>>> should be noted in *this* patch.
>>>
>>> If you already ran 'make dt_binding_check' and didn't see the above
>>> error(s), then make sure 'yamllint' is installed and dt-schema is up to
>>> date:
>>>
>>> pip3 install dtschema --upgrade
>>>
>>> Please check and re-submit after running the above command yourself. Note
>>> that DT_SCHEMA_FILES can be set to your schema file to speed up checking
>>> your schema. However, it must be unset to test all examples with your schema.
>>>
>>
>> Dear Rob,
>>
>> I'm very sorry. No errors were detected on my PC. I'll check my local
>> environment and fix this issue in the next version.
>>
>> If I have done anything wrong, please remind me.
>>
>>
>>
>> hans@hans:~/code/kernel_org/linux$ export CROSS_COMPILE=/home/hans/cix/bringup_master/tools/gcc/arm-gnu-toolchain-12.3.rel1-x86_64-aarch64-none-linux-gnu/arm-gnu-toolchain-12.3.rel1-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-
>> hans@hans:~/code/kernel_org/linux$ export ARCH=arm64
>> hans@hans:~/code/kernel_org/linux$ make dt_binding_check
>> DT_SCHEMA_FILES=Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.yaml
>> SCHEMA Documentation/devicetree/bindings/processed-schema.json
>> CHKDT ./Documentation/devicetree/bindings
>> LINT ./Documentation/devicetree/bindings
>> DTEX Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.example.dts
>> DTC [C]
>> Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.example.dtb
>> hans@hans:~/code/kernel_org/linux$ make W=1 dt_binding_check
>> DT_SCHEMA_FILES=Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.yaml
>
> DT_SCHEMA_FILES limits testing to only the matching pattern.
> Ultimately, you have to test without it.
>
Dear Rob,
Thank you very much for your reply and reminder. I will check it
carefully again.
Best regards,
Hans
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v7 08/13] dt-bindings: PCI: Add CIX Sky1 PCIe Root Complex bindings
2025-08-13 15:44 ` Rob Herring
@ 2025-08-14 1:23 ` Hans Zhang
0 siblings, 0 replies; 40+ messages in thread
From: Hans Zhang @ 2025-08-14 1:23 UTC (permalink / raw)
To: Rob Herring
Cc: bhelgaas, lpieralisi, kw, mani, kwilczynski, krzk+dt, conor+dt,
mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel
On 2025/8/13 23:44, Rob Herring wrote:
> EXTERNAL EMAIL
>
> On Wed, Aug 13, 2025 at 12:23:26PM +0800, hans.zhang@cixtech.com wrote:
>> From: Hans Zhang <hans.zhang@cixtech.com>
>>
>> Document the bindings for CIX Sky1 PCIe Controller configured in
>> root complex mode with five root port.
>>
>> Supports 4 INTx, MSI and MSI-x interrupts from the ARM GICv3 controller.
>>
>> Signed-off-by: Hans Zhang <hans.zhang@cixtech.com>
>> ---
>> .../bindings/pci/cix,sky1-pcie-host.yaml | 79 +++++++++++++++++++
>> 1 file changed, 79 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.yaml b/Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.yaml
>> new file mode 100644
>> index 000000000000..2bd66603ac24
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.yaml
>> @@ -0,0 +1,79 @@
>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/pci/cix,sky1-pcie-host.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: CIX Sky1 PCIe Root Complex
>> +
>> +maintainers:
>> + - Hans Zhang <hans.zhang@cixtech.com>
>> +
>> +description:
>> + PCIe root complex controller based on the Cadence PCIe core.
>> +
>> +allOf:
>> + - $ref: /schemas/pci/pci-host-bridge.yaml#
>> +
>> +properties:
>> + compatible:
>> + const: cix,sky1-pcie-host
>> +
>> + reg:
>> + items:
>> + - description: PCIe controller registers.
>> + - description: ECAM registers.
>> + - description: Remote CIX System Unit registers.
>> + - description: Region for sending messages registers.
>> +
>> + reg-names:
>> + items:
>> + - const: reg
>> + - const: cfg
>> + - const: rcsu
>> + - const: msg
>> +
>> + ranges:
>> + maxItems: 3
>> +
>> +required:
>> + - compatible
>> + - ranges
>> + - bus-range
>> + - device_type
>> + - interrupt-map
>> + - interrupt-map-mask
>> + - msi-map
>> +
>> +unevaluatedProperties: false
>> +
>> +examples:
>> + - |
>> + #include <dt-bindings/interrupt-controller/arm-gic.h>
>> + / {
>
> bus {
Dear Rob,
Thank you very much for your reply. I'll refer to other recent submissions.
Best regards,
Hans
>
>> + #address-cells = <2>;
>> + #size-cells = <2>;
>> +
>> + pcie@a010000 {
>> + compatible = "cix,sky1-pcie-host";
>> + reg = <0x00 0x0a010000 0x00 0x10000>,
>> + <0x00 0x2c000000 0x00 0x4000000>,
>> + <0x00 0x0a000000 0x00 0x10000>,
>> + <0x00 0x60000000 0x00 0x00100000>;
>> + reg-names = "reg", "cfg", "rcsu", "msg";
>> + ranges = <0x01000000 0x00 0x60100000 0x00 0x60100000 0x00 0x00100000>,
>> + <0x02000000 0x00 0x60200000 0x00 0x60200000 0x00 0x1fe00000>,
>> + <0x43000000 0x18 0x00000000 0x18 0x00000000 0x04 0x00000000>;
>> + #address-cells = <3>;
>> + #size-cells = <2>;
>> + bus-range = <0xc0 0xff>;
>> + device_type = "pci";
>> + #interrupt-cells = <1>;
>> + interrupt-map-mask = <0 0 0 0x7>;
>> + interrupt-map = <0 0 0 1 &gic 0 0 GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH 0>,
>> + <0 0 0 2 &gic 0 0 GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH 0>,
>> + <0 0 0 3 &gic 0 0 GIC_SPI 409 IRQ_TYPE_LEVEL_HIGH 0>,
>> + <0 0 0 4 &gic 0 0 GIC_SPI 410 IRQ_TYPE_LEVEL_HIGH 0>;
>> + msi-map = <0xc000 &gic_its 0xc000 0x4000>;
>> + };
>> + };
>> --
>> 2.49.0
>>
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v7 08/13] dt-bindings: PCI: Add CIX Sky1 PCIe Root Complex bindings
2025-08-13 19:08 ` Krzysztof Kozlowski
@ 2025-08-14 1:26 ` Hans Zhang
0 siblings, 0 replies; 40+ messages in thread
From: Hans Zhang @ 2025-08-14 1:26 UTC (permalink / raw)
To: Krzysztof Kozlowski, Rob Herring (Arm)
Cc: mpillai, cix-kernel-upstream, lpieralisi, bhelgaas, devicetree,
conor+dt, linux-pci, mani, kw, kwilczynski, krzk+dt, fugang.duan,
guoyin.chen, peter.chen, linux-kernel
On 2025/8/14 03:08, Krzysztof Kozlowski wrote:
> EXTERNAL EMAIL
>
> On 13/08/2025 11:12, Hans Zhang wrote:
>>
>>
>> On 2025/8/13 16:31, Rob Herring (Arm) wrote:
>>> EXTERNAL EMAIL
>>>
>>> On Wed, 13 Aug 2025 12:23:26 +0800, hans.zhang@cixtech.com wrote:
>>>> From: Hans Zhang <hans.zhang@cixtech.com>
>>>>
>>>> Document the bindings for CIX Sky1 PCIe Controller configured in
>>>> root complex mode with five root port.
>>>>
>>>> Supports 4 INTx, MSI and MSI-x interrupts from the ARM GICv3 controller.
>>>>
>>>> Signed-off-by: Hans Zhang <hans.zhang@cixtech.com>
>>>> ---
>>>> .../bindings/pci/cix,sky1-pcie-host.yaml | 79 +++++++++++++++++++
>>>> 1 file changed, 79 insertions(+)
>>>> create mode 100644 Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.yaml
>>>>
>>>
>>> My bot found errors running 'make dt_binding_check' on your patch:
>>>
>>> yamllint warnings/errors:
>>>
>>> dtschema/dtc warnings/errors:
>>> /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.example.dtb: /: 'compatible' is a required property
>>> from schema $id: http://devicetree.org/schemas/root-node.yaml#
>>> /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/pci/cix,sky1-pcie-host.example.dtb: /: 'model' is a required property
>>> from schema $id: http://devicetree.org/schemas/root-node.yaml#
>>>
>>> doc reference errors (make refcheckdocs):
>>>
>>> See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20250813042331.1258272-9-hans.zhang@cixtech.com
>>>
>>> The base for the series is generally the latest rc1. A different dependency
>>> should be noted in *this* patch.
>>>
>>> If you already ran 'make dt_binding_check' and didn't see the above
>>> error(s), then make sure 'yamllint' is installed and dt-schema is up to
>>> date:
>>>
>>> pip3 install dtschema --upgrade
>>>
>>> Please check and re-submit after running the above command yourself. Note
>>> that DT_SCHEMA_FILES can be set to your schema file to speed up checking
>>> your schema. However, it must be unset to test all examples with your schema.
>>>
>>
>> Dear Rob,
>>
>> I'm very sorry. No errors were detected on my PC. I'll check my local
>> environment and fix this issue in the next version.
>>
>> If I have done anything wrong, please remind me.
>
> Your code is not correct. You are not supposed to have there root node.
> Please open ANY (most recent preferably) other binding and look how it
> is done there.
>
Dear Krzysztof,
Thank you very much for your reply.
I found a recent reference example, which will be fixed in the next version.
Documentation/devicetree/bindings/pci/sophgo,sg2044-pcie.yaml
Best regards,
Hans
^ permalink raw reply [flat|nested] 40+ messages in thread
* RE: [PATCH v7 03/13] PCI: cadence: Add register definitions for HPA(High Perf Architecture)
2025-08-13 19:17 ` Krzysztof Kozlowski
@ 2025-08-14 1:29 ` Manikandan Karunakaran Pillai
0 siblings, 0 replies; 40+ messages in thread
From: Manikandan Karunakaran Pillai @ 2025-08-14 1:29 UTC (permalink / raw)
To: Krzysztof Kozlowski, hans.zhang@cixtech.com, bhelgaas@google.com,
lpieralisi@kernel.org, kw@linux.com, mani@kernel.org,
robh@kernel.org, kwilczynski@kernel.org, krzk+dt@kernel.org,
conor+dt@kernel.org
Cc: fugang.duan@cixtech.com, guoyin.chen@cixtech.com,
peter.chen@cixtech.com, cix-kernel-upstream@cixtech.com,
linux-pci@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org
>On 13/08/2025 06:23, hans.zhang@cixtech.com wrote:
>> static inline u32 cdns_pcie_read_sz(void __iomem *addr, int size)
>> {
>> void __iomem *aligned_addr = PTR_ALIGN_DOWN(addr, 0x4);
>> @@ -313,19 +410,17 @@ static inline void cdns_pcie_ep_disable(struct
>cdns_pcie_ep *ep)
>> #endif
>>
>> void cdns_pcie_detect_quiet_min_delay_set(struct cdns_pcie *pcie);
>> -
>> void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 busnr, u8
>fn,
>> u32 r, bool is_io,
>> u64 cpu_addr, u64 pci_addr, size_t size);
>> -
>> void cdns_pcie_set_outbound_region_for_normal_msg(struct cdns_pcie
>*pcie,
>> u8 busnr, u8 fn,
>> u32 r, u64 cpu_addr);
>> -
>> 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);
>> +int cdns_pcie_enable_phy(struct cdns_pcie *pcie);
>> +int cdns_pcie_init_phy(struct device *dev, struct cdns_pcie *pcie);
>
>I don't understand how this (and many other pieces here) is related to
>"add register definitions".
>
>This is not a register definition.
>
>
This is just an indentation change to make it aligned with the other functions definitions. However, for the other changes that
you are mentioning which are not register definitions, there was some movement of code when new files were created wherein function definitions/structure definitions/enums were relocated. I will update the description to reflect these.
>
>Best regards,
>Krzysztof
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v7 10/13] PCI: sky1: Add PCIe host support for CIX Sky1
2025-08-13 19:16 ` Krzysztof Kozlowski
@ 2025-08-14 1:29 ` Hans Zhang
0 siblings, 0 replies; 40+ messages in thread
From: Hans Zhang @ 2025-08-14 1:29 UTC (permalink / raw)
To: Krzysztof Kozlowski, bhelgaas, lpieralisi, kw, mani, robh,
kwilczynski, krzk+dt, conor+dt
Cc: mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel
On 2025/8/14 03:16, Krzysztof Kozlowski wrote:
> EXTERNAL EMAIL
>
> On 13/08/2025 06:23, hans.zhang@cixtech.com wrote:
>> +static int sky1_pcie_parse_mem(struct sky1_pcie *pcie)
>> +{
>> + struct device *dev = pcie->dev;
>> + struct platform_device *pdev = to_platform_device(dev);
>> + struct resource *res;
>> + void __iomem *base;
>> + int ret = 0;
>> +
>> + base = devm_platform_ioremap_resource_byname(pdev, "reg");
>> + if (IS_ERR(base)) {
>> + dev_err(dev, "Parse \"reg\" resource err\n");
>
> Syntax is return dev_err_probe, and without \" so grepping works
> correctly (see coding style).
Dear Krzysztof,
Thank you very much for your reply. Will change.
>
>> + return PTR_ERR(base);
>> + }
>> + pcie->reg_base = base;
>> +
>> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
>> + if (!res) {
>> + dev_err(dev, "Parse \"cfg\" resource err\n");
>> + return -ENXIO;
>> + }
>> + pcie->cfg_res = res;
>> +
>> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rcsu");
>> + if (!res) {
>> + dev_err(dev, "Parse \"rcsu\" resource err\n");
>> + return -ENXIO;
>> + }
>> + pcie->rcsu_base = devm_ioremap(dev, res->start, resource_size(res));
>
> Why aren't you using wrapper over get_resource and ioremap? Isn't
> devm_platform_ioremap_resource_byname exactly what you want?
>
Thank you for the reminder. Will change.
> And if argument from previous versions was - you need to backport it for
> ancient 3.10 kernel - then it would be a no go.
Ok, will change.
>
>> + if (!pcie->rcsu_base) {
>> + dev_err(dev, "ioremap failed for resource %pR\n", res);
>> + return -ENOMEM;
>> + }
>> +
>> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "msg");
>> + if (!res) {
>> + dev_err(dev, "Parse \"msg\" resource err\n");
>> + return -ENXIO;
>> + }
>> + pcie->msg_res = res;
>> + pcie->msg_base = devm_ioremap(dev, res->start, resource_size(res));
>> + if (!pcie->msg_base) {
>> + dev_err(dev, "ioremap failed for resource %pR\n", res);
>> + return -ENOMEM;
>> + }
>> +
>> + return ret;
>> +}
>> +
>> +static int sky1_pcie_parse_property(struct platform_device *pdev,
>> + struct sky1_pcie *pcie)
>> +{
>> + int ret = 0;
>> +
>> + ret = sky1_pcie_parse_mem(pcie);
>> + if (ret < 0)
>> + return ret;
>> +
>> + sky1_pcie_init_bases(pcie);
>> +
>> + return ret;
>> +}
>> +
>> +static int sky1_pcie_start_link(struct cdns_pcie *cdns_pcie)
>> +{
>> + struct sky1_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
>> +
>> + sky1_pcie_clear_and_set_dword(pcie->strap_base + STRAP_REG(1),
>> + 0, LINK_TRAINING_ENABLE);
>> +
>> + return 0;
>> +}
>> +
>> +static void sky1_pcie_stop_link(struct cdns_pcie *cdns_pcie)
>> +{
>> + struct sky1_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
>> +
>> + sky1_pcie_clear_and_set_dword(pcie->strap_base + STRAP_REG(1),
>> + LINK_TRAINING_ENABLE, 0);
>> +}
>> +
>> +
>> +static bool sky1_pcie_link_up(struct cdns_pcie *cdns_pcie)
>> +{
>> + u32 val;
>> +
>> + val = cdns_pcie_hpa_readl(cdns_pcie, REG_BANK_IP_REG,
>> + IP_REG_I_DBG_STS_0);
>> + return val & LINK_COMPLETE;
>> +}
>> +
>> +static const struct cdns_pcie_ops sky1_pcie_ops = {
>> + .start_link = sky1_pcie_start_link,
>> + .stop_link = sky1_pcie_stop_link,
>> + .link_up = sky1_pcie_link_up,
>> +};
>> +
>> +static int sky1_pcie_probe(struct platform_device *pdev)
>> +{
>> + const struct sky1_pcie_data *data;
>> + struct device *dev = &pdev->dev;
>> + struct pci_host_bridge *bridge;
>> + struct cdns_pcie *cdns_pcie;
>> + struct resource_entry *bus;
>> + struct cdns_pcie_rc *rc;
>> + struct sky1_pcie *pcie;
>> + int ret;
>> +
>> + pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
>> + if (!pcie)
>> + return -ENOMEM;
>> +
>> + data = of_device_get_match_data(dev);
>> + if (!data)
>> + return -EINVAL;
>> +
>> + pcie->data = data;
>> + pcie->dev = dev;
>> + dev_set_drvdata(dev, pcie);
>> +
>> + bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
>> + if (!bridge)
>> + return -ENOMEM;
>> +
>> + bus = resource_list_first_type(&bridge->windows, IORESOURCE_BUS);
>> + if (!bus)
>> + return -ENODEV;
>> +
>> + ret = sky1_pcie_parse_property(pdev, pcie);
>> + if (ret < 0)
>> + return -ENXIO;
>> +
>> + pcie->cfg = pci_ecam_create(dev, pcie->cfg_res, bus->res,
>> + &pci_generic_ecam_ops);
>> + if (IS_ERR(pcie->cfg))
>> + return PTR_ERR(pcie->cfg);
>> +
>> + bridge->ops = (struct pci_ops *)&pci_generic_ecam_ops.pci_ops;
>> + rc = pci_host_bridge_priv(bridge);
>> + rc->ecam_support_flag = 1;
>> + rc->cfg_base = pcie->cfg->win;
>> + rc->cfg_res = &pcie->cfg->res;
>> +
>> + cdns_pcie = &rc->pcie;
>> + cdns_pcie->dev = dev;
>> + cdns_pcie->ops = &sky1_pcie_ops;
>> + cdns_pcie->reg_base = pcie->reg_base;
>> + cdns_pcie->msg_res = pcie->msg_res;
>> + cdns_pcie->cdns_pcie_reg_offsets = &data->reg_off;
>> + cdns_pcie->is_rc = data->reg_off.is_rc;
>> +
>> + pcie->cdns_pcie = cdns_pcie;
>> + pcie->cdns_pcie_rc = rc;
>> + pcie->cfg_base = rc->cfg_base;
>> + bridge->sysdata = pcie->cfg;
>> +
>> + if (data->soc_type == CIX_SKY1) {
>
>
> Dead code or rather if (true) code. Don't do it, it's more difficult to
> read.
Will remove.
>
>> + rc->vendor_id = PCI_VENDOR_ID_CIX;
>> + rc->device_id = PCI_DEVICE_ID_CIX_SKY1;
>> + rc->no_inbound_flag = 1;
>> + }
>> +
>> + ret = cdns_pcie_hpa_host_setup(rc);
>> + if (ret < 0) {
>> + pci_ecam_free(pcie->cfg);
>> + return ret;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static const struct sky1_pcie_data sky1_pcie_rc_data = {
>> + .reg_off = {
>> + .is_rc = true,
>> + .ip_reg_bank_offset = SKY1_IP_REG_BANK_OFFSET,
>> + .ip_cfg_ctrl_reg_offset = SKY1_IP_CFG_CTRL_REG_BANK_OFFSET,
>> + .axi_mstr_common_offset = SKY1_IP_AXI_MASTER_COMMON_OFFSET,
>> + .axi_slave_offset = SKY1_AXI_SLAVE_OFFSET,
>> + .axi_master_offset = SKY1_AXI_MASTER_OFFSET,
>> + .axi_hls_offset = SKY1_AXI_HLS_REGISTERS_OFFSET,
>> + .axi_ras_offset = SKY1_AXI_RAS_REGISTERS_OFFSET,
>> + .axi_dti_offset = SKY1_DTI_REGISTERS_OFFSET,
>> + },
>> + .soc_type = CIX_SKY1,
>
> You have only one device variant, so this entire pcie_data feels redundant.
>
Will remove.
>> +};
>> +
>> +static const struct of_device_id of_sky1_pcie_match[] = {
>> + {
>> + .compatible = "cix,sky1-pcie-host",
>> + .data = &sky1_pcie_rc_data,
>> + },
>> + {},
>
Best regards,
Hans
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v7 00/13] Enhance the PCIe controller driver for next generation controllers
2025-08-13 19:14 ` [PATCH v7 00/13] Enhance the PCIe controller driver for next generation controllers Krzysztof Kozlowski
@ 2025-08-14 1:37 ` Hans Zhang
0 siblings, 0 replies; 40+ messages in thread
From: Hans Zhang @ 2025-08-14 1:37 UTC (permalink / raw)
To: Krzysztof Kozlowski, bhelgaas, lpieralisi, kw, mani, robh,
kwilczynski, krzk+dt, conor+dt
Cc: mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel
On 2025/8/14 03:14, Krzysztof Kozlowski wrote:
> EXTERNAL EMAIL
>
> On 13/08/2025 06:23, hans.zhang@cixtech.com wrote:
>> From: Hans Zhang <hans.zhang@cixtech.com>
>>
>> ---
>> Dear Maintainers,
>>
>> This series is Cadence's HPA PCIe IP and the Root Port driver of our
>> CIX sky1. Please help review. Thank you very much.
>> ---
>>
>> Enhances the exiting Cadence PCIe controller drivers to support
>> HPA (High Performance Architecture) Cadence PCIe controllers.
>>
>> The patch set enhances the Cadence PCIe driver for HPA support.
>> The header files are separated out for legacy and high performance
>> register maps, register address and bit definitions. The driver
>> read register and write register functions for HPA take the
>> updated offset stored from the platform driver to access the registers.
>> As part of refactoring of the code, few new files are added to the
>> driver by splitting the existing files.
>> This helps SoC vendor who change the address map within PCIe controller
>> in their designs. Setting the menuconfig appropriately will allow
>> selection between RP and/or EP PCIe controller support. The support
>> will include Legacy and HPA for the selected configuration.
>>
>> The TI SoC continues to be supported with the changes incorporated.
>>
>> The changes address the review comments in the previous patches where
>> the need to move away from "ops" pointers used in current implementation
>> and separate out the Legacy and HPA driver implementation was stressed.
>>
>> The scripts/checkpatch.pl has been run on the patches with and without
>> --strict. With the --strict option, 4 checks are generated on 2 patch,
>> which can be ignored. There are no code fixes required for these checks.
>> All other checks generated by ./scripts/checkpatch.pl --strict can be
>> ignored.
>>
>> ---
>> Changes for v7
>> - Rebase to v6.17-rc1.
>> - Fixed the error issue of cix,sky1-pcie-host.yaml make dt_binding_check.
>> - CIX SKY1 Root Port driver compilation error issue: Add header
>> file, Kconfig select PCI_ECAM.
>>
>
> Where are lore links to all previous versions?
Dear Krzysztof,
I will add it in all future versions.
V6:
https://patchwork.kernel.org/project/linux-pci/cover/20250808072929.4090694-1-hans.zhang@cixtech.com/
V5:
https://patchwork.kernel.org/project/linux-pci/cover/20250630041601.399921-1-hans.zhang@cixtech.com/
V4:
https://patchwork.kernel.org/project/linux-pci/cover/20250424010445.2260090-1-hans.zhang@cixtech.com/
V3:
https://patchwork.kernel.org/project/linux-pci/patch/20250411103656.2740517-1-hans.zhang@cixtech.com/
Best regards,
Hans
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v7 02/13] PCI: cadence: Split PCIe controller header file
2025-08-13 4:23 ` [PATCH v7 02/13] PCI: cadence: Split PCIe controller header file hans.zhang
@ 2025-08-14 21:16 ` Bjorn Helgaas
2025-08-18 2:01 ` Manikandan Karunakaran Pillai
0 siblings, 1 reply; 40+ messages in thread
From: Bjorn Helgaas @ 2025-08-14 21:16 UTC (permalink / raw)
To: hans.zhang
Cc: bhelgaas, lpieralisi, kw, mani, robh, kwilczynski, krzk+dt,
conor+dt, mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel
On Wed, Aug 13, 2025 at 12:23:20PM +0800, hans.zhang@cixtech.com wrote:
> From: Manikandan K Pillai <mpillai@cadence.com>
>
> Split the Cadence PCIe header file by moving the Legacy(LGA)
> controller register definitions to a separate header file for
> support of next generation PCIe controller architecture.
s/Legacy(LGA)/Legacy (LGA)/
Similar for "HPA(High Performance architecture)" elsewhere.
> +++ b/drivers/pci/controller/cadence/pcie-cadence-lga-regs.h
> @@ -0,0 +1,228 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +// Copyright (c) 2017 Cadence
> +// Cadence PCIe controller driver.
> +// Author: Manikandan K Pillai <mpillai@cadence.com>
I'm not trying to be a killjoy, but the only author listed in
pcie-cadence.h is Cyrille Pitchen, and I don't think simply moving
these definitions to a separate file really counts as becoming the
author. I would at least preserve Cyrille's authorship.
Bjorn
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v7 01/13] PCI: cadence: Add support for modules for cadence controller builds
2025-08-13 4:23 ` [PATCH v7 01/13] PCI: cadence: Add support for modules for cadence controller builds hans.zhang
@ 2025-08-14 21:25 ` Bjorn Helgaas
0 siblings, 0 replies; 40+ messages in thread
From: Bjorn Helgaas @ 2025-08-14 21:25 UTC (permalink / raw)
To: hans.zhang
Cc: bhelgaas, lpieralisi, kw, mani, robh, kwilczynski, krzk+dt,
conor+dt, mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel
No need to repeat "cadence" in the subject. Something like this would
be sufficient:
PCI: cadence: Add module support for platform controller driver
On Wed, Aug 13, 2025 at 12:23:19PM +0800, hans.zhang@cixtech.com wrote:
> From: Manikandan K Pillai <mpillai@cadence.com>
>
> Add support for building PCI cadence platforms as a module.
>
> Signed-off-by: Manikandan K Pillai <mpillai@cadence.com>
> Signed-off-by: Hans Zhang <hans.zhang@cixtech.com>
> +++ b/drivers/pci/controller/cadence/pcie-cadence-plat.c
> @@ -178,3 +178,7 @@ static struct platform_driver cdns_plat_pcie_driver = {
> .shutdown = cdns_plat_pcie_shutdown,
> };
> builtin_platform_driver(cdns_plat_pcie_driver);
Do you need any change here, e.g., to module_platform_driver()? I'm
not an expert in the module machinery, so just a question.
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Cadence PCIe controller platform driver");
> +MODULE_AUTHOR("Manikandan K Pillai <mpillai@cadence.com>");
> diff --git a/drivers/pci/controller/cadence/pcie-cadence.c b/drivers/pci/controller/cadence/pcie-cadence.c
> index 70a19573440e..5603f214f4c7 100644
> --- a/drivers/pci/controller/cadence/pcie-cadence.c
> +++ b/drivers/pci/controller/cadence/pcie-cadence.c
> @@ -279,6 +279,7 @@ const struct dev_pm_ops cdns_pcie_pm_ops = {
> NOIRQ_SYSTEM_SLEEP_PM_OPS(cdns_pcie_suspend_noirq,
> cdns_pcie_resume_noirq)
> };
> +EXPORT_SYMBOL_GPL(cdns_pcie_pm_ops);
>
> MODULE_LICENSE("GPL");
> MODULE_DESCRIPTION("Cadence PCIe controller driver");
> --
> 2.49.0
>
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v7 03/13] PCI: cadence: Add register definitions for HPA(High Perf Architecture)
2025-08-13 4:23 ` [PATCH v7 03/13] PCI: cadence: Add register definitions for HPA(High Perf Architecture) hans.zhang
2025-08-13 19:17 ` Krzysztof Kozlowski
@ 2025-08-14 21:35 ` Bjorn Helgaas
1 sibling, 0 replies; 40+ messages in thread
From: Bjorn Helgaas @ 2025-08-14 21:35 UTC (permalink / raw)
To: hans.zhang
Cc: bhelgaas, lpieralisi, kw, mani, robh, kwilczynski, krzk+dt,
conor+dt, mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel
On Wed, Aug 13, 2025 at 12:23:21PM +0800, hans.zhang@cixtech.com wrote:
> From: Manikandan K Pillai <mpillai@cadence.com>
>
> Add the register offsets and register definitions for HPA(High
> Performance architecture) PCIe controllers from Cadence.
Add space in "HPA(High Performance architecture)"; also in subject.
> +++ b/drivers/pci/controller/cadence/pcie-cadence-hpa-regs.h
> +/*
> + * HPA (High Performance Architecture) PCIe controller register
> + */
Typical style would be:
/* HPA (High Performance Architecture) PCIe controller register */
> +#define CDNS_PCIE_HPA_IP_AXI_MASTER_COMMON 0x01020000
> +/*
> + * Address Translation Registers(HPA)
> + */
Use a one-line comment and add a blank line before it. Apply below
too.
> + * Root port register base address
s/Root port/Root Port/ to match spec and usage below.
> + * Endpoint Function BARs(HPA) Configuration Registers
Add space.
> + * Root Port Registers PCI config space(HPA) for root port function
Add space.
> +++ b/drivers/pci/controller/cadence/pcie-cadence-plat.c
> @@ -22,10 +22,6 @@ struct cdns_plat_pcie {
> struct cdns_pcie *pcie;
> };
>
> -struct cdns_plat_pcie_of_data {
> - bool is_rc;
> -};
Everything from here down is (as Krzysztof pointed out) much different
than the above and should be in a separate patch so the commit log can
be more specific.
Bjorn
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v7 04/13] PCI: cadence: Split PCIe EP support into common and specific functions
2025-08-13 4:23 ` [PATCH v7 04/13] PCI: cadence: Split PCIe EP support into common and specific functions hans.zhang
@ 2025-08-14 21:41 ` Bjorn Helgaas
0 siblings, 0 replies; 40+ messages in thread
From: Bjorn Helgaas @ 2025-08-14 21:41 UTC (permalink / raw)
To: hans.zhang
Cc: bhelgaas, lpieralisi, kw, mani, robh, kwilczynski, krzk+dt,
conor+dt, mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel
On Wed, Aug 13, 2025 at 12:23:22PM +0800, hans.zhang@cixtech.com wrote:
> From: Manikandan K Pillai <mpillai@cadence.com>
>
> Split the Cadence PCIe controller EP functionality into common
> ibrary functions and functions for legacy PCIe EP controller.
s/ibrary/library/
> +++ b/drivers/pci/controller/cadence/pcie-cadence-ep-common.c
> @@ -0,0 +1,252 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (c) 2017 Cadence
> +// Cadence PCIe endpoint controller driver common
> +// Author: Manikandan K Pillai <mpillai@cadence.com>
This *looks* like mostly a code move from pcie-cadence-ep.c to
pcie-cadence-ep-common.c. If that's the case, make this patch *only*
a move (no code changes or whitespace changes as in
cdns_pcie_ep_start()). And say in the commit log that you're only
moving, not changing, the code.
Also preserve the author from pcie-cadence-ep.c if that's the case.
I do look a little sideways at the // comments since the pcie-cadence*
files are basically the only users in drivers/pci/ (except for the
ibmhp driver that is ancient and basically dead).
Bjorn
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v7 05/13] PCI: cadence: Split PCIe RP support into common and specific functions
2025-08-13 4:23 ` [PATCH v7 05/13] PCI: cadence: Split PCIe RP " hans.zhang
@ 2025-08-14 21:48 ` Bjorn Helgaas
0 siblings, 0 replies; 40+ messages in thread
From: Bjorn Helgaas @ 2025-08-14 21:48 UTC (permalink / raw)
To: hans.zhang
Cc: bhelgaas, lpieralisi, kw, mani, robh, kwilczynski, krzk+dt,
conor+dt, mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel
On Wed, Aug 13, 2025 at 12:23:23PM +0800, hans.zhang@cixtech.com wrote:
> From: Manikandan K Pillai <mpillai@cadence.com>
>
> Split the Cadence PCIe controller RP functionality into common
> functions and functions for legacy PCIe RP controller.
I guess this is simply a move, with no actual code changes?
> +++ b/drivers/pci/controller/cadence/pcie-cadence-ep-common.h
> @@ -1,10 +1,10 @@
> /* SPDX-License-Identifier: GPL-2.0 */
> // Copyright (c) 2017 Cadence
> -// Cadence PCIe Endpoint controller driver.
> +// Cadence PCIe Endpoint controller driver
> // Author: Manikandan K Pillai <mpillai@cadence.com>
>
> -#ifndef _PCIE_CADENCE_EP_COMMON_H_
> -#define _PCIE_CADENCE_EP_COMMON_H_
> +#ifndef _PCIE_CADENCE_EP_COMMON_H
> +#define _PCIE_CADENCE_EP_COMMON_H
>
> #include <linux/kernel.h>
> #include <linux/pci.h>
> @@ -33,4 +33,4 @@ const struct pci_epc_features *cdns_pcie_ep_get_features(struct pci_epc *epc,
> u8 func_no,
> u8 vfunc_no);
>
> -#endif /* _PCIE_CADENCE_EP_COMMON_H_ */
> +#endif /* _PCIE_CADENCE_EP_COMMON_H */
All these changes should be in the patch that creates
pcie-cadence-ep-common.h so we don't have to touch it twice.
> diff --git a/drivers/pci/controller/cadence/pcie-cadence-host-common.c b/drivers/pci/controller/cadence/pcie-cadence-host-common.c
> new file mode 100644
> index 000000000000..5625c64c7974
> --- /dev/null
> +++ b/drivers/pci/controller/cadence/pcie-cadence-host-common.c
> @@ -0,0 +1,181 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (c) 2017 Cadence
> +// Cadence PCIe host controller driver.
> +// Author: Manikandan K Pillai <mpillai@cadence.com>
Not sure about the author here. The authorship info is usually all
there in the git history, so there's less value in including it in the
file itself than there used to be.
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v7 07/13] PCI: cadence: Add support for High Performance Arch(HPA) controller
2025-08-13 4:23 ` [PATCH v7 07/13] PCI: cadence: Add support for High Performance Arch(HPA) controller hans.zhang
@ 2025-08-14 22:14 ` Bjorn Helgaas
0 siblings, 0 replies; 40+ messages in thread
From: Bjorn Helgaas @ 2025-08-14 22:14 UTC (permalink / raw)
To: hans.zhang
Cc: bhelgaas, lpieralisi, kw, mani, robh, kwilczynski, krzk+dt,
conor+dt, mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel
On Wed, Aug 13, 2025 at 12:23:25PM +0800, hans.zhang@cixtech.com wrote:
> From: Manikandan K Pillai <mpillai@cadence.com>
>
> Add support for Cadence PCIe RP and EP configuration for High
> Performance Architecture(HPA) controllers
Add space (also in subject).
> Signed-off-by: Manikandan K Pillai <mpillai@cadence.com>
> Co-developed-by: Hans Zhang <hans.zhang@cixtech.com>
> Signed-off-by: Hans Zhang <hans.zhang@cixtech.com>
> ---
> drivers/pci/controller/cadence/Makefile | 10 +-
> .../controller/cadence/pcie-cadence-ep-hpa.c | 528 ++++++++++++++++
> .../cadence/pcie-cadence-host-hpa.c | 586 ++++++++++++++++++
> .../pci/controller/cadence/pcie-cadence-hpa.c | 207 +++++++
> .../controller/cadence/pcie-cadence-plat.c | 20 +-
> drivers/pci/controller/cadence/pcie-cadence.c | 11 +
> drivers/pci/controller/cadence/pcie-cadence.h | 91 ++-
> 7 files changed, 1438 insertions(+), 15 deletions(-)
> create mode 100644 drivers/pci/controller/cadence/pcie-cadence-ep-hpa.c
> create mode 100644 drivers/pci/controller/cadence/pcie-cadence-host-hpa.c
> create mode 100644 drivers/pci/controller/cadence/pcie-cadence-hpa.c
>
> diff --git a/drivers/pci/controller/cadence/Makefile b/drivers/pci/controller/cadence/Makefile
> index b104562fb86a..de4ddae7aca4 100644
> --- a/drivers/pci/controller/cadence/Makefile
> +++ b/drivers/pci/controller/cadence/Makefile
> @@ -1,6 +1,10 @@
> # SPDX-License-Identifier: GPL-2.0
> -obj-$(CONFIG_PCIE_CADENCE) += pcie-cadence-common.o pcie-cadence.o
> -obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host-common.o pcie-cadence-host.o
> -obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep-common.o pcie-cadence-ep.o
> +pcie-cadence-mod-y := pcie-cadence-hpa.o pcie-cadence-common.o pcie-cadence.o
> +pcie-cadence-host-mod-y := pcie-cadence-host-common.o pcie-cadence-host.o pcie-cadence-host-hpa.o
> +pcie-cadence-ep-mod-y := pcie-cadence-ep-common.o pcie-cadence-ep.o pcie-cadence-ep-hpa.o
> +
> +obj-$(CONFIG_PCIE_CADENCE) = pcie-cadence-mod.o
> +obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host-mod.o
> +obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep-mod.o
> obj-$(CONFIG_PCIE_CADENCE_PLAT) += pcie-cadence-plat.o
> obj-$(CONFIG_PCI_J721E) += pci-j721e.o
> diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep-hpa.c b/drivers/pci/controller/cadence/pcie-cadence-ep-hpa.c
> new file mode 100644
> index 000000000000..36f757820f61
> --- /dev/null
> +++ b/drivers/pci/controller/cadence/pcie-cadence-ep-hpa.c
> @@ -0,0 +1,528 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (c) 2017 Cadence
> +// Cadence PCIe endpoint controller driver.
> +// Author: Manikandan K Pillai <mpillai@cadence.com>
> +
> +#include <linux/bitfield.h>
> +#include <linux/delay.h>
> +#include <linux/kernel.h>
> +#include <linux/of.h>
> +#include <linux/pci-epc.h>
> +#include <linux/platform_device.h>
> +#include <linux/sizes.h>
> +
> +#include "pcie-cadence.h"
> +#include "pcie-cadence-ep-common.h"
> +
> +static int cdns_pcie_hpa_ep_map_addr(struct pci_epc *epc, u8 fn, u8 vfn,
> + phys_addr_t addr, u64 pci_addr, size_t size)
> +{
> + struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
> + struct cdns_pcie *pcie = &ep->pcie;
> + u32 r;
> +
> + r = find_first_zero_bit(&ep->ob_region_map, BITS_PER_LONG);
> + if (r >= ep->max_regions - 1) {
> + dev_err(&epc->dev, "no free outbound region\n");
> + return -EINVAL;
> + }
> +
> + fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn);
> + cdns_pcie_hpa_set_outbound_region(pcie, 0, fn, r, false, addr, pci_addr, size);
> +
> + set_bit(r, &ep->ob_region_map);
> + ep->ob_addr[r] = addr;
> +
> + return 0;
> +}
> +
> +static void cdns_pcie_hpa_ep_unmap_addr(struct pci_epc *epc, u8 fn, u8 vfn,
> + phys_addr_t addr)
> +{
> + struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
> + struct cdns_pcie *pcie = &ep->pcie;
> + u32 r;
> +
> + for (r = 0; r < ep->max_regions - 1; r++)
> + if (ep->ob_addr[r] == addr)
> + break;
> +
> + if (r == ep->max_regions - 1)
> + return;
> +
> + cdns_pcie_hpa_reset_outbound_region(pcie, r);
> +
> + ep->ob_addr[r] = 0;
> + clear_bit(r, &ep->ob_region_map);
> +}
> +
> +static void cdns_pcie_hpa_ep_assert_intx(struct cdns_pcie_ep *ep, u8 fn, u8 intx,
> + bool is_asserted)
"is_asserted" sounds like a statement about whether INTx is already
asserted. But IIUC "is_asserted" tells this function *whether* to
assert INTx. If you call it "assert" it will be clearer.
> +{
> + struct cdns_pcie *pcie = &ep->pcie;
> + unsigned long flags;
> + u32 offset;
> + u16 status;
> + u8 msg_code;
> +
> + intx &= 3;
> +
> + /* Set the outbound region if needed. */
One sentence comments like this typically omit the period.
> + if (unlikely(ep->irq_pci_addr != CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY ||
> + ep->irq_pci_fn != fn)) {
> + /* First region was reserved for IRQ writes. */
And this.
> + cdns_pcie_hpa_set_outbound_region_for_normal_msg(pcie, 0, fn, 0, ep->irq_phys_addr);
> + ep->irq_pci_addr = CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY;
> + ep->irq_pci_fn = fn;
> + }
> +
> + if (is_asserted) {
> + ep->irq_pending |= BIT(intx);
> + msg_code = PCIE_MSG_CODE_ASSERT_INTA + intx;
> + } else {
> + ep->irq_pending &= ~BIT(intx);
> + msg_code = PCIE_MSG_CODE_DEASSERT_INTA + intx;
> + }
> +
> + spin_lock_irqsave(&ep->lock, flags);
> + status = cdns_pcie_ep_fn_readw(pcie, fn, PCI_STATUS);
> + if (((status & PCI_STATUS_INTERRUPT) != 0) ^ (ep->irq_pending != 0)) {
> + status ^= PCI_STATUS_INTERRUPT;
> + cdns_pcie_ep_fn_writew(pcie, fn, PCI_STATUS, status);
> + }
> + spin_unlock_irqrestore(&ep->lock, flags);
> +
> + offset = CDNS_PCIE_NORMAL_MSG_ROUTING(MSG_ROUTING_LOCAL) |
> + CDNS_PCIE_NORMAL_MSG_CODE(msg_code);
> + writel(0, ep->irq_cpu_addr + offset);
> +}
> +
> +static int cdns_pcie_hpa_ep_send_intx_irq(struct cdns_pcie_ep *ep, u8 fn, u8 vfn,
> + u8 intx)
> +{
> + u16 cmd;
> +
> + cmd = cdns_pcie_ep_fn_readw(&ep->pcie, fn, PCI_COMMAND);
> + if (cmd & PCI_COMMAND_INTX_DISABLE)
> + return -EINVAL;
> +
> + cdns_pcie_hpa_ep_assert_intx(ep, fn, intx, true);
> +
> + /* The mdelay() value was taken from dra7xx_pcie_raise_intx_irq() */
Why is this function named "cdns_pcie_hpa_ep_send_intx_irq()" instead
of something like "cdns_pcie_raise_intx_irq()"?
If using a different name adds some value, fine. If it's pointless
difference, not so great.
> + mdelay(1);
> + cdns_pcie_hpa_ep_assert_intx(ep, fn, intx, false);
> + return 0;
> +}
> +
> +static int cdns_pcie_hpa_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn, u8 vfn,
> + u8 interrupt_num)
I see dw_pcie_ep_raise_msi_irq() and dra7xx_pcie_raise_msi_irq()
elsewhere. If there's a pattern we can copy, please copy it.
> +{
> + struct cdns_pcie *pcie = &ep->pcie;
> + u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET;
> + u16 flags, mme, data, data_mask;
> + u8 msi_count;
> + u64 pci_addr, pci_addr_mask = 0xff;
> +
> + fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn);
> +
> + /* Check whether the MSI feature has been enabled by the PCI host. */
> + flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS);
> + if (!(flags & PCI_MSI_FLAGS_ENABLE))
> + return -EINVAL;
> +
> + /* Get the number of enabled MSIs */
> + mme = FIELD_GET(PCI_MSI_FLAGS_QSIZE, flags);
> + msi_count = 1 << mme;
> + if (!interrupt_num || interrupt_num > msi_count)
> + return -EINVAL;
> +
> + /* Compute the data value to be written. */
> + data_mask = msi_count - 1;
> + data = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_DATA_64);
> + data = (data & ~data_mask) | ((interrupt_num - 1) & data_mask);
> +
> + /* Get the PCI address where to write the data into. */
> + pci_addr = cdns_pcie_ep_fn_readl(pcie, fn, cap + PCI_MSI_ADDRESS_HI);
> + pci_addr <<= 32;
> + pci_addr |= cdns_pcie_ep_fn_readl(pcie, fn, cap + PCI_MSI_ADDRESS_LO);
> + pci_addr &= GENMASK_ULL(63, 2);
> +
> + /* Set the outbound region if needed. */
> + if (unlikely(ep->irq_pci_addr != (pci_addr & ~pci_addr_mask) ||
> + ep->irq_pci_fn != fn)) {
> + /* First region was reserved for IRQ writes. */
> + cdns_pcie_hpa_set_outbound_region(pcie, 0, fn, 0,
> + false,
> + ep->irq_phys_addr,
> + pci_addr & ~pci_addr_mask,
> + pci_addr_mask + 1);
> + ep->irq_pci_addr = (pci_addr & ~pci_addr_mask);
> + ep->irq_pci_fn = fn;
> + }
> + writel(data, ep->irq_cpu_addr + (pci_addr & pci_addr_mask));
> +
> + return 0;
> +}
> +
> +static int cdns_pcie_hpa_ep_send_msix_irq(struct cdns_pcie_ep *ep, u8 fn, u8 vfn,
> + u16 interrupt_num)
> +{
> + u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
> + u32 tbl_offset, msg_data, reg;
> + struct cdns_pcie *pcie = &ep->pcie;
> + struct pci_epf_msix_tbl *msix_tbl;
> + struct cdns_pcie_epf *epf;
> + u64 pci_addr_mask = 0xff;
> + u64 msg_addr;
> + u16 flags;
> + u8 bir;
> +
> + epf = &ep->epf[fn];
> + if (vfn > 0)
> + epf = &epf->epf[vfn - 1];
> +
> + fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn);
> +
> + /* 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 = FIELD_GET(PCI_MSIX_TABLE_BIR, tbl_offset);
> + tbl_offset &= PCI_MSIX_TABLE_OFFSET;
> +
> + msix_tbl = epf->epf_bar[bir]->addr + tbl_offset;
> + msg_addr = msix_tbl[(interrupt_num - 1)].msg_addr;
> + msg_data = msix_tbl[(interrupt_num - 1)].msg_data;
> +
> + /* 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_hpa_set_outbound_region(pcie, 0, 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_hpa_ep_raise_irq(struct pci_epc *epc, u8 fn, u8 vfn,
> + unsigned int type, u16 interrupt_num)
> +{
> + struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
> + struct cdns_pcie *pcie = &ep->pcie;
> + struct device *dev = pcie->dev;
> +
> + switch (type) {
> + case PCI_IRQ_INTX:
> + if (vfn > 0) {
> + dev_err(dev, "Cannot raise INTX interrupts for VF\n");
> + return -EINVAL;
> + }
> + return cdns_pcie_hpa_ep_send_intx_irq(ep, fn, vfn, 0);
> +
> + case PCI_IRQ_MSI:
> + return cdns_pcie_hpa_ep_send_msi_irq(ep, fn, vfn, interrupt_num);
> +
> + case PCI_IRQ_MSIX:
> + return cdns_pcie_hpa_ep_send_msix_irq(ep, fn, vfn, interrupt_num);
> +
> + default:
> + break;
> + }
> +
> + return -EINVAL;
> +}
> +
> +static int cdns_pcie_hpa_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;
> + int max_epfs = sizeof(epc->function_num_map) * 8;
> + int ret, epf, last_fn;
> + u32 reg, value;
> +
> + /*
> + * BIT(0) is hardwired to 1, hence function 0 is always enabled
> + * and can't be disabled anyway.
> + */
> + cdns_pcie_hpa_writel(pcie, REG_BANK_IP_REG,
> + CDNS_PCIE_HPA_LM_EP_FUNC_CFG, epc->function_num_map);
> +
> + /*
> + * Next function field in ARI_CAP_AND_CTR register for last function
> + * should be 0. Clear Next Function Number field for the last
> + * function used.
> + */
> + last_fn = find_last_bit(&epc->function_num_map, BITS_PER_LONG);
> + reg = CDNS_PCIE_CORE_PF_I_ARI_CAP_AND_CTRL(last_fn);
> + value = cdns_pcie_readl(pcie, reg);
> + value &= ~CDNS_PCIE_ARI_CAP_NFN_MASK;
> + cdns_pcie_writel(pcie, reg, value);
> +
> + if (ep->quirk_disable_flr) {
> + for (epf = 0; epf < max_epfs; epf++) {
> + if (!(epc->function_num_map & BIT(epf)))
> + continue;
> +
> + value = cdns_pcie_ep_fn_readl(pcie, epf,
> + CDNS_PCIE_EP_FUNC_DEV_CAP_OFFSET +
> + PCI_EXP_DEVCAP);
> + value &= ~PCI_EXP_DEVCAP_FLR;
> + cdns_pcie_ep_fn_writel(pcie, epf,
> + CDNS_PCIE_EP_FUNC_DEV_CAP_OFFSET +
> + PCI_EXP_DEVCAP, value);
> + }
> + }
> +
> + ret = cdns_pcie_start_link(pcie);
> + if (ret) {
> + dev_err(dev, "Failed to start link\n");
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int cdns_pcie_hpa_ep_set_bar(struct pci_epc *epc, u8 fn, u8 vfn,
> + 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;
> + int flags = epf_bar->flags;
> + u32 addr0, addr1, reg, cfg, b, aperture, ctrl;
> + u64 sz;
> +
> + /* BAR size is 2^(aperture + 7) */
> + sz = max_t(size_t, epf_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);
> +
> + /* 128B -> 0, 256B -> 1, 512B -> 2, ... */
> + aperture = ilog2(sz) - 7;
> +
> + if ((flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
> + ctrl = CDNS_PCIE_HPA_LM_BAR_CFG_CTRL_IO_32BITS;
> + } else {
> + bool is_prefetch = !!(flags & PCI_BASE_ADDRESS_MEM_PREFETCH);
> + bool is_64bits = !!(flags & PCI_BASE_ADDRESS_MEM_TYPE_64);
> +
> + if (is_64bits && (bar & 1))
> + return -EINVAL;
> +
> + if (is_64bits && is_prefetch)
> + ctrl = CDNS_PCIE_HPA_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS;
> + else if (is_prefetch)
> + ctrl = CDNS_PCIE_HPA_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS;
> + else if (is_64bits)
> + ctrl = CDNS_PCIE_HPA_LM_BAR_CFG_CTRL_MEM_64BITS;
> + else
> + ctrl = CDNS_PCIE_HPA_LM_BAR_CFG_CTRL_MEM_32BITS;
> + }
> +
> + addr0 = lower_32_bits(bar_phys);
> + addr1 = upper_32_bits(bar_phys);
> +
> + if (vfn == 1)
> + reg = CDNS_PCIE_HPA_LM_EP_VFUNC_BAR_CFG(bar, fn);
> + else
> + reg = CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG(bar, fn);
> + b = (bar < BAR_4) ? bar : bar - BAR_4;
> +
> + if (vfn == 0 || vfn == 1) {
> + cfg = cdns_pcie_hpa_readl(pcie, REG_BANK_IP_CFG_CTRL_REG, reg);
> + cfg &= ~(CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) |
> + CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b));
> + cfg |= (CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG_BAR_APERTURE(b, aperture) |
> + CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl));
> + cdns_pcie_hpa_writel(pcie, REG_BANK_IP_CFG_CTRL_REG, reg, cfg);
> + }
> +
> + fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_MASTER_COMMON,
> + CDNS_PCIE_HPA_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar), addr0);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_MASTER_COMMON,
> + CDNS_PCIE_HPA_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar), addr1);
> +
> + if (vfn > 0)
> + epf = &epf->epf[vfn - 1];
> + epf->epf_bar[bar] = epf_bar;
> +
> + return 0;
> +}
> +
> +static void cdns_pcie_hpa_ep_clear_bar(struct pci_epc *epc, u8 fn, u8 vfn,
> + 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;
> +
> + if (vfn == 1)
> + reg = CDNS_PCIE_HPA_LM_EP_VFUNC_BAR_CFG(bar, fn);
> + else
> + reg = CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG(bar, fn);
> + b = (bar < BAR_4) ? bar : bar - BAR_4;
> +
> + if (vfn == 0 || vfn == 1) {
> + ctrl = CDNS_PCIE_HPA_LM_BAR_CFG_CTRL_DISABLED;
> + cfg = cdns_pcie_hpa_readl(pcie, REG_BANK_IP_CFG_CTRL_REG, reg);
> + cfg &= ~(CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) |
> + CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b));
> + cfg |= CDNS_PCIE_HPA_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_IP_CFG_CTRL_REG, reg, cfg);
> + }
> +
> + fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_MASTER_COMMON,
> + CDNS_PCIE_HPA_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar), 0);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_MASTER_COMMON,
> + CDNS_PCIE_HPA_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar), 0);
> +
> + if (vfn > 0)
> + epf = &epf->epf[vfn - 1];
> + epf->epf_bar[bar] = NULL;
> +}
> +
> +static const struct pci_epc_ops cdns_pcie_hpa_epc_ops = {
> + .write_header = cdns_pcie_ep_write_header,
> + .set_bar = cdns_pcie_hpa_ep_set_bar,
> + .clear_bar = cdns_pcie_hpa_ep_clear_bar,
> + .map_addr = cdns_pcie_hpa_ep_map_addr,
> + .unmap_addr = cdns_pcie_hpa_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_hpa_ep_raise_irq,
> + .map_msi_irq = cdns_pcie_ep_map_msi_irq,
> + .start = cdns_pcie_hpa_ep_start,
> + .get_features = cdns_pcie_ep_get_features,
> +};
> +
> +int cdns_pcie_hpa_ep_setup(struct cdns_pcie_ep *ep)
> +{
> + struct device *dev = ep->pcie.dev;
> + struct platform_device *pdev = to_platform_device(dev);
> + struct device_node *np = dev->of_node;
> + struct cdns_pcie *pcie = &ep->pcie;
> + struct cdns_pcie_epf *epf;
> + struct resource *res;
> + struct pci_epc *epc;
> + int ret;
> + int i;
> +
> + pcie->is_rc = false;
> +
> + pcie->reg_base = devm_platform_ioremap_resource_byname(pdev, "reg");
> + if (IS_ERR(pcie->reg_base)) {
> + dev_err(dev, "missing \"reg\"\n");
> + return PTR_ERR(pcie->reg_base);
> + }
> +
> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem");
> + if (!res) {
> + dev_err(dev, "missing \"mem\"\n");
> + return -EINVAL;
> + }
> + pcie->mem_res = res;
> +
> + ep->max_regions = CDNS_PCIE_MAX_OB;
> + of_property_read_u32(np, "cdns,max-outbound-regions", &ep->max_regions);
> +
> + ep->ob_addr = devm_kcalloc(dev,
> + ep->max_regions, sizeof(*ep->ob_addr),
> + GFP_KERNEL);
> + if (!ep->ob_addr)
> + return -ENOMEM;
> +
> + epc = devm_pci_epc_create(dev, &cdns_pcie_hpa_epc_ops);
> + if (IS_ERR(epc)) {
> + dev_err(dev, "failed to create epc device\n");
> + return PTR_ERR(epc);
> + }
> +
> + epc_set_drvdata(epc, 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;
> +
> + epc->max_vfs = devm_kcalloc(dev, epc->max_functions,
> + sizeof(*epc->max_vfs), GFP_KERNEL);
> + if (!epc->max_vfs)
> + return -ENOMEM;
> +
> + ret = of_property_read_u8_array(np, "max-virtual-functions",
> + epc->max_vfs, epc->max_functions);
> + if (ret == 0) {
> + for (i = 0; i < epc->max_functions; i++) {
> + epf = &ep->epf[i];
> + if (epc->max_vfs[i] == 0)
> + continue;
> + epf->epf = devm_kcalloc(dev, epc->max_vfs[i],
> + sizeof(*ep->epf), GFP_KERNEL);
> + if (!epf->epf)
> + return -ENOMEM;
> + }
> + }
> +
> + ret = pci_epc_mem_init(epc, pcie->mem_res->start,
> + resource_size(pcie->mem_res), PAGE_SIZE);
> + if (ret < 0) {
> + dev_err(dev, "failed to initialize the memory space\n");
> + return ret;
> + }
> +
> + ep->irq_cpu_addr = pci_epc_mem_alloc_addr(epc, &ep->irq_phys_addr,
> + SZ_128K);
> + if (!ep->irq_cpu_addr) {
> + dev_err(dev, "failed to reserve memory space for MSI\n");
> + ret = -ENOMEM;
> + goto free_epc_mem;
> + }
> + ep->irq_pci_addr = CDNS_PCIE_EP_IRQ_PCI_ADDR_NONE;
> + /* Reserve region 0 for IRQs */
> + set_bit(0, &ep->ob_region_map);
> +
> + if (ep->quirk_detect_quiet_flag)
> + cdns_pcie_hpa_detect_quiet_min_delay_set(&ep->pcie);
> +
> + spin_lock_init(&ep->lock);
> +
> + pci_epc_init_notify(epc);
> +
> + return 0;
> +
> + free_epc_mem:
> + pci_epc_mem_exit(epc);
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(cdns_pcie_hpa_ep_setup);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Cadence PCIe controller driver");
> +MODULE_AUTHOR("Manikandan K Pillai <mpillai@cadence.com>");
> diff --git a/drivers/pci/controller/cadence/pcie-cadence-host-hpa.c b/drivers/pci/controller/cadence/pcie-cadence-host-hpa.c
> new file mode 100644
> index 000000000000..f930b745bc33
> --- /dev/null
> +++ b/drivers/pci/controller/cadence/pcie-cadence-host-hpa.c
> @@ -0,0 +1,586 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (c) 2017 Cadence
> +// Cadence PCIe host controller driver.
> +// Author: Manikandan K Pillai <mpillai@cadence.com>
> +
> +#include <linux/delay.h>
> +#include <linux/kernel.h>
> +#include <linux/list_sort.h>
> +#include <linux/of_address.h>
> +#include <linux/of_pci.h>
> +#include <linux/platform_device.h>
> +
> +#include "pcie-cadence.h"
> +#include "pcie-cadence-host-common.h"
> +
> +static u8 bar_aperture_mask[] = {
> + [RP_BAR0] = 0x1F,
> + [RP_BAR1] = 0xF,
> +};
> +
> +void __iomem *cdns_pci_hpa_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);
> + struct cdns_pcie *pcie = &rc->pcie;
> + unsigned int busn = bus->number;
> + u32 addr0, desc0, desc1, ctrl0;
> + u32 regval;
> +
> + if (pci_is_root_bus(bus)) {
> + /*
> + * Only the root port (devfn == 0) is connected to this bus.
> + * All other PCI devices are behind some bridge hence on another
> + * bus.
> + */
> + if (devfn)
> + return NULL;
> +
> + return pcie->reg_base + (where & 0xfff);
> + }
> +
> + /* Clear AXI link-down status */
> + regval = cdns_pcie_hpa_readl(pcie, REG_BANK_AXI_SLAVE, CDNS_PCIE_HPA_AT_LINKDOWN);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE, CDNS_PCIE_HPA_AT_LINKDOWN,
> + (regval & ~GENMASK(0, 0)));
> +
> + desc0 = 0;
> + desc1 = 0;
> + ctrl0 = 0;
> +
> + /* Update Output registers for AXI region 0. */
> + addr0 = CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR0_NBITS(12) |
> + CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) |
> + CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR0_BUS(busn);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR0(0), addr0);
> +
> + desc1 = cdns_pcie_hpa_readl(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_DESC1(0));
> + desc1 &= ~CDNS_PCIE_HPA_AT_OB_REGION_DESC1_DEVFN_MASK;
> + desc1 |= CDNS_PCIE_HPA_AT_OB_REGION_DESC1_DEVFN(0);
> + ctrl0 = CDNS_PCIE_HPA_AT_OB_REGION_CTRL0_SUPPLY_BUS |
> + CDNS_PCIE_HPA_AT_OB_REGION_CTRL0_SUPPLY_DEV_FN;
> +
> + if (busn == bridge->busnr + 1)
> + desc0 |= CDNS_PCIE_HPA_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0;
> + else
> + desc0 |= CDNS_PCIE_HPA_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1;
> +
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_DESC0(0), desc0);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_DESC1(0), desc1);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_CTRL0(0), ctrl0);
> +
> + return rc->cfg_base + (where & 0xfff);
> +}
> +
> +int cdns_pcie_hpa_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;
> +}
> +EXPORT_SYMBOL_GPL(cdns_pcie_hpa_host_wait_for_link);
> +
> +int cdns_pcie_hpa_host_start_link(struct cdns_pcie_rc *rc)
> +{
> + struct cdns_pcie *pcie = &rc->pcie;
> + int ret;
> +
> + ret = cdns_pcie_host_wait_for_link(pcie);
> +
> + /*
> + * Retrain link for Gen2 training defect
> + * if quirk flag is set.
Wrap to fill 78 columns like other comments here.
> + */
> + if (!ret && rc->quirk_retrain_flag)
> + ret = cdns_pcie_retrain(pcie);
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(cdns_pcie_hpa_host_start_link);
> +
> +static struct pci_ops cdns_pcie_hpa_host_ops = {
> + .map_bus = cdns_pci_hpa_map_bus,
> + .read = pci_generic_config_read,
> + .write = pci_generic_config_write,
> +};
> +
> +static void cdns_pcie_hpa_host_enable_ptm_response(struct cdns_pcie *pcie)
> +{
> + u32 val;
> +
> + val = cdns_pcie_hpa_readl(pcie, REG_BANK_IP_REG, CDNS_PCIE_HPA_LM_PTM_CTRL);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_IP_REG, CDNS_PCIE_HPA_LM_PTM_CTRL,
> + val | CDNS_PCIE_HPA_LM_TPM_CTRL_PTMRSEN);
> +}
> +
> +static int cdns_pcie_hpa_host_bar_ib_config(struct cdns_pcie_rc *rc,
> + enum cdns_pcie_rp_bar bar,
> + u64 cpu_addr, u64 size,
> + unsigned long flags)
> +{
> + struct cdns_pcie *pcie = &rc->pcie;
> + u32 addr0, addr1, aperture, value;
> +
> + if (!rc->avail_ib_bar[bar])
> + return -EBUSY;
> +
> + rc->avail_ib_bar[bar] = false;
> +
> + aperture = ilog2(size);
> + addr0 = CDNS_PCIE_HPA_AT_IB_RP_BAR_ADDR0_NBITS(aperture) |
> + (lower_32_bits(cpu_addr) & GENMASK(31, 8));
> + addr1 = upper_32_bits(cpu_addr);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_MASTER,
> + CDNS_PCIE_HPA_AT_IB_RP_BAR_ADDR0(bar), addr0);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_MASTER,
> + CDNS_PCIE_HPA_AT_IB_RP_BAR_ADDR1(bar), addr1);
> +
> + if (bar == RP_NO_BAR)
> + return 0;
> +
> + value = cdns_pcie_hpa_readl(pcie, REG_BANK_IP_CFG_CTRL_REG, CDNS_PCIE_HPA_LM_RC_BAR_CFG);
> + value &= ~(HPA_LM_RC_BAR_CFG_CTRL_MEM_64BITS(bar) |
> + HPA_LM_RC_BAR_CFG_CTRL_PREF_MEM_64BITS(bar) |
> + HPA_LM_RC_BAR_CFG_CTRL_MEM_32BITS(bar) |
> + HPA_LM_RC_BAR_CFG_CTRL_PREF_MEM_32BITS(bar) |
> + HPA_LM_RC_BAR_CFG_APERTURE(bar, bar_aperture_mask[bar] + 2));
> + if (size + cpu_addr >= SZ_4G) {
> + if (!(flags & IORESOURCE_PREFETCH))
> + value |= HPA_LM_RC_BAR_CFG_CTRL_MEM_64BITS(bar);
> + value |= HPA_LM_RC_BAR_CFG_CTRL_PREF_MEM_64BITS(bar);
> + } else {
> + if (!(flags & IORESOURCE_PREFETCH))
> + value |= HPA_LM_RC_BAR_CFG_CTRL_MEM_32BITS(bar);
> + value |= HPA_LM_RC_BAR_CFG_CTRL_PREF_MEM_32BITS(bar);
> + }
> +
> + value |= HPA_LM_RC_BAR_CFG_APERTURE(bar, aperture);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_IP_CFG_CTRL_REG, CDNS_PCIE_HPA_LM_RC_BAR_CFG, value);
> +
> + return 0;
> +}
> +
> +static int cdns_pcie_hpa_host_bar_config(struct cdns_pcie_rc *rc,
> + struct resource_entry *entry)
> +{
> + u64 cpu_addr, pci_addr, size, winsize;
> + struct cdns_pcie *pcie = &rc->pcie;
> + struct device *dev = pcie->dev;
> + enum cdns_pcie_rp_bar bar;
> + unsigned long flags;
> + int ret;
> +
> + cpu_addr = entry->res->start;
> + pci_addr = entry->res->start - entry->offset;
> + flags = entry->res->flags;
> + size = resource_size(entry->res);
> +
> + if (entry->offset) {
> + dev_err(dev, "PCI addr: %llx must be equal to CPU addr: %llx\n",
> + pci_addr, cpu_addr);
> + return -EINVAL;
> + }
> +
> + while (size > 0) {
> + /*
> + * Try to find a minimum BAR whose size is greater than
> + * or equal to the remaining resource_entry size. This will
> + * fail if the size of each of the available BARs is less than
> + * the remaining resource_entry size.
> + * If a minimum BAR is found, IB ATU will be configured and
> + * exited.
Add blank lines between paragraphs. Also below.
> + */
> + bar = cdns_pcie_host_find_min_bar(rc, size);
> + if (bar != RP_BAR_UNDEFINED) {
> + ret = cdns_pcie_hpa_host_bar_ib_config(rc, bar, cpu_addr,
> + size, flags);
> + if (ret)
> + dev_err(dev, "IB BAR: %d config failed\n", bar);
> + return ret;
> + }
> +
> + /*
> + * If the control reaches here, it would mean the remaining
> + * resource_entry size cannot be fitted in a single BAR. So we
> + * find a maximum BAR whose size is less than or equal to the
> + * remaining resource_entry size and split the resource entry
> + * so that part of resource entry is fitted inside the maximum
> + * BAR. The remaining size would be fitted during the next
> + * iteration of the loop.
> + * If a maximum BAR is not found, there is no way we can fit
> + * this resource_entry, so we error out.
> + */
> + bar = cdns_pcie_host_find_max_bar(rc, size);
> + if (bar == RP_BAR_UNDEFINED) {
> + dev_err(dev, "No free BAR to map cpu_addr %llx\n",
> + cpu_addr);
> + return -EINVAL;
> + }
> +
> + winsize = bar_max_size[bar];
> + ret = cdns_pcie_hpa_host_bar_ib_config(rc, bar, cpu_addr, winsize, flags);
> + if (ret) {
> + dev_err(dev, "IB BAR: %d config failed\n", bar);
> + return ret;
> + }
> +
> + size -= winsize;
> + cpu_addr += winsize;
> + }
> +
> + return 0;
> +}
> +
> +static int cdns_pcie_hpa_host_map_dma_ranges(struct cdns_pcie_rc *rc)
> +{
> + struct cdns_pcie *pcie = &rc->pcie;
> + struct device *dev = pcie->dev;
> + struct device_node *np = dev->of_node;
> + struct pci_host_bridge *bridge;
> + struct resource_entry *entry;
> + u32 no_bar_nbits = 32;
> + int err;
> +
> + bridge = pci_host_bridge_from_priv(rc);
> + if (!bridge)
> + return -ENOMEM;
> +
> + if (list_empty(&bridge->dma_ranges)) {
> + of_property_read_u32(np, "cdns,no-bar-match-nbits",
> + &no_bar_nbits);
> + err = cdns_pcie_hpa_host_bar_ib_config(rc, RP_NO_BAR, 0x0,
> + (u64)1 << no_bar_nbits, 0);
> + if (err)
> + dev_err(dev, "IB BAR: %d config failed\n", RP_NO_BAR);
> + return err;
> + }
> +
> + list_sort(NULL, &bridge->dma_ranges, cdns_pcie_host_dma_ranges_cmp);
> +
> + resource_list_for_each_entry(entry, &bridge->dma_ranges) {
> + err = cdns_pcie_hpa_host_bar_config(rc, entry);
> + if (err) {
> + dev_err(dev, "Fail to configure IB using dma-ranges\n");
> + return err;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int cdns_pcie_hpa_host_init_root_port(struct cdns_pcie_rc *rc)
> +{
> + struct cdns_pcie *pcie = &rc->pcie;
> + u32 value, ctrl;
> +
> + /*
> + * Set the root complex BAR configuration register:
> + * - disable both BAR0 and BAR1.
> + * - enable Prefetchable Memory Base and Limit registers in type 1
> + * config space (64 bits).
> + * - enable IO Base and Limit registers in type 1 config
> + * space (32 bits).
> + */
> +
> + ctrl = CDNS_PCIE_HPA_LM_BAR_CFG_CTRL_DISABLED;
> + value = CDNS_PCIE_HPA_LM_RC_BAR_CFG_BAR0_CTRL(ctrl) |
> + CDNS_PCIE_HPA_LM_RC_BAR_CFG_BAR1_CTRL(ctrl) |
> + CDNS_PCIE_HPA_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE |
> + CDNS_PCIE_HPA_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS |
> + CDNS_PCIE_HPA_LM_RC_BAR_CFG_IO_ENABLE |
> + CDNS_PCIE_HPA_LM_RC_BAR_CFG_IO_32BITS;
> + cdns_pcie_hpa_writel(pcie, REG_BANK_IP_CFG_CTRL_REG,
> + CDNS_PCIE_HPA_LM_RC_BAR_CFG, value);
> +
> + if (rc->vendor_id != 0xffff)
> + cdns_pcie_hpa_rp_writew(pcie, PCI_VENDOR_ID, rc->vendor_id);
> +
> + if (rc->device_id != 0xffff)
> + cdns_pcie_hpa_rp_writew(pcie, PCI_DEVICE_ID, rc->device_id);
> +
> + cdns_pcie_hpa_rp_writeb(pcie, PCI_CLASS_REVISION, 0);
> + cdns_pcie_hpa_rp_writeb(pcie, PCI_CLASS_PROG, 0);
> + cdns_pcie_hpa_rp_writew(pcie, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI);
> +
> + return 0;
> +}
> +
> +static void cdns_pcie_hpa_create_region_for_ecam(struct cdns_pcie_rc *rc)
> +{
> + struct pci_host_bridge *bridge = pci_host_bridge_from_priv(rc);
> + struct resource *cfg_res = rc->cfg_res;
> + struct cdns_pcie *pcie = &rc->pcie;
> + u32 value, root_port_req_id_reg, pcie_bus_number_reg;
> + u32 ecam_addr_0, region_size_0, request_id_0;
> + int busnr = 0, secbus = 0, subbus = 0;
> + struct resource_entry *entry;
> + resource_size_t size;
> + u32 axi_address_low;
> + int nbits;
> + u64 sz;
> +
> + entry = resource_list_first_type(&bridge->windows, IORESOURCE_BUS);
> + if (entry) {
> + busnr = entry->res->start;
> + secbus = (busnr < 0xff) ? (busnr + 1) : 0xff;
> + subbus = entry->res->end;
> + }
> + size = resource_size(cfg_res);
> + sz = 1ULL << fls64(size - 1);
> + nbits = ilog2(sz);
> + if (nbits < 8)
> + nbits = 8;
> +
> + root_port_req_id_reg = ((busnr & 0xff) << 8);
> + pcie_bus_number_reg = ((subbus & 0xff) << 16) | ((secbus & 0xff) << 8) |
> + (busnr & 0xff);
> + ecam_addr_0 = cfg_res->start;
> + region_size_0 = nbits - 1;
> + request_id_0 = ((busnr & 0xff) << 8);
> +
> +#define CDNS_PCIE_HPA_TAG_MANAGEMENT (0x0)
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_TAG_MANAGEMENT, 0x200000);
> +
> + /* Taking slave err as OKAY */
> +#define CDNS_PCIE_HPA_SLAVE_RESP (0x100)
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE, CDNS_PCIE_HPA_SLAVE_RESP,
> + 0x0);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_SLAVE_RESP + 0x4, 0x0);
> +
> + /* Program the register "i_root_port_req_id_reg" with RP's BDF */
> +#define I_ROOT_PORT_REQ_ID_REG (0x141c)
> + cdns_pcie_hpa_writel(pcie, REG_BANK_IP_REG, I_ROOT_PORT_REQ_ID_REG,
> + root_port_req_id_reg);
> +
> + /**
> + * Program the register "i_pcie_bus_numbers" with Primary(RP's bus number),
> + * secondary and subordinate bus numbers
> + */
> +#define I_PCIE_BUS_NUMBERS (CDNS_PCIE_HPA_RP_BASE + 0x18)
> + cdns_pcie_hpa_writel(pcie, REG_BANK_RP, I_PCIE_BUS_NUMBERS,
> + pcie_bus_number_reg);
> +
> + /* Program the register "lm_hal_sbsa_ctrl[0]" to enable the sbsa */
> +#define LM_HAL_SBSA_CTRL (0x1170)
> + value = cdns_pcie_hpa_readl(pcie, REG_BANK_IP_REG, LM_HAL_SBSA_CTRL);
> + value |= BIT(0);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_IP_REG, LM_HAL_SBSA_CTRL, value);
> +
> + /* Program region[0] for ECAM */
> + axi_address_low = (ecam_addr_0 & 0xfff00000) | region_size_0;
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR0(0),
> + axi_address_low);
> +
> + /* rc0-high-axi-address */
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR1(0), 0x0);
> + /* Type-1 CFG */
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_DESC0(0), 0x05000000);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_DESC1(0),
> + (request_id_0 << 16));
> +
> + /* All AXI bits pass through PCIe */
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR0(0), 0x1b);
> + /* PCIe address-high */
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR1(0), 0);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_CTRL0(0), 0x06000000);
> +}
> +
> +static void cdns_pcie_hpa_create_region_for_cfg(struct cdns_pcie_rc *rc)
> +{
> + struct cdns_pcie *pcie = &rc->pcie;
> + struct pci_host_bridge *bridge = pci_host_bridge_from_priv(rc);
> + struct resource *cfg_res = rc->cfg_res;
> + struct resource_entry *entry;
> + u64 cpu_addr = cfg_res->start;
> + u32 addr0, addr1, desc1;
> + int busnr = 0;
> +
> + entry = resource_list_first_type(&bridge->windows, IORESOURCE_BUS);
> + if (entry)
> + busnr = entry->res->start;
> +
> + /*
> + * Reserve region 0 for PCI configure space accesses:
> + * OB_REGION_PCI_ADDR0 and OB_REGION_DESC0 are updated dynamically by
> + * cdns_pci_map_bus(), other region registers are set here once for all.
> + */
> + addr1 = 0;
> + desc1 = CDNS_PCIE_HPA_AT_OB_REGION_DESC1_BUS(busnr);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR1(0), addr1);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_DESC1(0), desc1);
> +
> + addr0 = CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR0_NBITS(12) |
> + (lower_32_bits(cpu_addr) & GENMASK(31, 8));
> + addr1 = upper_32_bits(cpu_addr);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR0(0), addr0);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR1(0), addr1);
> +}
> +
> +static int cdns_pcie_hpa_host_init_address_translation(struct cdns_pcie_rc *rc)
> +{
> + struct cdns_pcie *pcie = &rc->pcie;
> + struct pci_host_bridge *bridge = pci_host_bridge_from_priv(rc);
> + struct resource_entry *entry;
> + int r = 0, busnr = 0;
> +
> + if (rc->ecam_support_flag)
> + cdns_pcie_hpa_create_region_for_ecam(rc);
> + else
> + cdns_pcie_hpa_create_region_for_cfg(rc);
> +
> + entry = resource_list_first_type(&bridge->windows, IORESOURCE_BUS);
> + if (entry)
> + busnr = entry->res->start;
> +
> + r++;
> + if (pcie->msg_res)
> + cdns_pcie_hpa_set_outbound_region_for_normal_msg(pcie, busnr, 0, r,
> + pcie->msg_res->start);
> +
> + r++;
> + resource_list_for_each_entry(entry, &bridge->windows) {
> + struct resource *res = entry->res;
> + u64 pci_addr = res->start - entry->offset;
> +
> + if (resource_type(res) == IORESOURCE_IO)
> + cdns_pcie_hpa_set_outbound_region(pcie, busnr, 0, r,
> + true,
> + pci_pio_to_address(res->start),
> + pci_addr,
> + resource_size(res));
> + else
> + cdns_pcie_hpa_set_outbound_region(pcie, busnr, 0, r,
> + false,
> + res->start,
> + pci_addr,
> + resource_size(res));
> +
> + r++;
> + }
> +
> + if (rc->no_inbound_flag)
> + return 0;
> + else
> + return cdns_pcie_hpa_host_map_dma_ranges(rc);
> +}
> +
> +int cdns_pcie_hpa_host_init(struct cdns_pcie_rc *rc)
> +{
> + int err;
> +
> + err = cdns_pcie_hpa_host_init_root_port(rc);
> + if (err)
> + return err;
> +
> + return cdns_pcie_hpa_host_init_address_translation(rc);
> +}
> +EXPORT_SYMBOL_GPL(cdns_pcie_hpa_host_init);
> +
> +int cdns_pcie_hpa_host_link_setup(struct cdns_pcie_rc *rc)
> +{
> + struct cdns_pcie *pcie = &rc->pcie;
> + struct device *dev = rc->pcie.dev;
> + int ret;
> +
> + if (rc->quirk_detect_quiet_flag)
> + cdns_pcie_hpa_detect_quiet_min_delay_set(&rc->pcie);
> +
> + cdns_pcie_hpa_host_enable_ptm_response(pcie);
> +
> + ret = cdns_pcie_start_link(pcie);
> + if (ret) {
> + dev_err(dev, "Failed to start link\n");
> + return ret;
> + }
> +
> + ret = cdns_pcie_hpa_host_start_link(rc);
> + if (ret)
> + dev_dbg(dev, "PCIe link never came up\n");
I see this whole function is cloned from cdns_pcie_host_link_setup(),
but I can't remember why we need two _start_link() functions here.
Seems confusing.
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(cdns_pcie_hpa_host_link_setup);
> +
> +int cdns_pcie_hpa_host_setup(struct cdns_pcie_rc *rc)
> +{
> + struct device *dev = rc->pcie.dev;
> + struct platform_device *pdev = to_platform_device(dev);
> + struct pci_host_bridge *bridge;
> + enum cdns_pcie_rp_bar bar;
> + struct cdns_pcie *pcie;
> + struct resource *res;
> + int ret;
> +
> + bridge = pci_host_bridge_from_priv(rc);
> + if (!bridge)
> + return -ENOMEM;
> +
> + pcie = &rc->pcie;
> + pcie->is_rc = true;
> +
> + if (!pcie->reg_base) {
> + pcie->reg_base = devm_platform_ioremap_resource_byname(pdev, "reg");
> + if (IS_ERR(pcie->reg_base)) {
> + dev_err(dev, "missing \"reg\"\n");
> + return PTR_ERR(pcie->reg_base);
> + }
> + }
> +
> + /* ECAM config space is remapped at glue layer */
> + if (!rc->cfg_base) {
> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
> + rc->cfg_base = devm_pci_remap_cfg_resource(dev, res);
> + if (IS_ERR(rc->cfg_base))
> + return PTR_ERR(rc->cfg_base);
> + rc->cfg_res = res;
> + }
> +
> + ret = cdns_pcie_hpa_host_link_setup(rc);
> + if (ret)
> + return ret;
> +
> + for (bar = RP_BAR0; bar <= RP_NO_BAR; bar++)
> + rc->avail_ib_bar[bar] = true;
> +
> + ret = cdns_pcie_hpa_host_init(rc);
> + if (ret)
> + return ret;
> +
> + if (!bridge->ops)
> + bridge->ops = &cdns_pcie_hpa_host_ops;
> +
> + return pci_host_probe(bridge);
> +}
> +EXPORT_SYMBOL_GPL(cdns_pcie_hpa_host_setup);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Cadence PCIe controller driver");
> +MODULE_AUTHOR("Manikandan K Pillai <mpillai@cadence.com>");
> diff --git a/drivers/pci/controller/cadence/pcie-cadence-hpa.c b/drivers/pci/controller/cadence/pcie-cadence-hpa.c
> new file mode 100644
> index 000000000000..1152d2dcae77
> --- /dev/null
> +++ b/drivers/pci/controller/cadence/pcie-cadence-hpa.c
> @@ -0,0 +1,207 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (c) 2017 Cadence
> +// Cadence PCIe controller driver
> +// Author: Manikandan K Pillai <mpillai@cadence.com>
> +
> +#include <linux/kernel.h>
> +#include <linux/of.h>
> +
> +#include "pcie-cadence.h"
> +
> +bool cdns_pcie_hpa_link_up(struct cdns_pcie *pcie)
> +{
> + u32 pl_reg_val;
> +
> + pl_reg_val = cdns_pcie_hpa_readl(pcie, REG_BANK_IP_REG, CDNS_PCIE_HPA_PHY_DBG_STS_REG0);
> + if (pl_reg_val & GENMASK(0, 0))
> + return true;
> + return false;
> +}
> +
> +int cdns_pcie_hpa_start_link(struct cdns_pcie *pcie)
> +{
> + u32 pl_reg_val;
> +
> + pl_reg_val = cdns_pcie_hpa_readl(pcie, REG_BANK_IP_REG, CDNS_PCIE_HPA_PHY_LAYER_CFG0);
> + pl_reg_val |= CDNS_PCIE_HPA_LINK_TRNG_EN_MASK;
> + cdns_pcie_hpa_writel(pcie, REG_BANK_IP_REG, CDNS_PCIE_HPA_PHY_LAYER_CFG0, pl_reg_val);
> + return 0;
> +}
> +
> +void cdns_pcie_hpa_stop_link(struct cdns_pcie *pcie)
> +{
> + u32 pl_reg_val;
> +
> + pl_reg_val = cdns_pcie_hpa_readl(pcie, REG_BANK_IP_REG, CDNS_PCIE_HPA_PHY_LAYER_CFG0);
> + pl_reg_val &= ~CDNS_PCIE_HPA_LINK_TRNG_EN_MASK;
> + cdns_pcie_hpa_writel(pcie, REG_BANK_IP_REG, CDNS_PCIE_HPA_PHY_LAYER_CFG0, pl_reg_val);
> +}
> +
> +void cdns_pcie_hpa_detect_quiet_min_delay_set(struct cdns_pcie *pcie)
> +{
> + u32 delay = 0x3;
> + u32 ltssm_control_cap;
> +
> + /*
> + * Set the LTSSM Detect Quiet state min. delay to 2ms.
> + */
> + ltssm_control_cap = cdns_pcie_hpa_readl(pcie, REG_BANK_IP_REG,
> + CDNS_PCIE_HPA_PHY_LAYER_CFG0);
> + ltssm_control_cap = ((ltssm_control_cap &
> + ~CDNS_PCIE_HPA_DETECT_QUIET_MIN_DELAY_MASK) |
> + CDNS_PCIE_HPA_DETECT_QUIET_MIN_DELAY(delay));
> +
> + cdns_pcie_hpa_writel(pcie, REG_BANK_IP_REG,
> + CDNS_PCIE_HPA_PHY_LAYER_CFG0, ltssm_control_cap);
> +}
> +EXPORT_SYMBOL_GPL(cdns_pcie_hpa_detect_quiet_min_delay_set);
> +
> +void cdns_pcie_hpa_set_outbound_region(struct cdns_pcie *pcie, u8 busnr, u8 fn,
> + u32 r, bool is_io,
> + u64 cpu_addr, u64 pci_addr, size_t size)
> +{
> + /*
> + * roundup_pow_of_two() returns an unsigned long, which is not suited
> + * for 64bit values.
> + */
> + u64 sz = 1ULL << fls64(size - 1);
> + int nbits = ilog2(sz);
> + u32 addr0, addr1, desc0, desc1, ctrl0;
> +
> + if (nbits < 8)
> + nbits = 8;
> +
> + /* Set the PCI address */
> + addr0 = CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR0_NBITS(nbits) |
> + (lower_32_bits(pci_addr) & GENMASK(31, 8));
> + addr1 = upper_32_bits(pci_addr);
> +
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR0(r), addr0);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR1(r), addr1);
> +
> + /* Set the PCIe header descriptor */
> + if (is_io)
> + desc0 = CDNS_PCIE_HPA_AT_OB_REGION_DESC0_TYPE_IO;
> + else
> + desc0 = CDNS_PCIE_HPA_AT_OB_REGION_DESC0_TYPE_MEM;
> + desc1 = 0;
> + ctrl0 = 0;
> +
> + /*
> + * Whether Bit [26] is set or not inside DESC0 register of the outbound
> + * PCIe descriptor, the PCI function number must be set into
> + * Bits [31:24] of DESC1 anyway.
> + *
> + * In Root Complex mode, the function number is always 0 but in Endpoint
> + * mode, the PCIe controller may support more than one function. This
> + * function number needs to be set properly into the outbound PCIe
> + * descriptor.
> + *
> + * Besides, setting Bit [26] is mandatory when in Root Complex mode:
> + * then the driver must provide the bus, resp. device, number in
> + * Bits [31:24] of DESC1, resp. Bits[23:16] of DESC0. Like the function
> + * number, the device number is always 0 in Root Complex mode.
> + *
> + * However when in Endpoint mode, we can clear Bit [26] of DESC0, hence
> + * the PCIe controller will use the captured values for the bus and
> + * device numbers.
> + */
> + if (pcie->is_rc) {
> + /* The device and function numbers are always 0. */
> + desc1 = CDNS_PCIE_HPA_AT_OB_REGION_DESC1_BUS(busnr) |
> + CDNS_PCIE_HPA_AT_OB_REGION_DESC1_DEVFN(0);
> + ctrl0 = CDNS_PCIE_HPA_AT_OB_REGION_CTRL0_SUPPLY_BUS |
> + CDNS_PCIE_HPA_AT_OB_REGION_CTRL0_SUPPLY_DEV_FN;
> + } else {
> + /*
> + * Use captured values for bus and device numbers but still
> + * need to set the function number.
> + */
> + desc1 |= CDNS_PCIE_HPA_AT_OB_REGION_DESC1_DEVFN(fn);
> + }
> +
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_DESC0(r), desc0);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_DESC1(r), desc1);
> +
> + addr0 = CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) |
> + (lower_32_bits(cpu_addr) & GENMASK(31, 8));
> + addr1 = upper_32_bits(cpu_addr);
> +
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR0(r), addr0);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR1(r), addr1);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_CTRL0(r), ctrl0);
> +}
> +EXPORT_SYMBOL_GPL(cdns_pcie_hpa_set_outbound_region);
> +
> +void cdns_pcie_hpa_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie,
> + u8 busnr, u8 fn,
> + u32 r, u64 cpu_addr)
> +{
> + u32 addr0, addr1, desc0, desc1, ctrl0;
> +
> + desc0 = CDNS_PCIE_HPA_AT_OB_REGION_DESC0_TYPE_NORMAL_MSG;
> + desc1 = 0;
> + ctrl0 = 0;
> +
> + /*
> + * See cdns_pcie_set_outbound_region() comments above.
> + */
> + if (pcie->is_rc) {
> + desc1 = CDNS_PCIE_HPA_AT_OB_REGION_DESC1_BUS(busnr) |
> + CDNS_PCIE_HPA_AT_OB_REGION_DESC1_DEVFN(0);
> + ctrl0 = CDNS_PCIE_HPA_AT_OB_REGION_CTRL0_SUPPLY_BUS |
> + CDNS_PCIE_HPA_AT_OB_REGION_CTRL0_SUPPLY_DEV_FN;
> + } else {
> + desc1 |= CDNS_PCIE_HPA_AT_OB_REGION_DESC1_DEVFN(fn);
> + }
> +
> + addr0 = CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR0_NBITS(17) |
> + (lower_32_bits(cpu_addr) & GENMASK(31, 8));
> + addr1 = upper_32_bits(cpu_addr);
> +
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR0(r), 0);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR1(r), 0);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_DESC0(r), desc0);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_DESC1(r), desc1);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR0(r), addr0);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR1(r), addr1);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_CTRL0(r), ctrl0);
> +}
> +EXPORT_SYMBOL_GPL(cdns_pcie_hpa_set_outbound_region_for_normal_msg);
> +
> +void cdns_pcie_hpa_reset_outbound_region(struct cdns_pcie *pcie, u32 r)
> +{
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR0(r), 0);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_PCI_ADDR1(r), 0);
> +
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_DESC0(r), 0);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_DESC1(r), 0);
> +
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR0(r), 0);
> + cdns_pcie_hpa_writel(pcie, REG_BANK_AXI_SLAVE,
> + CDNS_PCIE_HPA_AT_OB_REGION_CPU_ADDR1(r), 0);
> +}
> +EXPORT_SYMBOL_GPL(cdns_pcie_hpa_reset_outbound_region);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Cadence PCIe controller driver");
> +MODULE_AUTHOR("Manikandan K Pillai <mpillai@cadence.com>");
> diff --git a/drivers/pci/controller/cadence/pcie-cadence-plat.c b/drivers/pci/controller/cadence/pcie-cadence-plat.c
> index ced030cc0fda..6ce18a0cf564 100644
> --- a/drivers/pci/controller/cadence/pcie-cadence-plat.c
> +++ b/drivers/pci/controller/cadence/pcie-cadence-plat.c
> @@ -12,8 +12,7 @@
> #include <linux/pm_runtime.h>
> #include "pcie-cadence.h"
>
> -#define CDNS_PLAT_CPU_TO_BUS_ADDR 0x0FFFFFFF
> -
> +void cdns_pcie_disable_phy(struct cdns_pcie *pcie);
> /**
> * struct cdns_plat_pcie - private data for this PCIe platform driver
> * @pcie: Cadence PCIe controller
> @@ -24,13 +23,8 @@ struct cdns_plat_pcie {
>
> 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,
This stuff doesn't look HPA related. This looks cpu_addr_fixup stuff
that should be in a separate patch.
Most of the stuff below isn't HPA related either. I'm confused.
> + .link_up = cdns_pcie_linkup,
> };
>
> static int cdns_plat_pcie_probe(struct platform_device *pdev)
> @@ -68,6 +62,11 @@ 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;
> + rc->pcie.is_rc = data->is_rc;
> +
> + /* Store the register bank offsets pointer */
> + rc->pcie.cdns_pcie_reg_offsets = data;
> +
> cdns_plat_pcie->pcie = &rc->pcie;
>
> ret = cdns_pcie_init_phy(dev, cdns_plat_pcie->pcie);
> @@ -95,6 +94,11 @@ static int cdns_plat_pcie_probe(struct platform_device *pdev)
>
> ep->pcie.dev = dev;
> ep->pcie.ops = &cdns_plat_ops;
> + ep->pcie.is_rc = data->is_rc;
> +
> + /* Store the register bank offset pointer */
> + ep->pcie.cdns_pcie_reg_offsets = data;
> +
> cdns_plat_pcie->pcie = &ep->pcie;
>
> ret = cdns_pcie_init_phy(dev, cdns_plat_pcie->pcie);
> diff --git a/drivers/pci/controller/cadence/pcie-cadence.c b/drivers/pci/controller/cadence/pcie-cadence.c
> index 51c9bc4eb174..aaf921ea70e0 100644
> --- a/drivers/pci/controller/cadence/pcie-cadence.c
> +++ b/drivers/pci/controller/cadence/pcie-cadence.c
> @@ -9,6 +9,17 @@
>
> #include "pcie-cadence.h"
>
> +bool cdns_pcie_linkup(struct cdns_pcie *pcie)
> +{
> + u32 pl_reg_val;
> +
> + pl_reg_val = cdns_pcie_readl(pcie, CDNS_PCIE_LM_BASE);
> + if (pl_reg_val & GENMASK(0, 0))
> + return true;
> + return false;
> +}
> +EXPORT_SYMBOL_GPL(cdns_pcie_linkup);
> +
> void cdns_pcie_detect_quiet_min_delay_set(struct cdns_pcie *pcie)
> {
> u32 delay = 0x3;
> diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
> index 8048bef215d0..3e0fd6bb21b1 100644
> --- a/drivers/pci/controller/cadence/pcie-cadence.h
> +++ b/drivers/pci/controller/cadence/pcie-cadence.h
> @@ -7,10 +7,12 @@
> #define _PCIE_CADENCE_H
>
> #include <linux/kernel.h>
> +#include <linux/module.h>
> #include <linux/pci.h>
> #include <linux/pci-epf.h>
> #include <linux/phy/phy.h>
> #include <linux/bitfield.h>
> +
Spurious whitespace change. Should have been done when the #includes
below were added.
> #include "pcie-cadence-lga-regs.h"
> #include "pcie-cadence-hpa-regs.h"
>
> @@ -29,6 +31,26 @@ struct cdns_pcie_rp_ib_bar {
> struct cdns_pcie;
> struct cdns_pcie_rc;
>
> +enum cdns_pcie_msg_routing {
> + /* Route to Root Complex */
> + MSG_ROUTING_TO_RC,
> +
> + /* Use Address Routing */
> + MSG_ROUTING_BY_ADDR,
> +
> + /* Use ID Routing */
> + MSG_ROUTING_BY_ID,
> +
> + /* Route as Broadcast Message from Root Complex */
> + MSG_ROUTING_BCAST,
> +
> + /* Local message; terminate at receiver (INTx messages) */
> + MSG_ROUTING_LOCAL,
> +
> + /* Gather & route to Root Complex (PME_TO_Ack message) */
> + MSG_ROUTING_GATHER,
> +};
Looks like duplicates of PCIE_MSG_TYPE_R_RC, etc from
drivers/pci/pci.h
> enum cdns_pcie_reg_bank {
> REG_BANK_RP,
> REG_BANK_IP_REG,
> @@ -43,9 +65,9 @@ enum cdns_pcie_reg_bank {
> };
>
> 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);
> + 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);
> };
>
> @@ -77,6 +99,7 @@ struct cdns_plat_pcie_of_data {
> * struct cdns_pcie - private data for Cadence PCIe controller drivers
> * @reg_base: IO mapped register base
> * @mem_res: start/end offsets in the physical system memory to map PCI accesses
> + * @msg_res: Region for send message to map PCI accesses
> * @dev: PCIe controller
> * @is_rc: tell whether the PCIe controller mode is Root Complex or Endpoint.
> * @phy_count: number of supported PHY devices
> @@ -89,6 +112,7 @@ struct cdns_plat_pcie_of_data {
> struct cdns_pcie {
> void __iomem *reg_base;
> struct resource *mem_res;
> + struct resource *msg_res;
> struct device *dev;
> bool is_rc;
> int phy_count;
> @@ -111,6 +135,7 @@ struct cdns_pcie {
> * available
> * @quirk_retrain_flag: Retrain link as quirk for PCIe Gen2
> * @quirk_detect_quiet_flag: LTSSM Detect Quiet min delay set as quirk
> + * @ecam_support_flag: Whether the ECAM flag is supported
> */
> struct cdns_pcie_rc {
> struct cdns_pcie pcie;
> @@ -121,6 +146,8 @@ struct cdns_pcie_rc {
> bool avail_ib_bar[CDNS_PCIE_RP_MAX_IB];
> unsigned int quirk_retrain_flag:1;
> unsigned int quirk_detect_quiet_flag:1;
> + unsigned int ecam_support_flag:1;
> + unsigned int no_inbound_flag:1;
> };
>
> /**
> @@ -304,6 +331,29 @@ static inline u16 cdns_pcie_rp_readw(struct cdns_pcie *pcie, u32 reg)
> return cdns_pcie_read_sz(addr, 0x2);
> }
>
> +static inline void cdns_pcie_hpa_rp_writeb(struct cdns_pcie *pcie,
> + u32 reg, u8 value)
> +{
> + void __iomem *addr = pcie->reg_base + CDNS_PCIE_HPA_RP_BASE + reg;
> +
> + cdns_pcie_write_sz(addr, 0x1, value);
> +}
> +
> +static inline void cdns_pcie_hpa_rp_writew(struct cdns_pcie *pcie,
> + u32 reg, u16 value)
> +{
> + void __iomem *addr = pcie->reg_base + CDNS_PCIE_HPA_RP_BASE + reg;
> +
> + cdns_pcie_write_sz(addr, 0x2, value);
> +}
> +
> +static inline u16 cdns_pcie_hpa_rp_readw(struct cdns_pcie *pcie, u32 reg)
> +{
> + void __iomem *addr = pcie->reg_base + CDNS_PCIE_HPA_RP_BASE + reg;
> +
> + return cdns_pcie_read_sz(addr, 0x2);
> +}
> +
> /* Endpoint Function register access */
> static inline void cdns_pcie_ep_fn_writeb(struct cdns_pcie *pcie, u8 fn,
> u32 reg, u8 value)
> @@ -368,6 +418,7 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc);
> void cdns_pcie_host_disable(struct cdns_pcie_rc *rc);
> void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
> int where);
> +int cdns_pcie_hpa_host_setup(struct cdns_pcie_rc *rc);
> #else
> static inline int cdns_pcie_host_link_setup(struct cdns_pcie_rc *rc)
> {
> @@ -384,6 +435,11 @@ static inline int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
> return 0;
> }
>
> +static inline int cdns_pcie_hpa_host_setup(struct cdns_pcie_rc *rc)
> +{
> + return 0;
> +}
> +
> static inline void cdns_pcie_host_disable(struct cdns_pcie_rc *rc)
> {
> }
> @@ -398,17 +454,25 @@ static inline void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int d
> #if IS_ENABLED(CONFIG_PCIE_CADENCE_EP)
> int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep);
> void cdns_pcie_ep_disable(struct cdns_pcie_ep *ep);
> +int cdns_pcie_hpa_ep_setup(struct cdns_pcie_ep *ep);
> #else
> static inline int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
> {
> return 0;
> }
>
> +static inline int cdns_pcie_hpa_ep_setup(struct cdns_pcie_ep *ep)
> +{
> + return 0;
> +}
> +
> static inline void cdns_pcie_ep_disable(struct cdns_pcie_ep *ep)
> {
> }
> #endif
> -
> +bool cdns_pcie_linkup(struct cdns_pcie *pcie);
> +int cdns_pcie_host_wait_for_link(struct cdns_pcie *pcie);
> +int cdns_pcie_host_start_link(struct cdns_pcie_rc *rc);
> void cdns_pcie_detect_quiet_min_delay_set(struct cdns_pcie *pcie);
> void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 busnr, u8 fn,
> u32 r, bool is_io,
> @@ -421,6 +485,25 @@ 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);
>
> +void cdns_pcie_hpa_detect_quiet_min_delay_set(struct cdns_pcie *pcie);
> +void cdns_pcie_hpa_set_outbound_region(struct cdns_pcie *pcie, u8 busnr, u8 fn,
> + u32 r, bool is_io,
> + u64 cpu_addr, u64 pci_addr, size_t size);
> +void cdns_pcie_hpa_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie,
> + u8 busnr, u8 fn,
> + u32 r, u64 cpu_addr);
> +void cdns_pcie_hpa_reset_outbound_region(struct cdns_pcie *pcie, u32 r);
> +int cdns_pcie_hpa_host_link_setup(struct cdns_pcie_rc *rc);
> +int cdns_pcie_hpa_host_init(struct cdns_pcie_rc *rc);
> +void __iomem *cdns_pci_hpa_map_bus(struct pci_bus *bus, unsigned int devfn,
> + int where);
> +int cdns_pcie_hpa_host_wait_for_link(struct cdns_pcie *pcie);
> +int cdns_pcie_hpa_host_start_link(struct cdns_pcie_rc *rc);
> +
> +int cdns_pcie_hpa_start_link(struct cdns_pcie *pcie);
> +void cdns_pcie_hpa_stop_link(struct cdns_pcie *pcie);
> +bool cdns_pcie_hpa_link_up(struct cdns_pcie *pcie);
> +
> extern const struct dev_pm_ops cdns_pcie_pm_ops;
>
> #endif /* _PCIE_CADENCE_H */
> --
> 2.49.0
>
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v7 09/13] PCI: Add Cix Technology Vendor and Device ID
2025-08-13 4:23 ` [PATCH v7 09/13] PCI: Add Cix Technology Vendor and Device ID hans.zhang
@ 2025-08-14 22:23 ` Bjorn Helgaas
2025-08-15 3:32 ` Peter Chen
0 siblings, 1 reply; 40+ messages in thread
From: Bjorn Helgaas @ 2025-08-14 22:23 UTC (permalink / raw)
To: hans.zhang
Cc: bhelgaas, lpieralisi, kw, mani, robh, kwilczynski, krzk+dt,
conor+dt, mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel
On Wed, Aug 13, 2025 at 12:23:27PM +0800, hans.zhang@cixtech.com wrote:
> From: Hans Zhang <hans.zhang@cixtech.com>
>
> Add Cixtech P1 (internal name sky1) as a vendor and device ID for PCI
> devices. This ID will be used by the CIX Sky1 PCIe host controller driver.
>
> Signed-off-by: Hans Zhang <hans.zhang@cixtech.com>
> ---
> include/linux/pci_ids.h | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
> index 92ffc4373f6d..24b04d085920 100644
> --- a/include/linux/pci_ids.h
> +++ b/include/linux/pci_ids.h
> @@ -2631,6 +2631,9 @@
>
> #define PCI_VENDOR_ID_CXL 0x1e98
>
> +#define PCI_VENDOR_ID_CIX 0x1f6c
> +#define PCI_DEVICE_ID_CIX_SKY1 0x0001
I only see these used once in this series, so they probably should be
defined in the file that uses them, per the comment at the top of this
file.
Also, https://pcisig.com/membership/member-companies?combine=0x1f6c
doesn't show 0x1f6c as assigned to CIX. That database often seems
incomplete, but please double check to make sure the ID is actually
reserved.
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v7 10/13] PCI: sky1: Add PCIe host support for CIX Sky1
2025-08-13 4:23 ` [PATCH v7 10/13] PCI: sky1: Add PCIe host support for CIX Sky1 hans.zhang
2025-08-13 19:16 ` Krzysztof Kozlowski
@ 2025-08-14 22:46 ` Bjorn Helgaas
2025-08-15 7:53 ` Hans Zhang
1 sibling, 1 reply; 40+ messages in thread
From: Bjorn Helgaas @ 2025-08-14 22:46 UTC (permalink / raw)
To: hans.zhang
Cc: bhelgaas, lpieralisi, kw, mani, robh, kwilczynski, krzk+dt,
conor+dt, mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel
On Wed, Aug 13, 2025 at 12:23:28PM +0800, hans.zhang@cixtech.com wrote:
> From: Hans Zhang <hans.zhang@cixtech.com>
>
> Add driver for the CIX Sky1 SoC PCIe Gen4 16 GT/s controller based
> on the Cadence PCIe core.
>
> Supports MSI/MSI-x via GICv3, Single Virtual Channel, Single Function.
> +config PCI_SKY1_HOST
> + tristate "CIX SKY1 PCIe controller (host mode)"
> + depends on OF
> + select PCIE_CADENCE_HOST
> + select PCI_ECAM
> + help
> + Say Y here if you want to support the CIX SKY1 PCIe platform
> + controller in host mode. CIX SKY1 PCIe controller uses Cadence HPA(High
> + Performance Architecture IP[Second generation of cadence PCIe IP])
> +
> + This driver requires Cadence PCIe core infrastructure (PCIE_CADENCE_HOST)
> + and hardware platform adaptation layer to function.
Reorder so this menu entry appears in alphabetical order by vendor.
Add space in "HPA(..".
Add space in "IP[Second ..."
s/cadence PCIe IP/Cadence PCIe IP/
Rewrap so help text fits in 80 columns when displayed by menuconfig.
> +++ b/drivers/pci/controller/cadence/Makefile
> +++ b/drivers/pci/controller/cadence/pci-sky1.c
> @@ -0,0 +1,294 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * PCIe controller driver for CIX's sky1 SoCs
> + *
> + * Author: Hans Zhang <hans.zhang@cixtech.com>
> + */
The typical comment style, thank you :)
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/pci.h>
> +#include <linux/pci-ecam.h>
> +#include <linux/pci_ids.h>
> +
> +#include "pcie-cadence.h"
> +#include "pcie-cadence-host-common.h"
> +
> +#define STRAP_REG(n) ((n) * 0x04)
> +#define STATUS_REG(n) ((n) * 0x04)
> +
> +#define RCSU_STRAP_REG 0x300
> +#define RCSU_STATUS_REG 0x400
> +
> +#define SKY1_IP_REG_BANK_OFFSET 0x1000
> +#define SKY1_IP_CFG_CTRL_REG_BANK_OFFSET 0x4c00
> +#define SKY1_IP_AXI_MASTER_COMMON_OFFSET 0xf000
> +#define SKY1_AXI_SLAVE_OFFSET 0x9000
> +#define SKY1_AXI_MASTER_OFFSET 0xb000
> +#define SKY1_AXI_HLS_REGISTERS_OFFSET 0xc000
> +#define SKY1_AXI_RAS_REGISTERS_OFFSET 0xe000
> +#define SKY1_DTI_REGISTERS_OFFSET 0xd000
Indent the values to line up.
Consider dropping "_OFFSET".
> +#define IP_REG_I_DBG_STS_0 0x420
> +
> +#define LINK_TRAINING_ENABLE BIT(0)
> +#define LINK_COMPLETE BIT(0)
Define next to the offset of the register that contains these.
Consider naming them to relate to the register.
> +enum cix_soc_type {
> + CIX_SKY1,
> +};
> +
> +struct sky1_pcie_data {
> + struct cdns_plat_pcie_of_data reg_off;
Weird name for this member. cdns_plat_pcie_of_data contains more than
just offsets.
> + enum cix_soc_type soc_type;
> +};
> +
> +struct sky1_pcie {
> + struct device *dev;
> + const struct sky1_pcie_data *data;
> + struct cdns_pcie *cdns_pcie;
Typically first in the driver struct. Also cdns_pcie already contains
a struct device *; do you need another?
> + struct cdns_pcie_rc *cdns_pcie_rc;
> +
> + struct resource *cfg_res;
> + struct resource *msg_res;
> + struct pci_config_window *cfg;
> + void __iomem *rcsu_base;
> + void __iomem *strap_base;
> + void __iomem *status_base;
> + void __iomem *reg_base;
> + void __iomem *cfg_base;
> + void __iomem *msg_base;
> +};
> +
> +static void sky1_pcie_clear_and_set_dword(void __iomem *addr, u32 clear,
> + u32 set)
> +{
> + u32 val;
> +
> + val = readl(addr);
> + val &= ~clear;
> + val |= set;
> + writel(val, addr);
Nothing specific to sky1 here. Find an existing interface or copy the
style of other drivers. Surely other drivers do something similar,
but "git grep clear_and_set_dword drivers/pci/controller/" finds
nothing.
> +static int sky1_pcie_parse_mem(struct sky1_pcie *pcie)
> +{
> + struct device *dev = pcie->dev;
> + struct platform_device *pdev = to_platform_device(dev);
> + struct resource *res;
> + void __iomem *base;
> + int ret = 0;
> +
> + base = devm_platform_ioremap_resource_byname(pdev, "reg");
> + if (IS_ERR(base)) {
> + dev_err(dev, "Parse \"reg\" resource err\n");
> + return PTR_ERR(base);
> + }
> + pcie->reg_base = base;
> +
> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
> + if (!res) {
> + dev_err(dev, "Parse \"cfg\" resource err\n");
> + return -ENXIO;
> + }
> + pcie->cfg_res = res;
> +
> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rcsu");
> + if (!res) {
> + dev_err(dev, "Parse \"rcsu\" resource err\n");
> + return -ENXIO;
> + }
> + pcie->rcsu_base = devm_ioremap(dev, res->start, resource_size(res));
> + if (!pcie->rcsu_base) {
> + dev_err(dev, "ioremap failed for resource %pR\n", res);
> + return -ENOMEM;
> + }
> +
> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "msg");
> + if (!res) {
> + dev_err(dev, "Parse \"msg\" resource err\n");
> + return -ENXIO;
> + }
> + pcie->msg_res = res;
> + pcie->msg_base = devm_ioremap(dev, res->start, resource_size(res));
> + if (!pcie->msg_base) {
> + dev_err(dev, "ioremap failed for resource %pR\n", res);
> + return -ENOMEM;
> + }
> +
> + return ret;
"ret" is never used; remove it and just "return 0" here.
> +}
> +
> +static int sky1_pcie_parse_property(struct platform_device *pdev,
> + struct sky1_pcie *pcie)
Find a similar function in other drivers and copy the name.
"git grep parse_property drivers/pci/controller/" finds nothing.
> +{
> + int ret = 0;
> +
> + ret = sky1_pcie_parse_mem(pcie);
> + if (ret < 0)
> + return ret;
> +
> + sky1_pcie_init_bases(pcie);
> +
> + return ret;
Drop "ret" and return 0 here.
> +}
> +
> +static int sky1_pcie_start_link(struct cdns_pcie *cdns_pcie)
> +{
> + struct sky1_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
> +
> + sky1_pcie_clear_and_set_dword(pcie->strap_base + STRAP_REG(1),
> + 0, LINK_TRAINING_ENABLE);
> +
> + return 0;
> +}
> +
> +static void sky1_pcie_stop_link(struct cdns_pcie *cdns_pcie)
> +{
> + struct sky1_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
> +
> + sky1_pcie_clear_and_set_dword(pcie->strap_base + STRAP_REG(1),
> + LINK_TRAINING_ENABLE, 0);
> +}
> +
> +
> +static bool sky1_pcie_link_up(struct cdns_pcie *cdns_pcie)
> +{
> + u32 val;
> +
> + val = cdns_pcie_hpa_readl(cdns_pcie, REG_BANK_IP_REG,
> + IP_REG_I_DBG_STS_0);
> + return val & LINK_COMPLETE;
> +}
> +
> +static const struct cdns_pcie_ops sky1_pcie_ops = {
> + .start_link = sky1_pcie_start_link,
> + .stop_link = sky1_pcie_stop_link,
> + .link_up = sky1_pcie_link_up,
> +};
> +
> +static int sky1_pcie_probe(struct platform_device *pdev)
> +{
> + const struct sky1_pcie_data *data;
> + struct device *dev = &pdev->dev;
> + struct pci_host_bridge *bridge;
> + struct cdns_pcie *cdns_pcie;
> + struct resource_entry *bus;
> + struct cdns_pcie_rc *rc;
> + struct sky1_pcie *pcie;
> + int ret;
> +
> + pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
> + if (!pcie)
> + return -ENOMEM;
> +
> + data = of_device_get_match_data(dev);
> + if (!data)
> + return -EINVAL;
> +
> + pcie->data = data;
> + pcie->dev = dev;
> + dev_set_drvdata(dev, pcie);
> +
> + bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
> + if (!bridge)
> + return -ENOMEM;
> +
> + bus = resource_list_first_type(&bridge->windows, IORESOURCE_BUS);
> + if (!bus)
> + return -ENODEV;
Maybe put this near the code that uses it instead of sticking the
unrelated sky1_pcie_parse_property() in the middle?
> + ret = sky1_pcie_parse_property(pdev, pcie);
> + if (ret < 0)
> + return -ENXIO;
> +
> + pcie->cfg = pci_ecam_create(dev, pcie->cfg_res, bus->res,
> + &pci_generic_ecam_ops);
> + if (IS_ERR(pcie->cfg))
> + return PTR_ERR(pcie->cfg);
> +
> + bridge->ops = (struct pci_ops *)&pci_generic_ecam_ops.pci_ops;
> + rc = pci_host_bridge_priv(bridge);
> + rc->ecam_support_flag = 1;
> + rc->cfg_base = pcie->cfg->win;
> + rc->cfg_res = &pcie->cfg->res;
> +
> + cdns_pcie = &rc->pcie;
> + cdns_pcie->dev = dev;
> + cdns_pcie->ops = &sky1_pcie_ops;
> + cdns_pcie->reg_base = pcie->reg_base;
> + cdns_pcie->msg_res = pcie->msg_res;
> + cdns_pcie->cdns_pcie_reg_offsets = &data->reg_off;
> + cdns_pcie->is_rc = data->reg_off.is_rc;
> +
> + pcie->cdns_pcie = cdns_pcie;
> + pcie->cdns_pcie_rc = rc;
> + pcie->cfg_base = rc->cfg_base;
> + bridge->sysdata = pcie->cfg;
> +
> + if (data->soc_type == CIX_SKY1) {
> + rc->vendor_id = PCI_VENDOR_ID_CIX;
> + rc->device_id = PCI_DEVICE_ID_CIX_SKY1;
> + rc->no_inbound_flag = 1;
> + }
> +
> + ret = cdns_pcie_hpa_host_setup(rc);
> + if (ret < 0) {
> + pci_ecam_free(pcie->cfg);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static const struct sky1_pcie_data sky1_pcie_rc_data = {
> + .reg_off = {
> + .is_rc = true,
> + .ip_reg_bank_offset = SKY1_IP_REG_BANK_OFFSET,
> + .ip_cfg_ctrl_reg_offset = SKY1_IP_CFG_CTRL_REG_BANK_OFFSET,
> + .axi_mstr_common_offset = SKY1_IP_AXI_MASTER_COMMON_OFFSET,
> + .axi_slave_offset = SKY1_AXI_SLAVE_OFFSET,
> + .axi_master_offset = SKY1_AXI_MASTER_OFFSET,
> + .axi_hls_offset = SKY1_AXI_HLS_REGISTERS_OFFSET,
> + .axi_ras_offset = SKY1_AXI_RAS_REGISTERS_OFFSET,
> + .axi_dti_offset = SKY1_DTI_REGISTERS_OFFSET,
> + },
> + .soc_type = CIX_SKY1,
> +};
> +
> +static const struct of_device_id of_sky1_pcie_match[] = {
> + {
> + .compatible = "cix,sky1-pcie-host",
> + .data = &sky1_pcie_rc_data,
> + },
> + {},
> +};
> +
> +static void sky1_pcie_remove(struct platform_device *pdev)
> +{
> + struct sky1_pcie *pcie = platform_get_drvdata(pdev);
> +
> + pci_ecam_free(pcie->cfg);
> +}
> +
> +static struct platform_driver sky1_pcie_driver = {
> + .probe = sky1_pcie_probe,
> + .remove = sky1_pcie_remove,
> + .driver = {
> + .name = "sky1-pcie",
> + .of_match_table = of_sky1_pcie_match,
> + },
> +};
> +module_platform_driver(sky1_pcie_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("PCIe controller driver for CIX's sky1 SoCs");
> +MODULE_AUTHOR("Hans Zhang <hans.zhang@cixtech.com>");
> --
> 2.49.0
>
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v7 09/13] PCI: Add Cix Technology Vendor and Device ID
2025-08-14 22:23 ` Bjorn Helgaas
@ 2025-08-15 3:32 ` Peter Chen
2025-08-15 14:27 ` Bjorn Helgaas
0 siblings, 1 reply; 40+ messages in thread
From: Peter Chen @ 2025-08-15 3:32 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: hans.zhang, bhelgaas, lpieralisi, kw, mani, robh, kwilczynski,
krzk+dt, conor+dt, mpillai, fugang.duan, guoyin.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel
On 25-08-14 17:23:58, Bjorn Helgaas wrote:
> EXTERNAL EMAIL
>
> On Wed, Aug 13, 2025 at 12:23:27PM +0800, hans.zhang@cixtech.com wrote:
> > From: Hans Zhang <hans.zhang@cixtech.com>
> >
> > Add Cixtech P1 (internal name sky1) as a vendor and device ID for PCI
> > devices. This ID will be used by the CIX Sky1 PCIe host controller driver.
> >
> > Signed-off-by: Hans Zhang <hans.zhang@cixtech.com>
> > ---
> > include/linux/pci_ids.h | 3 +++
> > 1 file changed, 3 insertions(+)
> >
> > diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
> > index 92ffc4373f6d..24b04d085920 100644
> > --- a/include/linux/pci_ids.h
> > +++ b/include/linux/pci_ids.h
> > @@ -2631,6 +2631,9 @@
> >
> > #define PCI_VENDOR_ID_CXL 0x1e98
> >
> > +#define PCI_VENDOR_ID_CIX 0x1f6c
> > +#define PCI_DEVICE_ID_CIX_SKY1 0x0001
>
> I only see these used once in this series, so they probably should be
> defined in the file that uses them, per the comment at the top of this
> file.
>
> Also, https://pcisig.com/membership/member-companies?combine=0x1f6c
> doesn't show 0x1f6c as assigned to CIX. That database often seems
> incomplete, but please double check to make sure the ID is actually
> reserved.
Hi Bjorn,
Would you please check below:
https://pcisig.com/membership/member-companies?combine=1f6c
--
Best regards,
Peter
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v7 10/13] PCI: sky1: Add PCIe host support for CIX Sky1
2025-08-14 22:46 ` Bjorn Helgaas
@ 2025-08-15 7:53 ` Hans Zhang
0 siblings, 0 replies; 40+ messages in thread
From: Hans Zhang @ 2025-08-15 7:53 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: bhelgaas, lpieralisi, kw, mani, robh, kwilczynski, krzk+dt,
conor+dt, mpillai, fugang.duan, guoyin.chen, peter.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel
On 2025/8/15 06:46, Bjorn Helgaas wrote:
> EXTERNAL EMAIL
>
> On Wed, Aug 13, 2025 at 12:23:28PM +0800, hans.zhang@cixtech.com wrote:
>> From: Hans Zhang <hans.zhang@cixtech.com>
>>
>> Add driver for the CIX Sky1 SoC PCIe Gen4 16 GT/s controller based
>> on the Cadence PCIe core.
>>
>> Supports MSI/MSI-x via GICv3, Single Virtual Channel, Single Function.
>
>> +config PCI_SKY1_HOST
>> + tristate "CIX SKY1 PCIe controller (host mode)"
>> + depends on OF
>> + select PCIE_CADENCE_HOST
>> + select PCI_ECAM
>> + help
>> + Say Y here if you want to support the CIX SKY1 PCIe platform
>> + controller in host mode. CIX SKY1 PCIe controller uses Cadence HPA(High
>> + Performance Architecture IP[Second generation of cadence PCIe IP])
>> +
>> + This driver requires Cadence PCIe core infrastructure (PCIE_CADENCE_HOST)
>> + and hardware platform adaptation layer to function.
>
> Reorder so this menu entry appears in alphabetical order by vendor.
>
> Add space in "HPA(..".
>
> Add space in "IP[Second ..."
>
> s/cadence PCIe IP/Cadence PCIe IP/
>
> Rewrap so help text fits in 80 columns when displayed by menuconfig.
Dear Bjorn,
Thank you very much for your reply. Will change.
>
>> +++ b/drivers/pci/controller/cadence/Makefile
>> +++ b/drivers/pci/controller/cadence/pci-sky1.c
>> @@ -0,0 +1,294 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * PCIe controller driver for CIX's sky1 SoCs
>> + *
>> + * Author: Hans Zhang <hans.zhang@cixtech.com>
>> + */
>
> The typical comment style, thank you :)
>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include <linux/of_device.h>
>> +#include <linux/pci.h>
>> +#include <linux/pci-ecam.h>
>> +#include <linux/pci_ids.h>
>> +
>> +#include "pcie-cadence.h"
>> +#include "pcie-cadence-host-common.h"
>> +
>> +#define STRAP_REG(n) ((n) * 0x04)
>> +#define STATUS_REG(n) ((n) * 0x04)
>> +
>> +#define RCSU_STRAP_REG 0x300
>> +#define RCSU_STATUS_REG 0x400
>> +
>> +#define SKY1_IP_REG_BANK_OFFSET 0x1000
>> +#define SKY1_IP_CFG_CTRL_REG_BANK_OFFSET 0x4c00
>> +#define SKY1_IP_AXI_MASTER_COMMON_OFFSET 0xf000
>> +#define SKY1_AXI_SLAVE_OFFSET 0x9000
>> +#define SKY1_AXI_MASTER_OFFSET 0xb000
>> +#define SKY1_AXI_HLS_REGISTERS_OFFSET 0xc000
>> +#define SKY1_AXI_RAS_REGISTERS_OFFSET 0xe000
>> +#define SKY1_DTI_REGISTERS_OFFSET 0xd000
>
> Indent the values to line up.
>
> Consider dropping "_OFFSET".
Will change.
>
>> +#define IP_REG_I_DBG_STS_0 0x420
>> +
>> +#define LINK_TRAINING_ENABLE BIT(0)
>> +#define LINK_COMPLETE BIT(0)
>
> Define next to the offset of the register that contains these.
> Consider naming them to relate to the register.
>
All of our registers are RCSU (Remote CIX System Unit registers.), and
they are named like this: I moved it below this.
#define STRAP_REG(n) ((n) * 0x04)
#define STATUS_REG(n) ((n) * 0x04)
>> +enum cix_soc_type {
>> + CIX_SKY1,
>> +};
>> +
>> +struct sky1_pcie_data {
>> + struct cdns_plat_pcie_of_data reg_off;
>
> Weird name for this member. cdns_plat_pcie_of_data contains more than
> just offsets.
We are considering deleting cdns_plat_pcie_of_data. Krzysztof also
provided a review opinion, intending to directly assign the register
offset value in the probe.
>
>> + enum cix_soc_type soc_type;
>> +};
>> +
>> +struct sky1_pcie {
>> + struct device *dev;
>> + const struct sky1_pcie_data *data;
>> + struct cdns_pcie *cdns_pcie;
>
> Typically first in the driver struct. Also cdns_pcie already contains
> a struct device *; do you need another?
I checked and it's indeed possible to delete it by using "dev" in cdns_pcie.
>
>> + struct cdns_pcie_rc *cdns_pcie_rc;
>> +
>> + struct resource *cfg_res;
>> + struct resource *msg_res;
>> + struct pci_config_window *cfg;
>> + void __iomem *rcsu_base;
>> + void __iomem *strap_base;
>> + void __iomem *status_base;
>> + void __iomem *reg_base;
>> + void __iomem *cfg_base;
>> + void __iomem *msg_base;
>> +};
>> +
>> +static void sky1_pcie_clear_and_set_dword(void __iomem *addr, u32 clear,
>> + u32 set)
>> +{
>> + u32 val;
>> +
>> + val = readl(addr);
>> + val &= ~clear;
>> + val |= set;
>> + writel(val, addr);
>
> Nothing specific to sky1 here. Find an existing interface or copy the
> style of other drivers. Surely other drivers do something similar,
> but "git grep clear_and_set_dword drivers/pci/controller/" finds
> nothing.
My original intention was for the future upstream, as there are many
repetitive read and write registers. Then I'll delete it first.
>
>> +static int sky1_pcie_parse_mem(struct sky1_pcie *pcie)
>> +{
>> + struct device *dev = pcie->dev;
>> + struct platform_device *pdev = to_platform_device(dev);
>> + struct resource *res;
>> + void __iomem *base;
>> + int ret = 0;
>> +
>> + base = devm_platform_ioremap_resource_byname(pdev, "reg");
>> + if (IS_ERR(base)) {
>> + dev_err(dev, "Parse \"reg\" resource err\n");
>> + return PTR_ERR(base);
>> + }
>> + pcie->reg_base = base;
>> +
>> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
>> + if (!res) {
>> + dev_err(dev, "Parse \"cfg\" resource err\n");
>> + return -ENXIO;
>> + }
>> + pcie->cfg_res = res;
>> +
>> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rcsu");
>> + if (!res) {
>> + dev_err(dev, "Parse \"rcsu\" resource err\n");
>> + return -ENXIO;
>> + }
>> + pcie->rcsu_base = devm_ioremap(dev, res->start, resource_size(res));
>> + if (!pcie->rcsu_base) {
>> + dev_err(dev, "ioremap failed for resource %pR\n", res);
>> + return -ENOMEM;
>> + }
>> +
>> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "msg");
>> + if (!res) {
>> + dev_err(dev, "Parse \"msg\" resource err\n");
>> + return -ENXIO;
>> + }
>> + pcie->msg_res = res;
>> + pcie->msg_base = devm_ioremap(dev, res->start, resource_size(res));
>> + if (!pcie->msg_base) {
>> + dev_err(dev, "ioremap failed for resource %pR\n", res);
>> + return -ENOMEM;
>> + }
>> +
>> + return ret;
>
> "ret" is never used; remove it and just "return 0" here.
Will change.
>
>> +}
>> +
>> +static int sky1_pcie_parse_property(struct platform_device *pdev,
>> + struct sky1_pcie *pcie)
>
> Find a similar function in other drivers and copy the name.
> "git grep parse_property drivers/pci/controller/" finds nothing.
Will change.
>
>> +{
>> + int ret = 0;
>> +
>> + ret = sky1_pcie_parse_mem(pcie);
>> + if (ret < 0)
>> + return ret;
>> +
>> + sky1_pcie_init_bases(pcie);
>> +
>> + return ret;
>
> Drop "ret" and return 0 here.
Will change.
>
>> +}
>> +
>> +static int sky1_pcie_start_link(struct cdns_pcie *cdns_pcie)
>> +{
>> + struct sky1_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
>> +
>> + sky1_pcie_clear_and_set_dword(pcie->strap_base + STRAP_REG(1),
>> + 0, LINK_TRAINING_ENABLE);
>> +
>> + return 0;
>> +}
>> +
>> +static void sky1_pcie_stop_link(struct cdns_pcie *cdns_pcie)
>> +{
>> + struct sky1_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
>> +
>> + sky1_pcie_clear_and_set_dword(pcie->strap_base + STRAP_REG(1),
>> + LINK_TRAINING_ENABLE, 0);
>> +}
>> +
>> +
>> +static bool sky1_pcie_link_up(struct cdns_pcie *cdns_pcie)
>> +{
>> + u32 val;
>> +
>> + val = cdns_pcie_hpa_readl(cdns_pcie, REG_BANK_IP_REG,
>> + IP_REG_I_DBG_STS_0);
>> + return val & LINK_COMPLETE;
>> +}
>> +
>> +static const struct cdns_pcie_ops sky1_pcie_ops = {
>> + .start_link = sky1_pcie_start_link,
>> + .stop_link = sky1_pcie_stop_link,
>> + .link_up = sky1_pcie_link_up,
>> +};
>> +
>> +static int sky1_pcie_probe(struct platform_device *pdev)
>> +{
>> + const struct sky1_pcie_data *data;
>> + struct device *dev = &pdev->dev;
>> + struct pci_host_bridge *bridge;
>> + struct cdns_pcie *cdns_pcie;
>> + struct resource_entry *bus;
>> + struct cdns_pcie_rc *rc;
>> + struct sky1_pcie *pcie;
>> + int ret;
>> +
>> + pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
>> + if (!pcie)
>> + return -ENOMEM;
>> +
>> + data = of_device_get_match_data(dev);
>> + if (!data)
>> + return -EINVAL;
>> +
>> + pcie->data = data;
>> + pcie->dev = dev;
>> + dev_set_drvdata(dev, pcie);
>> +
>> + bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
>> + if (!bridge)
>> + return -ENOMEM;
>> +
>> + bus = resource_list_first_type(&bridge->windows, IORESOURCE_BUS);
>> + if (!bus)
>> + return -ENODEV;
>
> Maybe put this near the code that uses it instead of sticking the
> unrelated sky1_pcie_parse_property() in the middle?
Will change.
>
>> + ret = sky1_pcie_parse_property(pdev, pcie);
>> + if (ret < 0)
>> + return -ENXIO;
>> +
>> + pcie->cfg = pci_ecam_create(dev, pcie->cfg_res, bus->res,
>> + &pci_generic_ecam_ops);
>> + if (IS_ERR(pcie->cfg))
>> + return PTR_ERR(pcie->cfg);
>> +
>> + bridge->ops = (struct pci_ops *)&pci_generic_ecam_ops.pci_ops;
>> + rc = pci_host_bridge_priv(bridge);
>> + rc->ecam_support_flag = 1;
>> + rc->cfg_base = pcie->cfg->win;
>> + rc->cfg_res = &pcie->cfg->res;
>> +
>> + cdns_pcie = &rc->pcie;
>> + cdns_pcie->dev = dev;
>> + cdns_pcie->ops = &sky1_pcie_ops;
>> + cdns_pcie->reg_base = pcie->reg_base;
>> + cdns_pcie->msg_res = pcie->msg_res;
>> + cdns_pcie->cdns_pcie_reg_offsets = &data->reg_off;
>> + cdns_pcie->is_rc = data->reg_off.is_rc;
>> +
>> + pcie->cdns_pcie = cdns_pcie;
>> + pcie->cdns_pcie_rc = rc;
>> + pcie->cfg_base = rc->cfg_base;
>> + bridge->sysdata = pcie->cfg;
>> +
>> + if (data->soc_type == CIX_SKY1) {
>> + rc->vendor_id = PCI_VENDOR_ID_CIX;
>> + rc->device_id = PCI_DEVICE_ID_CIX_SKY1;
>> + rc->no_inbound_flag = 1;
>> + }
>> +
>> + ret = cdns_pcie_hpa_host_setup(rc);
>> + if (ret < 0) {
>> + pci_ecam_free(pcie->cfg);
>> + return ret;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static const struct sky1_pcie_data sky1_pcie_rc_data = {
>> + .reg_off = {
>> + .is_rc = true,
>> + .ip_reg_bank_offset = SKY1_IP_REG_BANK_OFFSET,
>> + .ip_cfg_ctrl_reg_offset = SKY1_IP_CFG_CTRL_REG_BANK_OFFSET,
>> + .axi_mstr_common_offset = SKY1_IP_AXI_MASTER_COMMON_OFFSET,
>> + .axi_slave_offset = SKY1_AXI_SLAVE_OFFSET,
>> + .axi_master_offset = SKY1_AXI_MASTER_OFFSET,
>> + .axi_hls_offset = SKY1_AXI_HLS_REGISTERS_OFFSET,
>> + .axi_ras_offset = SKY1_AXI_RAS_REGISTERS_OFFSET,
>> + .axi_dti_offset = SKY1_DTI_REGISTERS_OFFSET,
>> + },
>> + .soc_type = CIX_SKY1,
>> +};
>> +
>> +static const struct of_device_id of_sky1_pcie_match[] = {
>> + {
>> + .compatible = "cix,sky1-pcie-host",
>> + .data = &sky1_pcie_rc_data,
>> + },
>> + {},
>> +};
>> +
>> +static void sky1_pcie_remove(struct platform_device *pdev)
>> +{
>> + struct sky1_pcie *pcie = platform_get_drvdata(pdev);
>> +
>> + pci_ecam_free(pcie->cfg);
>> +}
>> +
>> +static struct platform_driver sky1_pcie_driver = {
>> + .probe = sky1_pcie_probe,
>> + .remove = sky1_pcie_remove,
>> + .driver = {
>> + .name = "sky1-pcie",
>> + .of_match_table = of_sky1_pcie_match,
>> + },
>> +};
>> +module_platform_driver(sky1_pcie_driver);
>> +
>> +MODULE_LICENSE("GPL");
>> +MODULE_DESCRIPTION("PCIe controller driver for CIX's sky1 SoCs");
>> +MODULE_AUTHOR("Hans Zhang <hans.zhang@cixtech.com>");
>> --
>> 2.49.0
>>
Best regards,
Hans
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v7 09/13] PCI: Add Cix Technology Vendor and Device ID
2025-08-15 3:32 ` Peter Chen
@ 2025-08-15 14:27 ` Bjorn Helgaas
0 siblings, 0 replies; 40+ messages in thread
From: Bjorn Helgaas @ 2025-08-15 14:27 UTC (permalink / raw)
To: Peter Chen
Cc: hans.zhang, bhelgaas, lpieralisi, kw, mani, robh, kwilczynski,
krzk+dt, conor+dt, mpillai, fugang.duan, guoyin.chen,
cix-kernel-upstream, linux-pci, devicetree, linux-kernel
On Fri, Aug 15, 2025 at 11:32:29AM +0800, Peter Chen wrote:
> On 25-08-14 17:23:58, Bjorn Helgaas wrote:
> > On Wed, Aug 13, 2025 at 12:23:27PM +0800, hans.zhang@cixtech.com wrote:
> > > From: Hans Zhang <hans.zhang@cixtech.com>
> > >
> > > Add Cixtech P1 (internal name sky1) as a vendor and device ID for PCI
> > > devices. This ID will be used by the CIX Sky1 PCIe host controller driver.
> > >
> > > Signed-off-by: Hans Zhang <hans.zhang@cixtech.com>
> > > ---
> > > include/linux/pci_ids.h | 3 +++
> > > 1 file changed, 3 insertions(+)
> > >
> > > diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
> > > index 92ffc4373f6d..24b04d085920 100644
> > > --- a/include/linux/pci_ids.h
> > > +++ b/include/linux/pci_ids.h
> > > @@ -2631,6 +2631,9 @@
> > >
> > > #define PCI_VENDOR_ID_CXL 0x1e98
> > >
> > > +#define PCI_VENDOR_ID_CIX 0x1f6c
> > > +#define PCI_DEVICE_ID_CIX_SKY1 0x0001
> >
> > I only see these used once in this series, so they probably should be
> > defined in the file that uses them, per the comment at the top of this
> > file.
> >
> > Also, https://pcisig.com/membership/member-companies?combine=0x1f6c
> > doesn't show 0x1f6c as assigned to CIX. That database often seems
> > incomplete, but please double check to make sure the ID is actually
> > reserved.
>
> Would you please check below:
> https://pcisig.com/membership/member-companies?combine=1f6c
Thanks, sorry if I've asked this before. Searching that pcisig
database always seems a little hit and miss.
Bjorn
^ permalink raw reply [flat|nested] 40+ messages in thread
* RE: [PATCH v7 02/13] PCI: cadence: Split PCIe controller header file
2025-08-14 21:16 ` Bjorn Helgaas
@ 2025-08-18 2:01 ` Manikandan Karunakaran Pillai
0 siblings, 0 replies; 40+ messages in thread
From: Manikandan Karunakaran Pillai @ 2025-08-18 2:01 UTC (permalink / raw)
To: Bjorn Helgaas, hans.zhang@cixtech.com
Cc: bhelgaas@google.com, lpieralisi@kernel.org, kw@linux.com,
mani@kernel.org, robh@kernel.org, kwilczynski@kernel.org,
krzk+dt@kernel.org, conor+dt@kernel.org, fugang.duan@cixtech.com,
guoyin.chen@cixtech.com, peter.chen@cixtech.com,
cix-kernel-upstream@cixtech.com, linux-pci@vger.kernel.org,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org
Thanks Bjorn for your comments. Will address your comments on patches 1 to patches 7, in the next submission
>-----Original Message-----
>From: Bjorn Helgaas <helgaas@kernel.org>
>Sent: Friday, August 15, 2025 2:47 AM
>To: hans.zhang@cixtech.com
>Cc: bhelgaas@google.com; lpieralisi@kernel.org; kw@linux.com;
>mani@kernel.org; robh@kernel.org; kwilczynski@kernel.org;
>krzk+dt@kernel.org; conor+dt@kernel.org; Manikandan Karunakaran Pillai
><mpillai@cadence.com>; fugang.duan@cixtech.com;
>guoyin.chen@cixtech.com; peter.chen@cixtech.com; cix-kernel-
>upstream@cixtech.com; linux-pci@vger.kernel.org;
>devicetree@vger.kernel.org; linux-kernel@vger.kernel.org
>Subject: Re: [PATCH v7 02/13] PCI: cadence: Split PCIe controller header file
>
>EXTERNAL MAIL
>
>
>On Wed, Aug 13, 2025 at 12:23:20PM +0800, hans.zhang@cixtech.com wrote:
>> From: Manikandan K Pillai <mpillai@cadence.com>
>>
>> Split the Cadence PCIe header file by moving the Legacy(LGA)
>> controller register definitions to a separate header file for
>> support of next generation PCIe controller architecture.
>
>s/Legacy(LGA)/Legacy (LGA)/
>
>Similar for "HPA(High Performance architecture)" elsewhere.
>
>> +++ b/drivers/pci/controller/cadence/pcie-cadence-lga-regs.h
>> @@ -0,0 +1,228 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +// Copyright (c) 2017 Cadence
>> +// Cadence PCIe controller driver.
>> +// Author: Manikandan K Pillai <mpillai@cadence.com>
>
>I'm not trying to be a killjoy, but the only author listed in
>pcie-cadence.h is Cyrille Pitchen, and I don't think simply moving
>these definitions to a separate file really counts as becoming the
>author. I would at least preserve Cyrille's authorship.
>
>Bjorn
^ permalink raw reply [flat|nested] 40+ messages in thread
end of thread, other threads:[~2025-08-18 2:02 UTC | newest]
Thread overview: 40+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-13 4:23 [PATCH v7 00/13] Enhance the PCIe controller driver for next generation controllers hans.zhang
2025-08-13 4:23 ` [PATCH v7 01/13] PCI: cadence: Add support for modules for cadence controller builds hans.zhang
2025-08-14 21:25 ` Bjorn Helgaas
2025-08-13 4:23 ` [PATCH v7 02/13] PCI: cadence: Split PCIe controller header file hans.zhang
2025-08-14 21:16 ` Bjorn Helgaas
2025-08-18 2:01 ` Manikandan Karunakaran Pillai
2025-08-13 4:23 ` [PATCH v7 03/13] PCI: cadence: Add register definitions for HPA(High Perf Architecture) hans.zhang
2025-08-13 19:17 ` Krzysztof Kozlowski
2025-08-14 1:29 ` Manikandan Karunakaran Pillai
2025-08-14 21:35 ` Bjorn Helgaas
2025-08-13 4:23 ` [PATCH v7 04/13] PCI: cadence: Split PCIe EP support into common and specific functions hans.zhang
2025-08-14 21:41 ` Bjorn Helgaas
2025-08-13 4:23 ` [PATCH v7 05/13] PCI: cadence: Split PCIe RP " hans.zhang
2025-08-14 21:48 ` Bjorn Helgaas
2025-08-13 4:23 ` [PATCH v7 06/13] PCI: cadence: Split the common functions for PCIe controller support hans.zhang
2025-08-13 4:23 ` [PATCH v7 07/13] PCI: cadence: Add support for High Performance Arch(HPA) controller hans.zhang
2025-08-14 22:14 ` Bjorn Helgaas
2025-08-13 4:23 ` [PATCH v7 08/13] dt-bindings: PCI: Add CIX Sky1 PCIe Root Complex bindings hans.zhang
2025-08-13 8:31 ` Rob Herring (Arm)
2025-08-13 9:12 ` Hans Zhang
2025-08-13 15:43 ` Rob Herring
2025-08-14 1:22 ` Hans Zhang
2025-08-13 19:08 ` Krzysztof Kozlowski
2025-08-14 1:26 ` Hans Zhang
2025-08-13 15:44 ` Rob Herring
2025-08-14 1:23 ` Hans Zhang
2025-08-13 4:23 ` [PATCH v7 09/13] PCI: Add Cix Technology Vendor and Device ID hans.zhang
2025-08-14 22:23 ` Bjorn Helgaas
2025-08-15 3:32 ` Peter Chen
2025-08-15 14:27 ` Bjorn Helgaas
2025-08-13 4:23 ` [PATCH v7 10/13] PCI: sky1: Add PCIe host support for CIX Sky1 hans.zhang
2025-08-13 19:16 ` Krzysztof Kozlowski
2025-08-14 1:29 ` Hans Zhang
2025-08-14 22:46 ` Bjorn Helgaas
2025-08-15 7:53 ` Hans Zhang
2025-08-13 4:23 ` [PATCH v7 11/13] MAINTAINERS: add entry for CIX Sky1 PCIe driver hans.zhang
2025-08-13 4:23 ` [PATCH v7 12/13] arm64: dts: cix: Add PCIe Root Complex on sky1 hans.zhang
2025-08-13 4:23 ` [PATCH v7 13/13] arm64: dts: cix: Enable PCIe on the Orion O6 board hans.zhang
2025-08-13 19:14 ` [PATCH v7 00/13] Enhance the PCIe controller driver for next generation controllers Krzysztof Kozlowski
2025-08-14 1:37 ` Hans Zhang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).