aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManoj Kumar <manoj.kumar3@arm.com>2018-11-28 19:12:02 +0530
committerronald-cron-arm <39518861+ronald-cron-arm@users.noreply.github.com>2018-11-30 12:46:36 +0100
commitd5d9194118b795cda4fc7e53e797b07a8cc35d65 (patch)
tree8fead8b892bfaccdf44608900d37a20a38d83791
parentc90a10c8eed9a13a3c8a5935e7934969c913968f (diff)
n1sdp/n1sdp_pcie: add module n1sdp_pcie
This patch adds n1sdp_pcie module used for control plane programming of n1sdp PCIe/CCIX controllers. Change-Id: I574788e9f64a6be3d934ced2c75313ef12928fc3 Signed-off-by: Manoj Kumar <manoj.kumar3@arm.com>
-rw-r--r--product/n1sdp/module/n1sdp_pcie/include/internal/pcie_ctrl_apb_reg.h190
-rw-r--r--product/n1sdp/module/n1sdp_pcie/include/mod_n1sdp_pcie.h74
-rw-r--r--product/n1sdp/module/n1sdp_pcie/src/Makefile11
-rw-r--r--product/n1sdp/module/n1sdp_pcie/src/mod_n1sdp_pcie.c358
-rw-r--r--product/n1sdp/module/n1sdp_pcie/src/n1sdp_pcie.c187
-rw-r--r--product/n1sdp/module/n1sdp_pcie/src/n1sdp_pcie.h431
6 files changed, 1251 insertions, 0 deletions
diff --git a/product/n1sdp/module/n1sdp_pcie/include/internal/pcie_ctrl_apb_reg.h b/product/n1sdp/module/n1sdp_pcie/include/internal/pcie_ctrl_apb_reg.h
new file mode 100644
index 00000000..9db4be9f
--- /dev/null
+++ b/product/n1sdp/module/n1sdp_pcie/include/internal/pcie_ctrl_apb_reg.h
@@ -0,0 +1,190 @@
+/*
+ * Arm SCP/MCP Software
+ * Copyright (c) 2018, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Description:
+ * PCIe controller configuration registers.
+ */
+
+#ifndef PCIE_CTRL_APB_REG_H
+#define PCIE_CTRL_APB_REG_H
+
+#include <stdint.h>
+#include <fwk_macros.h>
+
+/*!
+ * \brief PCIe APB register definitions
+ */
+struct pcie_ctrl_apb_reg {
+ FWK_W uint32_t RESET_CTRL;
+ FWK_R uint32_t RESET_STATUS;
+ uint8_t RESERVED0[0x1000-0x8];
+ FWK_RW uint32_t INT_CTRL;
+ uint32_t RESERVED1;
+ uint32_t RESERVED2;
+ uint32_t RESERVED3;
+ FWK_RW uint32_t RP_CONFIG_IN;
+ FWK_R uint32_t RP_CONFIG_OUT;
+ uint32_t RESERVED4;
+ FWK_RW uint32_t RP_ERROR_CTRL;
+ FWK_R uint32_t RP_DEBUG;
+ FWK_RW uint32_t RP_L1_EXIT_CTRL;
+ FWK_R uint32_t RP_LTSSM_STATE;
+ FWK_R uint32_t PIPE_STATUS;
+ FWK_R uint32_t PM_STATUS;
+ uint32_t RESERVED5;
+ uint32_t RESERVED6;
+ uint32_t RESERVED7;
+ FWK_R uint32_t PMA_COMMON_STATUS;
+ FWK_R uint32_t PMA_LANE_STATUS;
+ uint8_t RESERVED8[0x3000-0x1048];
+ FWK_RW uint32_t MODE_CTRL;
+ FWK_RW uint32_t PWR_STATE_CHANGE_CTRL;
+ FWK_R uint32_t VF_PWR_STATE;
+ FWK_RW uint32_t HOT_RESET_INT_CTRL;
+ FWK_RW uint32_t FLR_RESET_INT_CTRL;
+ FWK_RW uint32_t EP_MISC_CTRL;
+ FWK_R uint32_t EP_MISC_STATUS;
+ FWK_R uint32_t PF_TPH_STATUS;
+ FWK_R uint32_t VF_TPH_STATUS;
+ FWK_RW uint32_t CCIX_CTRL;
+ uint8_t RESERVED9[0xFFD0-0x3028];
+ FWK_R uint32_t PID4;
+ FWK_R uint32_t PID0;
+ FWK_R uint32_t PID1;
+ FWK_R uint32_t PID2;
+ FWK_R uint32_t PID3;
+ FWK_R uint32_t CID0;
+ FWK_R uint32_t CID1;
+ FWK_R uint32_t CID2;
+ FWK_R uint32_t CID3;
+};
+
+#define RESET_CTRL_PHY_REL_POS UINT32_C(0)
+#define RESET_CTRL_RC_REL_POS UINT32_C(1)
+#define RESET_CTRL_HOT_RESET_POS UINT32_C(3)
+
+#define RESET_CTRL_PHY_REL_MASK (1 << RESET_CTRL_PHY_REL_POS)
+#define RESET_CTRL_RC_REL_MASK (1 << RESET_CTRL_RC_REL_POS)
+#define RESET_CTRL_HOT_RESET_MASK (1 << RESET_CTRL_HOT_RESET_POS)
+
+#define RESET_STATUS_PLL_ST_POS UINT32_C(0)
+#define RESET_STATUS_PHY_REL_ST_POS UINT32_C(1)
+#define RESET_STATUS_RC_ST_POS UINT32_C(2)
+#define RESET_STATUS_RC_REL_ST_POS UINT32_C(4)
+#define RESET_STATUS_HOT_RESET_ST_POS UINT32_C(5)
+#define RESET_STATUS_PM_ST_POS UINT32_C(6)
+
+#define RESET_STATUS_PLL_ST_MASK (1 << RESET_STATUS_PLL_ST_POS)
+#define RESET_STATUS_PHY_REL_ST_MASK (1 << RESET_STATUS_PHY_REL_ST_POS)
+#define RESET_STATUS_RC_ST_MASK (1 << RESET_STATUS_RC_ST_POS)
+#define RESET_STATUS_RC_REL_ST_MASK (1 << RESET_STATUS_RC_REL_ST_POS)
+#define RESET_STATUS_HOT_RESET_ST_MASK (1 << RESET_STATUS_HOT_RESET_ST_POS)
+#define RESET_STATUS_PM_ST_MASK (1 << RESET_STATUS_PM_ST_POS)
+
+#define INT_CTRL_NEGOTIATED_SPD_IRQ_EN_POS UINT32_C(0)
+#define INT_CTRL_LINK_TRNG_DONE_IRQ_EN_POS UINT32_C(1)
+#define INT_CTRL_PLL_STATUS_IRQ_EN_POS UINT32_C(2)
+
+#define INT_CTRL_NEGOTIATED_SPD_IRQ_EN_MASK \
+ (1 << INT_CTRL_NEGOTIATED_SPD_IRQ_EN_POS)
+#define INT_CTRL_LINK_TRNG_DONE_IRQ_EN_MASK \
+ (1 << INT_CTRL_LINK_TRNG_DONE_IRQ_EN_POS)
+#define INT_CTRL_PLL_STATUS_IRQ_EN_MASK \
+ (1 << INT_CTRL_PLL_STATUS_IRQ_EN_POS)
+
+#define RP_CONFIG_IN_CLIENT_REQ_EXIT_L2_POS UINT32_C(0)
+#define RP_CONFIG_IN_LINK_TRNG_EN_POS UINT32_C(1)
+#define RP_CONFIG_IN_ARI_EN_POS UINT32_C(2)
+#define RP_CONFIG_IN_LANE_CNT_IN_POS UINT32_C(3)
+#define RP_CONFIG_IN_PCIE_GEN_SEL_POS UINT32_C(6)
+#define RP_CONFIG_IN_SR_IOV_EN_POS UINT32_C(8)
+#define RP_CONFIG_IN_GEN3_DC_BAL_DIS_POS UINT32_C(9)
+#define RP_CONFIG_IN_SRIS_EN_POS UINT32_C(10)
+#define RP_CONFIG_IN_PMA_CMN_EXT_REFCLK_DET_POS UINT32_C(11)
+#define RP_CONFIG_IN_PMA_CMN_EXT_REFCLK_TERMEN_POS UINT32_C(12)
+#define RP_CONFIG_IN_NON_POSTED_REJ_POS UINT32_C(13)
+
+#define RP_CONFIG_IN_CLIENT_REQ_EXIT_L2_MASK \
+ (1 << RP_CONFIG_IN_CLIENT_REQ_EXIT_L2_POS)
+#define RP_CONFIG_IN_LINK_TRNG_EN_MASK \
+ (1 << RP_CONFIG_IN_LINK_TRNG_EN_POS)
+#define RP_CONFIG_IN_ARI_EN_MASK \
+ (1 << RP_CONFIG_IN_ARI_EN_POS)
+#define RP_CONFIG_IN_LANE_CNT_IN_MASK \
+ (0x7 << RP_CONFIG_IN_LANE_CNT_IN_POS)
+#define RP_CONFIG_IN_PCIE_GEN_SEL_MASK \
+ (0x3 << RP_CONFIG_IN_PCIE_GEN_SEL_POS)
+#define RP_CONFIG_IN_SR_IOV_EN_MASK \
+ (1 << RP_CONFIG_IN_SR_IOV_EN_POS)
+#define RP_CONFIG_IN_GEN3_DC_BAL_DIS_MASK \
+ (1 << RP_CONFIG_IN_GEN3_DC_BAL_DIS_POS)
+#define RP_CONFIG_IN_SRIS_EN_MASK \
+ (1 << RP_CONFIG_IN_SRIS_EN_POS)
+#define RP_CONFIG_IN_PMA_CMN_EXT_REFCLK_DET_MASK \
+ (1 << RP_CONFIG_IN_PMA_CMN_EXT_REFCLK_DET_POS)
+#define RP_CONFIG_IN_PMA_CMN_EXT_REFCLK_TERMEN_MASK \
+ (1 << RP_CONFIG_IN_PMA_CMN_EXT_REFCLK_TERMEN_POS)
+#define RP_CONFIG_IN_NON_POSTED_REJ_MASK \
+ (1 << RP_CONFIG_IN_NON_POSTED_REJ_POS)
+
+#define RP_CONFIG_OUT_OBFF_EN_POS UINT32_C(0)
+#define RP_CONFIG_OUT_RCB_STATUS_POS UINT32_C(2)
+#define RP_CONFIG_OUT_MAX_PAYLOAD_SIZE_POS UINT32_C(3)
+#define RP_CONFIG_OUT_MAX_READREQ_SIZE_POS UINT32_C(6)
+#define RP_CONFIG_OUT_LINK_PWR_STATE_POS UINT32_C(9)
+#define RP_CONFIG_OUT_FN_PWR_STATE_POS UINT32_C(16)
+#define RP_CONFIG_OUT_NEGOTIATED_SPD_POS UINT32_C(20)
+#define RP_CONFIG_OUT_NEGOTIATED_LINK_WIDTH_POS UINT32_C(22)
+#define RP_CONFIG_OUT_LINK_STATUS_POS UINT32_C(25)
+
+#define RP_CONFIG_OUT_OBFF_EN_MASK \
+ (0x3 << RP_CONFIG_OUT_OBFF_EN_POS)
+#define RP_CONFIG_OUT_RCB_STATUS_MASK \
+ (1 << RP_CONFIG_OUT_RCB_STATUS_POS)
+#define RP_CONFIG_OUT_MAX_PAYLOAD_SIZE_MASK \
+ (0x7 << RP_CONFIG_OUT_MAX_PAYLOAD_SIZE_POS)
+#define RP_CONFIG_OUT_MAX_READREQ_SIZE_MASK \
+ (0x7 << RP_CONFIG_OUT_MAX_READREQ_SIZE_POS)
+#define RP_CONFIG_OUT_LINK_PWR_STATE_MASK \
+ (0xF << RP_CONFIG_OUT_LINK_PWR_STATE_POS)
+#define RP_CONFIG_OUT_FN_PWR_STATE_MASK \
+ (0x7 << RP_CONFIG_OUT_FN_PWR_STATE_POS)
+#define RP_CONFIG_OUT_NEGOTIATED_SPD_MASK \
+ (0x3 << RP_CONFIG_OUT_NEGOTIATED_SPD_POS)
+#define RP_CONFIG_OUT_NEGOTIATED_LINK_WIDTH_MASK \
+ (0x7 << RP_CONFIG_OUT_NEGOTIATED_LINK_WIDTH_POS)
+#define RP_CONFIG_OUT_LINK_STATUS_MASK \
+ (0x3 << RP_CONFIG_OUT_LINK_STATUS_POS)
+
+#define RP_ERROR_CTRL_UNCORRECTABLE_ERROR_IN_POS UINT32_C(0)
+#define RP_ERROR_CTRL_CORRECTABLE_ERROR_IN_POS UINT32_C(1)
+
+#define RP_ERROR_CTRL_UNCORRECTABLE_ERROR_IN_MASK \
+ (1 << RP_ERROR_CTRL_UNCORRECTABLE_ERROR_IN_POS)
+#define RP_ERROR_CTRL_CORRECTABLE_ERROR_IN_MASK \
+ (1 << RP_ERROR_CTRL_CORRECTABLE_ERROR_IN_POS)
+
+#define RP_LTSSM_STATE_POS UINT32_C(0)
+#define RP_LTSSM_STATE_MASK (0x3F << RP_LTSSM_STATE_POS)
+
+#define PIPE_STATUS_PIPE_RATE_POS UINT32_C(0)
+#define PIPE_STATUS_PIPE_RATE_MASK (0x3 << PIPE_STATUS_PIPE_RATE_POS)
+
+#define PM_STATUS_L1_PM_SUBSTATE_POS UINT32_C(0)
+#define PM_STATUS_L1_PM_SUBSTATE_MASK (0x7 << PM_STATUS_L1_PM_SUBSTATE_POS)
+
+#define MODE_CTRL_MODE_SELECT_EP UINT32_C(0)
+#define MODE_CTRL_MODE_SELECT_RP UINT32_C(1)
+
+#define EP_MISC_CTRL_REQ_PM_L23_READY_POS UINT32_C(0)
+#define EP_MISC_CTRL_CONFIG_EN_POS UINT32_C(8)
+
+#define EP_MISC_CTRL_REQ_PM_L23_READY_MASK \
+ (0x1 << EP_MISC_CTRL_REQ_PM_L23_READY_POS)
+#define EP_MISC_CTRL_CONFIG_EN_MASK \
+ (0x1 << EP_MISC_CTRL_CONFIG_EN_POS)
+
+#endif /* PCIE_CTRL_APB_REG_H */
diff --git a/product/n1sdp/module/n1sdp_pcie/include/mod_n1sdp_pcie.h b/product/n1sdp/module/n1sdp_pcie/include/mod_n1sdp_pcie.h
new file mode 100644
index 00000000..65d86821
--- /dev/null
+++ b/product/n1sdp/module/n1sdp_pcie/include/mod_n1sdp_pcie.h
@@ -0,0 +1,74 @@
+/*
+ * Arm SCP/MCP Software
+ * Copyright (c) 2018, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MOD_N1SDP_PCIE_H
+#define MOD_N1SDP_PCIE_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/*!
+ * \addtogroup GroupN1SDPModule N1SDP Product Modules
+ * @{
+ */
+
+/*!
+ * \defgroup GroupModuleN1SDPPcie N1SDP PCIe Driver
+ *
+ * \brief Driver support for N1SDP PCIe Root Complex & End Point devices.
+ *
+ * \details This module provides driver support for enabling and configuring
+ * the PCIe peripheral either in root complex mode or in end point mode.
+ *
+ * \{
+ */
+
+/*!
+ * \brief N1SDP PCIe instance configuration
+ */
+struct n1sdp_pcie_dev_config {
+ /*!
+ * Base address of the PCIe Controller. This includes the PHY configuration
+ * and PCIe IP level configuration registers.
+ */
+ uintptr_t ctrl_base;
+
+ /*!
+ * Base address of the PCIe functional configuration registers. This
+ * region includes registers for configuring the IP in both RC and
+ * EP modes.
+ */
+ uintptr_t global_config_base;
+
+ /*! Base address of the PCIe message registers. */
+ uintptr_t msg_base;
+
+ /*!
+ * Base address of the PCIe AXI slave memory region (within 32-bit address
+ * space). This region holds the ECAM space, MMIO32 & IO space.
+ */
+ uint32_t axi_slave_base32;
+
+ /*!
+ * Base address of the PCIe AXI slave memory region (in 64-bit address
+ * space). This region holds the MMIO64 space.
+ */
+ uint64_t axi_slave_base64;
+
+ /*! Identifier to indicate if the PCIe controller is CCIX capable */
+ bool ccix_capable;
+};
+
+/*!
+ * \}
+ */
+
+/*!
+ * \}
+ */
+
+#endif /* MOD_N1SDP_PCIE_H */
diff --git a/product/n1sdp/module/n1sdp_pcie/src/Makefile b/product/n1sdp/module/n1sdp_pcie/src/Makefile
new file mode 100644
index 00000000..7b9fb6dd
--- /dev/null
+++ b/product/n1sdp/module/n1sdp_pcie/src/Makefile
@@ -0,0 +1,11 @@
+#
+# Arm SCP/MCP Software
+# Copyright (c) 2018, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+BS_LIB_NAME := "N1SDP PCIe"
+BS_LIB_SOURCES = n1sdp_pcie.c mod_n1sdp_pcie.c
+
+include $(BS_DIR)/lib.mk
diff --git a/product/n1sdp/module/n1sdp_pcie/src/mod_n1sdp_pcie.c b/product/n1sdp/module/n1sdp_pcie/src/mod_n1sdp_pcie.c
new file mode 100644
index 00000000..238c7339
--- /dev/null
+++ b/product/n1sdp/module/n1sdp_pcie/src/mod_n1sdp_pcie.c
@@ -0,0 +1,358 @@
+/*
+ * Arm SCP/MCP Software
+ * Copyright (c) 2018, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+#include <fwk_assert.h>
+#include <fwk_errno.h>
+#include <fwk_id.h>
+#include <fwk_mm.h>
+#include <fwk_module.h>
+#include <fwk_module_idx.h>
+#include <fwk_notification.h>
+#include <mod_clock.h>
+#include <mod_n1sdp_pcie.h>
+#include <mod_log.h>
+#include <mod_timer.h>
+#include <config_clock.h>
+#include <n1sdp_pcie.h>
+#include <n1sdp_scc_reg.h>
+#include <n1sdp_scp_pik.h>
+#include <internal/pcie_ctrl_apb_reg.h>
+
+/*
+ * Device context
+ */
+struct n1sdp_pcie_dev_ctx {
+ /* Pointer to PCIe device configuration */
+ struct n1sdp_pcie_dev_config *config;
+
+ /*
+ * Pointer to PCIe Controller IP configuration APB registers.
+ * Accessible in both RC & EP modes.
+ */
+ struct pcie_ctrl_apb_reg *ctrl_apb;
+
+ /*
+ * Base address of the PCIe PHY APB registers.
+ * Accessible in both RC & EP modes.
+ */
+ uintptr_t phy_apb;
+
+ /*
+ * Base address of the PCIe configuration APB registers.
+ * Accessible in both RP & EP mode.
+ */
+ uintptr_t rp_ep_config_apb;
+
+ /*
+ * Base address of the PCIe Local Management (LM) registers.
+ * Accessible in both RC & EP modes.
+ */
+ uintptr_t lm_apb;
+
+ /*
+ * Base address of the AXI configuration registers for RC.
+ * Accessible in RC mode.
+ */
+ uintptr_t rc_axi_config_apb;
+
+ /*
+ * Base address of the AXI configuration registers for EP.
+ * Accessible in EP mode.
+ */
+ uintptr_t ep_axi_config_apb;
+};
+
+/*
+ * Module context
+ */
+struct n1sdp_pcie_ctx {
+ /* Log module API */
+ struct mod_log_api *log_api;
+
+ /* Timer module API */
+ struct mod_timer_api *timer_api;
+
+ /* Table of PCIe device contexts */
+ struct n1sdp_pcie_dev_ctx *device_ctx_table;
+
+ /* Number of PCIe root complexes/endpoints in the system */
+ unsigned int pcie_instance_count;
+};
+
+struct n1sdp_pcie_ctx pcie_ctx;
+
+/*
+ * Module functions
+ */
+static int n1sdp_pcie_setup(struct n1sdp_pcie_dev_ctx *dev_ctx)
+{
+ uint32_t ecam_base_addr;
+ int status;
+
+ /* Enable the CCIX/PCIe controller */
+ if (dev_ctx->config->ccix_capable) {
+ SCC->CCIX_PM_CTRL = SCC_CCIX_PM_CTRL_PWR_REQ_POS;
+ SCC->SYS_MAN_RESET &= ~(1 << SCC_SYS_MAN_RESET_CCIX_POS);
+ } else {
+ SCC->PCIE_PM_CTRL = SCC_PCIE_PM_CTRL_PWR_REQ_POS;
+ SCC->SYS_MAN_RESET &= ~(1 << SCC_SYS_MAN_RESET_PCIE_POS);
+ }
+
+ /* PHY initialization */
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, "[PCIe] Initializing PHY...");
+ status = pcie_init(dev_ctx->ctrl_apb,
+ pcie_ctx.timer_api,
+ PCIE_INIT_STAGE_PHY);
+ if (status != FWK_SUCCESS) {
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, "Timeout!\n");
+ return status;
+ }
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, "Done\n");
+
+ /* Controller initialization */
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO,
+ "[PCIe] Initializing controller...");
+ status = pcie_init(dev_ctx->ctrl_apb,
+ pcie_ctx.timer_api,
+ PCIE_INIT_STAGE_CTRL);
+ if (status != FWK_SUCCESS) {
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, "Timeout!\n");
+ return status;
+ }
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, "Done\n");
+
+ /* Link training */
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO,
+ "[PCIe] Starting link training...");
+ status = pcie_init(dev_ctx->ctrl_apb,
+ pcie_ctx.timer_api,
+ PCIE_INIT_STAGE_LINK_TRNG);
+ if (status != FWK_SUCCESS) {
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, "Timeout!\n");
+ return status;
+ }
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, "Done\n");
+
+ /* Root Complex setup */
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO,
+ "[PCIe] Setup Type0 configuration...");
+ ecam_base_addr = dev_ctx->config->axi_slave_base32 +
+ PCIE_AXI_ECAM_TYPE0_OFFSET;
+ status = axi_outbound_region_setup(dev_ctx->rc_axi_config_apb,
+ (ecam_base_addr - SCP_AP_AXI_OFFSET),
+ __builtin_ctz(AXI_ECAM_TYPE0_SIZE),
+ TRANS_TYPE_0_CFG);
+ if (status != FWK_SUCCESS) {
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, "Error!\n");
+ return status;
+ }
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, "Done\n");
+
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO,
+ "[PCIe] Setup Type1 configuration...");
+ ecam_base_addr = dev_ctx->config->axi_slave_base32 +
+ PCIE_AXI_ECAM_TYPE1_OFFSET;
+ status = axi_outbound_region_setup(dev_ctx->rc_axi_config_apb,
+ (ecam_base_addr - SCP_AP_AXI_OFFSET),
+ __builtin_ctz(AXI_ECAM_TYPE1_SIZE),
+ TRANS_TYPE_1_CFG);
+ if (status != FWK_SUCCESS) {
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, "Error!\n");
+ return status;
+ }
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, "Done\n");
+
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO,
+ "[PCIe] Setup MMIO32 configuration...");
+ if (dev_ctx->config->ccix_capable)
+ ecam_base_addr = dev_ctx->config->axi_slave_base32 +
+ CCIX_AXI_MMIO32_OFFSET;
+ else
+ ecam_base_addr = dev_ctx->config->axi_slave_base32 +
+ PCIE_AXI_MMIO32_OFFSET;
+ status = axi_outbound_region_setup(dev_ctx->rc_axi_config_apb,
+ (ecam_base_addr - SCP_AP_AXI_OFFSET),
+ __builtin_ctz(AXI_MMIO32_SIZE),
+ TRANS_TYPE_MEM_IO);
+ if (status != FWK_SUCCESS) {
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, "Error!\n");
+ return status;
+ }
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, "Done\n");
+
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO,
+ "[PCIe] Setup IO configuration...");
+ if (dev_ctx->config->ccix_capable)
+ ecam_base_addr = dev_ctx->config->axi_slave_base32 +
+ CCIX_AXI_IO_OFFSET;
+ else
+ ecam_base_addr = dev_ctx->config->axi_slave_base32 +
+ PCIE_AXI_IO_OFFSET;
+ status = axi_outbound_region_setup(dev_ctx->rc_axi_config_apb,
+ (ecam_base_addr - SCP_AP_AXI_OFFSET),
+ __builtin_ctz(AXI_IO_SIZE),
+ TRANS_TYPE_IO);
+ if (status != FWK_SUCCESS) {
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, "Error!\n");
+ return status;
+ }
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, "Done\n");
+
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO,
+ "[PCIe] Setup MMIO64 configuration...");
+ status = axi_outbound_region_setup(dev_ctx->rc_axi_config_apb,
+ dev_ctx->config->axi_slave_base64,
+ __builtin_ctz(AXI_MMIO64_SIZE),
+ TRANS_TYPE_MEM_IO);
+ if (status != FWK_SUCCESS) {
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, "Error!\n");
+ return status;
+ }
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, "Done\n");
+
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO,
+ "[PCIe] Setup RP classcode...");
+ status = pcie_rp_ep_config_write_word(dev_ctx->rp_ep_config_apb,
+ PCIE_CLASS_CODE_OFFSET,
+ PCIE_CLASS_CODE_PCI_BRIDGE);
+ if (status != FWK_SUCCESS) {
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, "Error!\n");
+ return status;
+ }
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, "Done\n");
+
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO,
+ "[PCIe] Enable inbound region in BAR 2...");
+ status = axi_inbound_region_setup(dev_ctx->rc_axi_config_apb,
+ AXI_IB_REGION_BASE,
+ __builtin_ctz(AXI_IB_REGION_SIZE), 2);
+ if (status != FWK_SUCCESS) {
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, "Error!\n");
+ return status;
+ }
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, "Done\n");
+
+ return FWK_SUCCESS;
+}
+
+/*
+ * Framework handlers
+ */
+static int n1sdp_pcie_init(fwk_id_t module_id, unsigned int element_count,
+ const void *data)
+{
+ if (element_count == 0)
+ return FWK_E_DATA;
+
+ pcie_ctx.device_ctx_table = fwk_mm_calloc(element_count,
+ sizeof(pcie_ctx.device_ctx_table[0]));
+ if (pcie_ctx.device_ctx_table == NULL)
+ return FWK_E_NOMEM;
+
+ pcie_ctx.pcie_instance_count = element_count;
+
+ return FWK_SUCCESS;
+}
+
+static int n1sdp_pcie_element_init(fwk_id_t element_id, unsigned int unused,
+ const void *data)
+{
+ struct n1sdp_pcie_dev_ctx *dev_ctx;
+ struct n1sdp_pcie_dev_config *config;
+
+ if (data == NULL)
+ return FWK_E_PARAM;
+
+ config = (struct n1sdp_pcie_dev_config *)data;
+
+ dev_ctx = &pcie_ctx.device_ctx_table[fwk_id_get_element_idx(element_id)];
+ if (dev_ctx == NULL)
+ return FWK_E_DATA;
+
+ dev_ctx->config = config;
+
+ dev_ctx->ctrl_apb = (struct pcie_ctrl_apb_reg *)
+ (config->ctrl_base + APB_OFFSET_CTRL_REGS);
+ dev_ctx->phy_apb = config->ctrl_base + APB_OFFSET_PHY_REGS;
+ dev_ctx->rp_ep_config_apb = config->global_config_base +
+ APB_OFFSET_RP_EP_CONFIG_REGS;
+ dev_ctx->lm_apb = config->global_config_base + APB_OFFSET_LM_REGS;
+ dev_ctx->rc_axi_config_apb = config->global_config_base +
+ APB_OFFSET_RC_AXI_CONFIG_REGS;
+ dev_ctx->ep_axi_config_apb = config->global_config_base +
+ APB_OFFSET_EP_AXI_CONFIG_REGS;
+
+ return FWK_SUCCESS;
+}
+
+
+static int n1sdp_pcie_bind(fwk_id_t id, unsigned int round)
+{
+ int status;
+
+ if (round == 0) {
+ status = fwk_module_bind(FWK_ID_MODULE(FWK_MODULE_IDX_LOG),
+ FWK_ID_API(FWK_MODULE_IDX_LOG, 0), &pcie_ctx.log_api);
+ if (status != FWK_SUCCESS)
+ return status;
+
+ status = fwk_module_bind(FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
+ FWK_ID_API(FWK_MODULE_IDX_TIMER, MOD_TIMER_API_IDX_TIMER),
+ &pcie_ctx.timer_api);
+ if (status != FWK_SUCCESS)
+ return status;
+ }
+ return FWK_SUCCESS;
+}
+
+static int n1sdp_pcie_start(fwk_id_t id)
+{
+ struct n1sdp_pcie_dev_ctx *dev_ctx;
+
+ if (fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) {
+ /*
+ * Enable AP core to access PCIe root port's
+ * configuration space
+ */
+ *(volatile uint32_t *)(NIC400_SOC_GPV_BASE + 0x0C) = 0x7F;
+ return FWK_SUCCESS;
+ }
+
+ dev_ctx = &pcie_ctx.device_ctx_table[fwk_id_get_element_idx(id)];
+ if (dev_ctx == NULL)
+ return FWK_E_PARAM;
+
+ return fwk_notification_subscribe(
+ mod_clock_notification_id_state_changed,
+ FWK_ID_ELEMENT(FWK_MODULE_IDX_CLOCK, CLOCK_IDX_INTERCONNECT),
+ id);
+}
+
+static int n1sdp_pcie_process_notification(const struct fwk_event *event,
+ struct fwk_event *resp)
+{
+ struct n1sdp_pcie_dev_ctx *dev_ctx;
+
+ dev_ctx = &pcie_ctx.device_ctx_table[
+ fwk_id_get_element_idx(event->target_id)];
+ if (dev_ctx == NULL)
+ return FWK_E_PARAM;
+
+ return n1sdp_pcie_setup(dev_ctx);
+}
+
+const struct fwk_module module_n1sdp_pcie = {
+ .name = "N1SDP PCIe",
+ .type = FWK_MODULE_TYPE_DRIVER,
+ .api_count = 0,
+ .init = n1sdp_pcie_init,
+ .element_init = n1sdp_pcie_element_init,
+ .bind = n1sdp_pcie_bind,
+ .start = n1sdp_pcie_start,
+ .process_notification = n1sdp_pcie_process_notification,
+};
diff --git a/product/n1sdp/module/n1sdp_pcie/src/n1sdp_pcie.c b/product/n1sdp/module/n1sdp_pcie/src/n1sdp_pcie.c
new file mode 100644
index 00000000..4e8fce07
--- /dev/null
+++ b/product/n1sdp/module/n1sdp_pcie/src/n1sdp_pcie.c
@@ -0,0 +1,187 @@
+/*
+ * Arm SCP/MCP Software
+ * Copyright (c) 2018, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <fwk_assert.h>
+#include <fwk_errno.h>
+#include <internal/pcie_ctrl_apb_reg.h>
+#include <mod_n1sdp_pcie.h>
+#include <mod_timer.h>
+#include <n1sdp_pcie.h>
+
+static bool wait_condition(void *data)
+{
+ assert(data != NULL);
+
+ struct wait_condition_data *wait_data = (struct wait_condition_data *)data;
+ struct pcie_ctrl_apb_reg *ctrl_apb =
+ (struct pcie_ctrl_apb_reg *)(wait_data->ctrl_apb);
+
+ switch (wait_data->stage) {
+ case PCIE_INIT_STAGE_PHY:
+ return ((ctrl_apb->RESET_STATUS &
+ RESET_STATUS_PHY_REL_ST_MASK) != 0);
+ case PCIE_INIT_STAGE_CTRL:
+ return ((ctrl_apb->RESET_STATUS &
+ RESET_STATUS_RC_REL_ST_MASK) != 0);
+ case PCIE_INIT_STAGE_LINK_TRNG:
+ return ((ctrl_apb->RP_LTSSM_STATE & RP_LTSSM_STATE_MASK) == 0x10);
+ default:
+ assert(false);
+ return false;
+ }
+}
+
+int pcie_init(struct pcie_ctrl_apb_reg *ctrl_apb,
+ struct mod_timer_api *timer_api,
+ enum pcie_init_stage stage)
+{
+ assert(ctrl_apb != NULL);
+ assert(timer_api != NULL);
+ assert(stage < PCIE_INIT_STAGE_COUNT);
+
+ struct wait_condition_data wait_data;
+ int status;
+
+ wait_data.ctrl_apb = ctrl_apb;
+ wait_data.stage = stage;
+
+ switch (stage) {
+ /* PCIe PHY reset request */
+ case PCIE_INIT_STAGE_PHY:
+ ctrl_apb->RESET_CTRL = RESET_CTRL_PHY_REL_MASK;
+ status = timer_api->wait(FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
+ PCIE_PHY_PLL_LOCK_TIMEOUT,
+ wait_condition,
+ &wait_data);
+ if (status != FWK_SUCCESS)
+ return status;
+ break;
+
+ /* PCIe RC reset request */
+ case PCIE_INIT_STAGE_CTRL:
+ /* Clear ARI & SR_IOV bits */
+ ctrl_apb->RP_CONFIG_IN &= ~RP_CONFIG_IN_ARI_EN_MASK;
+ ctrl_apb->RP_CONFIG_IN &= ~RP_CONFIG_IN_SR_IOV_EN_MASK;
+ ctrl_apb->RESET_CTRL = RESET_CTRL_RC_REL_MASK;
+ status = timer_api->wait(FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
+ PCIE_CTRL_RC_RESET_TIMEOUT,
+ wait_condition,
+ &wait_data);
+ if (status != FWK_SUCCESS)
+ return status;
+ break;
+
+ /* PCIe link training request */
+ case PCIE_INIT_STAGE_LINK_TRNG:
+ ctrl_apb->RP_CONFIG_IN |= RP_CONFIG_IN_LINK_TRNG_EN_MASK;
+ status = timer_api->wait(FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
+ PCIE_LINK_TRAINING_TIMEOUT,
+ wait_condition,
+ &wait_data);
+ if (status != FWK_SUCCESS)
+ return status;
+ break;
+
+ default:
+ assert(false);
+ return FWK_E_PARAM;
+ }
+ return FWK_SUCCESS;
+}
+
+int axi_outbound_region_setup(uint32_t axi_config_base_addr,
+ uint64_t axi_base_addr,
+ uint32_t region_size,
+ uint8_t trans_type)
+{
+ static uint8_t region_count;
+ volatile struct axi_ob_config ob_config = {0};
+ volatile uint32_t *region_address = NULL;
+ volatile uint32_t *ptr;
+ int count;
+
+ if (region_count >= AXI_OB_REGIONS_MAX)
+ return FWK_E_RANGE;
+
+ memset((void *)&ob_config, 0, sizeof(struct axi_ob_config));
+
+ ob_config.addr0.num_bits = region_size;
+ if ((trans_type == TRANS_TYPE_MEM_IO) ||
+ (trans_type == TRANS_TYPE_IO)) {
+ ob_config.addr0.address_bits =
+ ((uint32_t)axi_base_addr >> AXI_LOW_ADDR_BIT_POS);
+ ob_config.addr1.address_bits =
+ (uint32_t)(axi_base_addr >> AXI_HIGH_ADDR_BIT_POS);
+ } else {
+ ob_config.addr0.address_bits = 0;
+ }
+ ob_config.desc0.bus_dev_num_from_addr_desc = 1;
+ ob_config.desc0.trans_type = trans_type;
+ ob_config.axi_base_addr0.region_sz = region_size - 1;
+ ob_config.axi_base_addr0.axi_base_address =
+ ((uint32_t)axi_base_addr >> AXI_LOW_ADDR_BIT_POS);
+ ob_config.axi_base_addr1.axi_base_address =
+ (uint32_t)(axi_base_addr >> AXI_HIGH_ADDR_BIT_POS);
+ region_address = (volatile uint32_t *)(axi_config_base_addr +
+ (region_count * AXI_OB_REGISTER_SET_SIZE));
+ region_count++;
+
+ ptr = (volatile uint32_t *)&ob_config;
+
+ for (count = 0; count < AXI_OB_REGISTER_COUNT; count++)
+ region_address[count] = ptr[count];
+
+ return FWK_SUCCESS;
+}
+
+int axi_inbound_region_setup(uint32_t axi_config_base_addr,
+ uint64_t axi_base_addr,
+ uint32_t region_size,
+ uint8_t bar)
+{
+ uint32_t offset;
+
+ if ((bar >= AXI_IB_REGIONS_MAX) ||
+ (region_size > AXI_ADDR_NUM_BITS_MAX) ||
+ (__builtin_ctz(axi_base_addr) < AXI_LOW_ADDR_BIT_POS))
+ return FWK_E_PARAM;
+
+ offset = AXI_IB_REGION_REGS_OFFSET + (bar * AXI_IB_REGISTER_SET_SIZE);
+ *(uint32_t *)(axi_config_base_addr + offset) = (uint32_t)axi_base_addr |
+ (region_size - 1);
+ *(uint32_t *)(axi_config_base_addr + offset + 4) =
+ (uint32_t)(axi_base_addr >> AXI_HIGH_ADDR_BIT_POS);
+ return FWK_SUCCESS;
+}
+
+int pcie_rp_ep_config_write_word(uint32_t base,
+ uint32_t offset,
+ uint32_t value)
+{
+ if ((offset % 4))
+ return FWK_E_PARAM;
+
+ base |= ROOT_PORT_WRITE_ENABLE;
+ *(uint32_t *)(base + offset) = value;
+
+ return FWK_SUCCESS;
+}
+
+int pcie_rp_ep_config_read_word(uint32_t base,
+ uint32_t offset,
+ uint32_t *value)
+{
+ if ((offset % 4) || (value == NULL))
+ return FWK_E_PARAM;
+
+ *value = *(uint32_t *)(base + offset);
+
+ return FWK_SUCCESS;
+}
diff --git a/product/n1sdp/module/n1sdp_pcie/src/n1sdp_pcie.h b/product/n1sdp/module/n1sdp_pcie/src/n1sdp_pcie.h
new file mode 100644
index 00000000..01ff9125
--- /dev/null
+++ b/product/n1sdp/module/n1sdp_pcie/src/n1sdp_pcie.h
@@ -0,0 +1,431 @@
+/*
+ * Arm SCP/MCP Software
+ * Copyright (c) 2018, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef N1SDP_PCIE_H
+#define N1SDP_PCIE_H
+
+#include <stdint.h>
+#include <fwk_macros.h>
+#include <mod_timer.h>
+#include <internal/pcie_ctrl_apb_reg.h>
+
+/*
+ * Definitions of PCIe APB register offsets from global configuration
+ * base address.
+ */
+
+/*
+ * Offset from ctrl_base implementing PCIe controller
+ * configuration registers.
+ */
+#define APB_OFFSET_CTRL_REGS 0x00040000U
+/*
+ * Offset from ctrl_base implementing PCIe physical layer
+ * configuration registers.
+ */
+#define APB_OFFSET_PHY_REGS 0x00000000U
+/*
+ * Offset from global_config_base implementing Root Port/End Point's
+ * PCIe configuration space registers.
+ */
+#define APB_OFFSET_RP_EP_CONFIG_REGS 0x00000000U
+/*
+ * Offset from global_config_base implementing PCIe controller's
+ * local management configuration registers.
+ */
+#define APB_OFFSET_LM_REGS 0x00100000U
+/*
+ * Offset from global_config_base implementing Root Complex's
+ * AXI address translation registers.
+ */
+#define APB_OFFSET_RC_AXI_CONFIG_REGS 0x00400000U
+/*
+ * Offset from global_config_base implementing End Point's
+ * AXI address translation registers.
+ */
+#define APB_OFFSET_EP_AXI_CONFIG_REGS 0x00400840U
+/*
+ * Offset between SCP and AP's view of memory space in System Access Port.
+ * AP's view : 0x40000000 - 0x7FFFFFFF
+ * SCP's view : 0x60000000 - 0x9FFFFFFF
+ */
+#define SCP_AP_AXI_OFFSET 0x20000000U
+
+/* NIC400 base address definition */
+#define NIC400_SOC_GPV_BASE UINT32_C(0x84000000)
+
+/*
+ * PCIe timeout values for PHY, controller & link training.
+ * Timeout values specified in microseconds.
+ * Note: Execution will block for the specified timeout. If the timeout
+ * is too long switch to alarm API instead of blocking.
+ */
+#define PCIE_PHY_PLL_LOCK_TIMEOUT UINT32_C(100)
+#define PCIE_CTRL_RC_RESET_TIMEOUT UINT32_C(100)
+#define PCIE_LINK_TRAINING_TIMEOUT UINT32_C(20000)
+
+/* PCIe configuration space offset definitions */
+#define PCIE_CLASS_CODE_OFFSET 0x8
+
+/* PCIe class code for PCI bridge */
+#define PCIE_CLASS_CODE_PCI_BRIDGE UINT32_C(0x06040000)
+
+/*
+ * Root port's config space cannot be written directly with its base address.
+ * Bit 21 has to be set in the base address to enable writing to root port's
+ * config register. This macro defines the mask with bit 21 set to be used
+ * with root port write function
+ */
+#define ROOT_PORT_WRITE_ENABLE UINT32_C(0x00200000)
+
+/*
+ * ECAM space per bus
+ * 32 devices * 8 functions * 4kB config space = 1MB
+ */
+#define MAX_ECAM_SPACE_PER_BUS (1 * FWK_MIB)
+
+/* Maximum bus levels for type 0 and type 1 transactions */
+#define MAX_TYPE0_BUS_LEVELS 2
+#define MAX_TYPE1_BUS_LEVELS 8
+
+/* Maximum AXI space for type 0 and type 1 transactions */
+#define AXI_ECAM_TYPE0_SIZE (MAX_TYPE0_BUS_LEVELS * \
+ MAX_ECAM_SPACE_PER_BUS)
+#define AXI_ECAM_TYPE1_SIZE (MAX_TYPE1_BUS_LEVELS * \
+ MAX_ECAM_SPACE_PER_BUS)
+
+/* Maximum AXI space for MMIO64, MMIO32 & IO transactions */
+#define AXI_MMIO64_SIZE (128 * FWK_GIB)
+#define AXI_MMIO32_SIZE (64 * FWK_MIB)
+#define AXI_IO_SIZE (16 * FWK_MIB)
+
+/*
+ * PCIe AXI slave ECAM memory mapping
+ */
+#define PCIE_AXI_ECAM_TYPE0_OFFSET UINT32_C(0)
+
+#define PCIE_AXI_ECAM_TYPE1_OFFSET (PCIE_AXI_ECAM_TYPE0_OFFSET + \
+ AXI_ECAM_TYPE0_SIZE)
+
+/*
+ * CCIX AXI slave ECAM memory mapping
+ */
+#define CCIX_AXI_ECAM_TYPE0_OFFSET (16 * FWK_MIB)
+
+#define CCIX_AXI_ECAM_TYPE1_OFFSET (CCIX_AXI_ECAM_TYPE0_OFFSET + \
+ AXI_ECAM_TYPE0_SIZE)
+
+/* PCIe AXI slave MMIO32 & IO offset addresses */
+#define PCIE_AXI_MMIO32_OFFSET (PCIE_AXI_ECAM_TYPE1_OFFSET + \
+ AXI_ECAM_TYPE1_SIZE)
+#define PCIE_AXI_IO_OFFSET (PCIE_AXI_MMIO32_OFFSET + \
+ AXI_MMIO32_SIZE)
+
+/* CCIX AXI slave MMIO32 & IO offset addresses */
+#define CCIX_AXI_MMIO32_OFFSET (CCIX_AXI_ECAM_TYPE1_OFFSET + \
+ AXI_ECAM_TYPE1_SIZE)
+#define CCIX_AXI_IO_OFFSET UINT32_C(0)
+
+/* AXI inbound region data */
+#define AXI_IB_REGION_BASE UINT64_C(0)
+#define AXI_IB_REGION_SIZE (4 * FWK_GIB)
+
+/*
+ * PCIe Descriptor Register definitions
+ */
+#define TRANS_TYPE_MEM_IO 0x2
+#define TRANS_TYPE_IO 0x6
+#define TRANS_TYPE_0_CFG 0xA
+#define TRANS_TYPE_1_CFG 0xB
+#define TRANS_TYPE_NORMAL 0xC
+#define TRANS_TYPE_VDM 0xD
+
+#define PCIE_ATTR_ID_BASED_ORDERING 0x4
+#define PCIE_ATTR_RELAXED_ORDERING 0x2
+#define PCIE_ATTR_NO_SNOOP 0x1
+
+#define ATS_UNTRANSLATED 0
+#define ATS_TRANSLATION_REQUEST 1
+#define ATS_TRANSLATED 2
+
+#define TRAFFIC_CLASS_0 0
+#define TRAFFIC_CLASS_1 1
+#define TRAFFIC_CLASS_2 2
+#define TRAFFIC_CLASS_3 3
+#define TRAFFIC_CLASS_4 4
+#define TRAFFIC_CLASS_5 5
+#define TRAFFIC_CLASS_6 6
+#define TRAFFIC_CLASS_7 7
+
+#define FORCE_ECRC 1
+#define DISABLE_ECRC 0
+
+#define INPUT_REQ_ID_FROM_ADDR 1
+
+#define PASID_PRESENT 1
+#define PASID_NOT_PRESENT 0
+
+#define PRIV_MODE_ACCESS_REQUEST 1
+#define NO_PRIV_MODE_ACCESS 0
+
+#define EXEC_MODE_ACCESS_REQUEST 1
+#define NO_EXEC_MODE_ACCESS_REQUEST 0
+
+/*
+ * Maximum AXI outbound regions that can be configured
+ */
+#define AXI_OB_REGIONS_MAX 32
+
+/*
+ * Total register size of each outbound region
+ */
+#define AXI_OB_REGISTER_SET_SIZE (8 * 4)
+
+/*
+ * Total register count of each outbound region
+ */
+#define AXI_OB_REGISTER_COUNT 8
+
+/*
+ * Maximum AXI inbound regions that can be configured
+ */
+#define AXI_IB_REGIONS_MAX 3
+
+/*
+ * Offset from AXI region configuration base where inbound region
+ * configuration register starts
+ */
+#define AXI_IB_REGION_REGS_OFFSET (0x800)
+
+/*
+ * Total register size of each inbound region
+ */
+#define AXI_IB_REGISTER_SET_SIZE (2 * 4)
+
+/*
+ * AXI address translation register definitions
+ */
+#define AXI_LOW_ADDR_BIT_POS 8
+#define AXI_HIGH_ADDR_BIT_POS 32
+#define AXI_ADDR_NUM_BITS_MAX ((1 << 6) - 1)
+
+/*
+ * AXI outbound region register set definitions
+ */
+
+/*
+ * Input AXI to outbound PCIe Address translation registers
+ */
+struct axi_ob_addr0 {
+ /* Number of bits passed through from AXI address to PCIe address */
+ uint32_t num_bits:6;
+ uint32_t reserved:2;
+ /* Bits [31:8] of PCIe address */
+ uint32_t address_bits:24;
+};
+
+struct axi_ob_addr1 {
+ /* Bits [63:32] of PCIe address */
+ uint32_t address_bits;
+};
+
+/*
+ * Outbound PCIe descriptor registers
+ */
+struct axi_ob_desc0 {
+ /* Outbound transaction type */
+ uint32_t trans_type:4;
+ /* Outbound PCIe attributes */
+ uint32_t attr:3;
+ /*
+ * Address Translation Service
+ * Config TLP - reserved
+ * Mem/IO TLP - one of the address transalation types
+ */
+ uint32_t ats:2;
+ uint32_t reserved1:8;
+ uint32_t traffic_class:3;
+ /* Poison mem write for memory TLP, reserved for other TLPs */
+ uint32_t poison_mem_write:1;
+ /* Force generation of ECRC for every TLP */
+ uint32_t force_ecrc:1;
+ uint32_t reserved2:1;
+ /* Use bus/dev number from addrx for config TLP & descx for mem TLP */
+ uint32_t bus_dev_num_from_addr_desc:1;
+ /* Function number in ARI mode or Dev+Function number in non-ARI mode */
+ uint32_t dev_func_num:8;
+};
+
+struct axi_ob_desc1 {
+ /* Bus number if bus_dev_num_from_addr_desc in desc0 is set */
+ uint32_t bus_number:8;
+ uint32_t reserved:24;
+};
+
+struct axi_ob_desc2 {
+ /* Steering tag for the hint */
+ uint32_t steering_tag:8;
+ /* Index bit */
+ uint32_t index_bit:1;
+ /* PH value associated with the hint */
+ uint32_t ph_value:2;
+ /* Transaction Processing Hint length */
+ uint32_t tph_length:1;
+ /* TPH request */
+ uint32_t tph_req:1;
+ uint32_t reserved:19;
+};
+
+struct axi_ob_desc3 {
+ /* Process Address Space ID present identifier */
+ uint32_t pasid_present_bit:1;
+ /* PASID value */
+ uint32_t pasid_value:20;
+ /* Privilege mode access request */
+ uint32_t priv_mode_access_req:1;
+ /* Execute mode access request */
+ uint32_t exec_mode_access_req:1;
+ uint32_t reserved:9;
+};
+
+/*
+ * Input AXI base address registers
+ */
+struct axi_ob_axi_base_addr0 {
+ /* Region size = 2 ^ (region_sz + 1) */
+ uint32_t region_sz:6;
+ uint32_t reserved:2;
+ /* Bits [31:8] of AXI base address */
+ uint32_t axi_base_address:24;
+};
+
+struct axi_ob_axi_base_addr1 {
+ /* Bits [63:32] of AXI base address */
+ uint32_t axi_base_address;
+};
+
+/*
+ * AXI outbound region register set
+ */
+struct axi_ob_config {
+ struct axi_ob_addr0 addr0;
+ struct axi_ob_addr1 addr1;
+ struct axi_ob_desc0 desc0;
+ struct axi_ob_desc1 desc1;
+ struct axi_ob_desc2 desc2;
+ struct axi_ob_desc3 desc3;
+ struct axi_ob_axi_base_addr0 axi_base_addr0;
+ struct axi_ob_axi_base_addr1 axi_base_addr1;
+};
+
+/*
+ * Identifiers of PCIe initialization stages
+ */
+enum pcie_init_stage {
+ /* PHY initialization stage */
+ PCIE_INIT_STAGE_PHY,
+
+ /* Controller initialization stage */
+ PCIE_INIT_STAGE_CTRL,
+
+ /* Link training stage */
+ PCIE_INIT_STAGE_LINK_TRNG,
+
+ /* PCIe initialization stages */
+ PCIE_INIT_STAGE_COUNT,
+};
+
+/*
+ * Structure defining data to be passed to timer API
+ */
+struct wait_condition_data {
+ void *ctrl_apb;
+ enum pcie_init_stage stage;
+};
+
+/*
+ * Driver function prototypes
+ */
+
+/*
+ * Brief - Function to setup an outbound region for translating
+ * incoming AXI address to outgoing PCIe address.
+ *
+ * param - axi_config_base_addr - APB address of AXI configuration space
+ * param - axi_base_addr - AXI incoming base address
+ * param - region_size - Region size of the outbound region
+ * param - trans_type - Transaction type this region will generate when
+ * accessed
+ *
+ * retval - FWK_SUCCESS - if the operation is succeeded
+ * FWK_E_RANGE - if the maximum outbound region is exceeded
+ */
+int axi_outbound_region_setup(uint32_t axi_config_base_addr,
+ uint64_t axi_base_addr,
+ uint32_t region_size,
+ uint8_t trans_type);
+
+/*
+ * Brief - Function to setup an inbound region for translating
+ * incoming PCIe address to AXI address.
+ *
+ * param - axi_config_base_addr - APB address of AXI configuration space
+ * param - axi_base_addr - AXI base address
+ * param - region_size - Region size of the inbound region
+ * param - bar - BAR number to which this inbound region will be setup
+ *
+ * retval - FWK_SUCCESS - if the operation is succeeded
+ * FWK_E_PARAM - if the passed parameters are invalid
+ */
+int axi_inbound_region_setup(uint32_t axi_config_base_addr,
+ uint64_t axi_base_addr,
+ uint32_t region_size,
+ uint8_t bar);
+
+/*
+ * Brief - Function to initialize different stages of PCIe module.
+ *
+ * param - ctrl_apb - Pointer to APB controller register space
+ * param - timer_api - Pointer to timer API used for timeout detection
+ * param - stage - Identifier of current PCIe initialization stage
+ *
+ * retval - FWK_SUCCESS - if the operation is succeeded
+ * FWK_E_TIMEOUT - if initialization times out
+ */
+int pcie_init(struct pcie_ctrl_apb_reg *ctrl_apb,
+ struct mod_timer_api *timer_api,
+ enum pcie_init_stage stage);
+
+/*
+ * Brief - Function to write to Root Port's/End Point's configuration space.
+ *
+ * param - base - Base address of RP/EP's configuration memory
+ * param - offset - Register offset from base (must be word aligned)
+ * param - value - Value to write to the configuration space register
+ *
+ * retval - FWK_SUCCESS - if the operation is succeeded
+ * FWK_E_PARAM - if offset is not word aligned
+ */
+int pcie_rp_ep_config_write_word(uint32_t base,
+ uint32_t offset,
+ uint32_t value);
+
+/*
+ * Brief - Function to read from Root Port's/End Point's configuration space.
+ *
+ * param - base - Base address of RP/EP's configuration memory
+ * param - offset - Register offset from base (must be word aligned)
+ * param - value - Pointer to hold the read value
+ *
+ * retval - FWK_SUCCESS - if the operation is succeeded
+ * FWK_E_PARAM - if offset is not word aligned or value is NULL
+ */
+int pcie_rp_ep_config_read_word(uint32_t base,
+ uint32_t offset,
+ uint32_t *value);
+
+#endif /* N1SDP_PCIE_H */