From 6fdc649acef185f5ade4b29afda8f1af8d111611 Mon Sep 17 00:00:00 2001 From: Manoj Kumar Date: Fri, 18 Jan 2019 11:11:50 +0530 Subject: n1sdp: add fixes for pcie driver This patch fixes: - Type 0 & 1 configuration for both PCIe & CCIX RCs - Enable Type 1 MEM & IO bars in root ports - Log negotiated speed and lane count Change-Id: Id3a9996ff79e9db30aac19756df7df48a2273478 Signed-off-by: Manoj Kumar --- .../n1sdp/module/n1sdp_pcie/src/mod_n1sdp_pcie.c | 57 +++++++++++++++++++++- product/n1sdp/module/n1sdp_pcie/src/n1sdp_pcie.c | 20 +++++--- product/n1sdp/module/n1sdp_pcie/src/n1sdp_pcie.h | 38 +++++++++++++-- 3 files changed, 103 insertions(+), 12 deletions(-) diff --git a/product/n1sdp/module/n1sdp_pcie/src/mod_n1sdp_pcie.c b/product/n1sdp/module/n1sdp_pcie/src/mod_n1sdp_pcie.c index 5d85548d..698c3fd1 100644 --- a/product/n1sdp/module/n1sdp_pcie/src/mod_n1sdp_pcie.c +++ b/product/n1sdp/module/n1sdp_pcie/src/mod_n1sdp_pcie.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -92,14 +93,39 @@ struct n1sdp_pcie_ctx pcie_ctx; static int n1sdp_pcie_setup(struct n1sdp_pcie_dev_ctx *dev_ctx) { uint32_t ecam_base_addr; + uint8_t neg_config; + struct pcie_wait_condition_data wait_data; int status; /* Enable the CCIX/PCIe controller */ + wait_data.ctrl_apb = NULL; if (dev_ctx->config->ccix_capable) { SCC->CCIX_PM_CTRL = SCC_CCIX_PM_CTRL_PWR_REQ_POS; + wait_data.stage = PCIE_INIT_STAGE_CCIX_POWER_ON; + status = pcie_ctx.timer_api->wait(FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, + 0), + PCIE_POWER_ON_TIMEOUT, + pcie_wait_condition, + &wait_data); + if (status != FWK_SUCCESS) { + pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, + "[PCIe] Controller power-on failed!\n"); + return status; + } SCC->SYS_MAN_RESET &= ~(1 << SCC_SYS_MAN_RESET_CCIX_POS); } else { SCC->PCIE_PM_CTRL = SCC_PCIE_PM_CTRL_PWR_REQ_POS; + wait_data.stage = PCIE_INIT_STAGE_PCIE_POWER_ON; + status = pcie_ctx.timer_api->wait(FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, + 0), + PCIE_POWER_ON_TIMEOUT, + pcie_wait_condition, + &wait_data); + if (status != FWK_SUCCESS) { + pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, + "[PCIe] Controller power-on failed!\n"); + return status; + } SCC->SYS_MAN_RESET &= ~(1 << SCC_SYS_MAN_RESET_PCIE_POS); } @@ -138,10 +164,25 @@ static int n1sdp_pcie_setup(struct n1sdp_pcie_dev_ctx *dev_ctx) } pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, "Done\n"); + neg_config = (dev_ctx->ctrl_apb->RP_CONFIG_OUT & + RP_CONFIG_OUT_NEGOTIATED_SPD_MASK) >> RP_CONFIG_OUT_NEGOTIATED_SPD_POS; + pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, + "[PCIe] Negotiated speed: GEN%d\n", neg_config + 1); + + neg_config = (dev_ctx->ctrl_apb->RP_CONFIG_OUT & + RP_CONFIG_OUT_NEGOTIATED_LINK_WIDTH_MASK) >> + RP_CONFIG_OUT_NEGOTIATED_LINK_WIDTH_POS; + pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, + "[PCIe] Negotiated link width: x%d\n", fwk_math_pow2(neg_config)); + /* 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 + + if (dev_ctx->config->ccix_capable) + ecam_base_addr = dev_ctx->config->axi_slave_base32 + + CCIX_AXI_ECAM_TYPE0_OFFSET; + else + 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), @@ -155,7 +196,11 @@ static int n1sdp_pcie_setup(struct n1sdp_pcie_dev_ctx *dev_ctx) pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, "[PCIe] Setup Type1 configuration..."); - ecam_base_addr = dev_ctx->config->axi_slave_base32 + + if (dev_ctx->config->ccix_capable) + ecam_base_addr = dev_ctx->config->axi_slave_base32 + + CCIX_AXI_ECAM_TYPE1_OFFSET; + else + 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), @@ -237,6 +282,14 @@ static int n1sdp_pcie_setup(struct n1sdp_pcie_dev_ctx *dev_ctx) } pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, "Done\n"); + pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, + "[PCIe] Enable Type 1 I/O configuration\n"); + *(uint32_t *)(dev_ctx->lm_apb + PCIE_LM_RC_BAR_CONFIG_REG) = + (TYPE1_PREF_MEM_BAR_ENABLE_MASK | + TYPE1_PREF_MEM_BAR_SIZE_64BIT_MASK | + TYPE1_PREF_IO_BAR_ENABLE_MASK | + TYPE1_PREF_IO_BAR_SIZE_32BIT_MASK); + return FWK_SUCCESS; } diff --git a/product/n1sdp/module/n1sdp_pcie/src/n1sdp_pcie.c b/product/n1sdp/module/n1sdp_pcie/src/n1sdp_pcie.c index 15f0806d..e3594296 100644 --- a/product/n1sdp/module/n1sdp_pcie/src/n1sdp_pcie.c +++ b/product/n1sdp/module/n1sdp_pcie/src/n1sdp_pcie.c @@ -14,16 +14,22 @@ #include #include #include +#include -static bool wait_condition(void *data) +bool pcie_wait_condition(void *data) { assert(data != NULL); - struct wait_condition_data *wait_data = (struct wait_condition_data *)data; + struct pcie_wait_condition_data *wait_data = + (struct pcie_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_PCIE_POWER_ON: + return ((SCC->PCIE_PM_CTRL & SCC_PCIE_PM_CTRL_PWR_ACK_MASK) != 0); + case PCIE_INIT_STAGE_CCIX_POWER_ON: + return ((SCC->CCIX_PM_CTRL & SCC_CCIX_PM_CTRL_PWR_ACK_MASK) != 0); case PCIE_INIT_STAGE_PHY: return ((ctrl_apb->RESET_STATUS & RESET_STATUS_PHY_REL_ST_MASK) != 0); @@ -46,7 +52,7 @@ int pcie_init(struct pcie_ctrl_apb_reg *ctrl_apb, assert(timer_api != NULL); assert(stage < PCIE_INIT_STAGE_COUNT); - struct wait_condition_data wait_data; + struct pcie_wait_condition_data wait_data; int status; wait_data.ctrl_apb = ctrl_apb; @@ -58,7 +64,7 @@ int pcie_init(struct pcie_ctrl_apb_reg *ctrl_apb, 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, + pcie_wait_condition, &wait_data); if (status != FWK_SUCCESS) return status; @@ -69,10 +75,12 @@ int pcie_init(struct pcie_ctrl_apb_reg *ctrl_apb, /* 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->RP_CONFIG_IN = (0x4 << RP_CONFIG_IN_LANE_CNT_IN_POS) | + (0x1 << RP_CONFIG_IN_PCIE_GEN_SEL_POS); 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, + pcie_wait_condition, &wait_data); if (status != FWK_SUCCESS) return status; @@ -83,7 +91,7 @@ int pcie_init(struct pcie_ctrl_apb_reg *ctrl_apb, 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, + pcie_wait_condition, &wait_data); if (status != FWK_SUCCESS) return status; diff --git a/product/n1sdp/module/n1sdp_pcie/src/n1sdp_pcie.h b/product/n1sdp/module/n1sdp_pcie/src/n1sdp_pcie.h index 2d6ad80d..37c2cfed 100644 --- a/product/n1sdp/module/n1sdp_pcie/src/n1sdp_pcie.h +++ b/product/n1sdp/module/n1sdp_pcie/src/n1sdp_pcie.h @@ -66,7 +66,10 @@ */ #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) +#define PCIE_LINK_TRAINING_TIMEOUT UINT32_C(50000) + +/* PCIe controller power on timeout (in microseconds) */ +#define PCIE_POWER_ON_TIMEOUT UINT32_C(10) /* PCIe configuration space offset definitions */ #define PCIE_CLASS_CODE_OFFSET 0x8 @@ -74,6 +77,17 @@ /* PCIe class code for PCI bridge */ #define PCIE_CLASS_CODE_PCI_BRIDGE UINT32_C(0x06040000) +/* PCIe controller local management (LM) register offsets */ +#define PCIE_LM_RC_BAR_CONFIG_REG UINT32_C(0x300) + +/* PCIe LM root complex bar configuration register bit masks */ +#define TYPE1_PREF_MEM_BAR_ENABLE_MASK (1U << 17) +#define TYPE1_PREF_MEM_BAR_SIZE_32BIT_MASK (0U << 18) +#define TYPE1_PREF_MEM_BAR_SIZE_64BIT_MASK (1U << 18) +#define TYPE1_PREF_IO_BAR_ENABLE_MASK (1U << 19) +#define TYPE1_PREF_IO_BAR_SIZE_32BIT_MASK (0U << 20) +#define TYPE1_PREF_IO_BAR_SIZE_64BIT_MASK (1U << 20) + /* * 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 @@ -90,7 +104,7 @@ /* Maximum bus levels for type 0 and type 1 transactions */ #define MAX_TYPE0_BUS_LEVELS 2 -#define MAX_TYPE1_BUS_LEVELS 8 +#define MAX_TYPE1_BUS_LEVELS 16 /* Maximum AXI space for type 0 and type 1 transactions */ #define AXI_ECAM_TYPE0_SIZE (MAX_TYPE0_BUS_LEVELS * \ @@ -114,7 +128,7 @@ /* * CCIX AXI slave ECAM memory mapping */ -#define CCIX_AXI_ECAM_TYPE0_OFFSET (16 * FWK_MIB) +#define CCIX_AXI_ECAM_TYPE0_OFFSET (32 * FWK_MIB) #define CCIX_AXI_ECAM_TYPE1_OFFSET (CCIX_AXI_ECAM_TYPE0_OFFSET + \ AXI_ECAM_TYPE0_SIZE) @@ -326,6 +340,12 @@ struct axi_ob_config { * Identifiers of PCIe initialization stages */ enum pcie_init_stage { + /* PCIe controller power ON stage */ + PCIE_INIT_STAGE_PCIE_POWER_ON, + + /* CCIX controller power ON stage */ + PCIE_INIT_STAGE_CCIX_POWER_ON, + /* PHY initialization stage */ PCIE_INIT_STAGE_PHY, @@ -342,7 +362,7 @@ enum pcie_init_stage { /* * Structure defining data to be passed to timer API */ -struct wait_condition_data { +struct pcie_wait_condition_data { void *ctrl_apb; enum pcie_init_stage stage; }; @@ -386,6 +406,16 @@ int axi_inbound_region_setup(uint32_t axi_config_base_addr, uint32_t region_size, uint8_t bar); +/* + * Brief - Function to check PCIe status in various initialization stages. + * + * param - data - Pointer to wait condition data + * + * retval - true - if the condition is met + * false - if the condition is not met + */ +bool pcie_wait_condition(void *data); + /* * Brief - Function to initialize different stages of PCIe module. * -- cgit v1.2.3