diff options
author | Manoj Kumar <manoj.kumar3@arm.com> | 2018-11-28 19:12:02 +0530 |
---|---|---|
committer | ronald-cron-arm <39518861+ronald-cron-arm@users.noreply.github.com> | 2018-11-30 12:46:36 +0100 |
commit | d5d9194118b795cda4fc7e53e797b07a8cc35d65 (patch) | |
tree | 8fead8b892bfaccdf44608900d37a20a38d83791 | |
parent | c90a10c8eed9a13a3c8a5935e7934969c913968f (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.h | 190 | ||||
-rw-r--r-- | product/n1sdp/module/n1sdp_pcie/include/mod_n1sdp_pcie.h | 74 | ||||
-rw-r--r-- | product/n1sdp/module/n1sdp_pcie/src/Makefile | 11 | ||||
-rw-r--r-- | product/n1sdp/module/n1sdp_pcie/src/mod_n1sdp_pcie.c | 358 | ||||
-rw-r--r-- | product/n1sdp/module/n1sdp_pcie/src/n1sdp_pcie.c | 187 | ||||
-rw-r--r-- | product/n1sdp/module/n1sdp_pcie/src/n1sdp_pcie.h | 431 |
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 */ |