diff --git a/module/cmn600/src/mod_cmn600.c b/module/cmn600/src/mod_cmn600.c index 3704ab83f573b72dfda6a55aaf88d3040277ac9a..ec5922a3ed159b30caaf53a80d8b79d6792e2329 100644 --- a/module/cmn600/src/mod_cmn600.c +++ b/module/cmn600/src/mod_cmn600.c @@ -528,7 +528,7 @@ int cmn600_setup_sam(struct cmn600_rnsam_reg *rnsam) /* Use CAL mode only if the CMN600 revision is r2p0 or above */ if (is_cal_mode_supported(ctx->root) && config->hnf_cal_mode) { for (region_idx = 0; region_idx < CMN600_MAX_NUM_SCG; region_idx++) - rnsam->SYS_CACHE_GRP_CAL_MODE = scg_regions_enabled[region_idx] * + rnsam->SYS_CACHE_GRP_CAL_MODE |= scg_regions_enabled[region_idx] * (CMN600_RNSAM_SCG_HNF_CAL_MODE_EN << (region_idx * CMN600_RNSAM_SCG_HNF_CAL_MODE_SHIFT)); } diff --git a/module/cmn_rhodes/include/internal/cmn_rhodes_ctx.h b/module/cmn_rhodes/include/internal/cmn_rhodes_ctx.h index 0b692dc8ca4c3a4034acda6f40e3ff0b9d3bb873..b7c622fca560bccb659eb4ceea28b51d7ded28e5 100644 --- a/module/cmn_rhodes/include/internal/cmn_rhodes_ctx.h +++ b/module/cmn_rhodes/include/internal/cmn_rhodes_ctx.h @@ -18,13 +18,17 @@ #include #include -static struct cmn_rhodes_ctx { +struct cmn_rhodes_device_ctx { const struct mod_cmn_rhodes_config *config; struct cmn_rhodes_cfgm_reg *root; /* Number of HN-F (system cache) nodes in the system */ unsigned int hnf_count; + + /* Pointer to list of HN-F nodes for use in CCIX programming */ + uintptr_t *hnf_node; + uint64_t *hnf_cache_group; uint64_t *sn_nodeid_group; @@ -43,8 +47,38 @@ static struct cmn_rhodes_ctx { unsigned int internal_rnsam_count; struct cmn_rhodes_rnsam_reg **internal_rnsam_table; - bool initialized; -} *ctx; + /* Count of RN Nodes for the use in CCIX programming */ + unsigned int rnd_count; + unsigned int rnf_count; + unsigned int rni_count; + + /* CCIX specific members */ + + /* Node count of CXG_RA, CXG_HA, CXLA nodes each. */ + size_t ccix_node_count; + + /* + * CXG_RA register and node_id pairs. The driver keeps a list of tuples of + * pointers to the CXG_RA registers. + */ + struct cxg_ra_reg_tuple *cxg_ra_reg_table; + /* + * CXG_HA register and node_id pairs. The driver keeps a list of tuples of + * pointers to the CXG_HA registers. + */ + struct cxg_ha_reg_tuple *cxg_ha_reg_table; + + /* + * CXLA register and node_id pairs. The driver keeps a list of tuples of + * pointers to the CXLA registers. + */ + struct cxla_reg_tuple *cxla_reg_table; + + /* Timer module API */ + struct mod_timer_api *timer_api; + + bool initialized; +}; -#endif /* INTERNAL_CMN600_CTX_H */ +#endif /* INTERNAL_CMN_RHODES_CTX_H */ diff --git a/module/cmn_rhodes/include/mod_cmn_rhodes.h b/module/cmn_rhodes/include/mod_cmn_rhodes.h index a3236dc136740688028033d0954f8803bf6dba25..902f4a278abf1e4fcfe97baeabfffa3250fa778f 100644 --- a/module/cmn_rhodes/include/mod_cmn_rhodes.h +++ b/module/cmn_rhodes/include/mod_cmn_rhodes.h @@ -28,6 +28,12 @@ * @{ */ +/*! Maximum CCIX Protocol Links supported by CCIX Gateway (CXG) */ +#define CMN_RHODES_MAX_CCIX_PROTOCOL_LINKS 3 + +/*! Maximum RA SAM Address regions */ +#define CMN_RHODES_MAX_RA_SAM_ADDR_REGION 8 + /*! * \brief Module API indices */ @@ -57,6 +63,11 @@ enum mod_cmn_rhodes_mem_region_type { * dedicated SN-F nodes). */ MOD_CMN_RHODES_REGION_TYPE_SYSCACHE_SUB, + + /*! + * Region used for CCIX access (serviced by the CXRA nodes). + */ + MOD_CMN_RHODES_REGION_TYPE_CCIX, }; /*! @@ -76,14 +87,121 @@ struct mod_cmn_rhodes_mem_region_map { * \brief Target node identifier * * \note Not used for \ref - * mod_cmn_rhodes_mem_region_type. - * MOD_CMN_RHODES_MEM_REGION_TYPE_SYSCACHE - * memory regions as it uses the pool of HN-F nodes available in the - * system + * mod_cmn_rhodes_mem_region_type.MOD_CMN_RHODES_REGION_TYPE_SYSCACHE_SUB + * memory regions as it uses the pool of HN-F nodes available in the + * system */ unsigned int node_id; }; +/*! + * \brief Remote Agent to Link ID mapping + * + * \details Each CCIX Gateway block (CXG) can communicate up to three remote + * CCIX protocol links. Each remote agent, identified by their AgentID (RAID + * or HAID) will be behind one of these three links. This structure holds the + * start and end Agent IDs for each link. The remote AgentID to LinkID LUT + * registers (por_{cxg_ra,cxg_ha, cxla}_agentid_to_linkid_reg) will be + * configured sequentially from \ref + * mod_cmn_rhodes_agentid_to_linkid_map.remote_agentid_start + * and \ref mod_cmn_rhodes_agentid_to_linkid_map.remote_agentid_end values. For + * all three links, corresponding to these remote Agent IDs, HN-F's RN_PHYS_ID + * registers will be programmed with the node id of the CXG Gateway block. + * + */ +struct mod_cmn_rhodes_agentid_to_linkid_map { + /*! Remote Agent ID start */ + unsigned int remote_agentid_start; + + /*! Remote Agent ID end */ + unsigned int remote_agentid_end; +}; + +/*! + * \brief Remote Memory region map descriptor which will be used by CXRA SAM + * programming + */ +struct mod_cmn_rhodes_ra_mem_region_map { + /*! Base address */ + uint64_t base; + + /*! Region size in bytes */ + uint64_t size; + + /*! Target HAID of remote CXG gateway for CXRA SAM Address region */ + unsigned int remote_haid; +}; + +/*! + * \brief CCIX Gateway block descriptor + * + * \details Each CCIX Gateway block (CXG) can have up to eight remote memory map + * \ref mod_cmn_rhodes_ra_mem_region_map descriptors and can have three links + * which can target range of remote agent ids. User is expected to assign an + * Home AgentID (HAID) \ref mod_cmn_rhodes_ccix_config.haid for each logical ids + * of the CXG blocks. Overall structure of the descriptor is shown below: + * + * +----------------------------------------------------------+ + * | mod_cmn_rhodes_ccix_config | + * | | + * | HAID = haid | + * +----------------------------------------------------------+ + * | ra_mmap_table0 | agentid_to_linkid_map0| + * | | remote_agent_id_start| + * | base..base+size --> remote_haid | . | + * | | . | + * +----------------------------------+ . | + * | ra_mmap_table1 | . | + * | | remote_agent_id_end | + * | base..base+size --> remote_haid | | + * | +-----------------------+ + * +----------------------------------+ agentid_to_linkid_map1| + * | . | remote_agent_id_start| + * | . | . | + * | . | . | + * | . | . | + * | . | . | + * | . | remote_agent_id_end | + * +----------------------------------+ | + * | ra_mmap_table6 +-----------------------+ + * | | agentid_to_linkid_map2| + * | base..base+size --> remote_haid | remote_agent_id_start| + * | | . | + * +----------------------------------+ . | + * | ra_mmap_table7 | . | + * | | . | + * | base..base+size --> remote_haid | remote_agent_id_end | + * | | | + * +----------------------------------+-----------------------+ + */ +struct mod_cmn_rhodes_ccix_config { + /*! Logical ID of the CXG block to which this configuration applies */ + unsigned int ldid; + + /*! Unique HAID in a multi-chip system. This has to be assigned manually */ + unsigned int haid; + + /*! Number of remote RN Caching agents. */ + unsigned int remote_rnf_count; + + /*! Table of region memory map entries */ + const struct mod_cmn_rhodes_mem_region_map remote_mmap_table; + + /*! Table of remote region memory map entries */ + const struct mod_cmn_rhodes_ra_mem_region_map + ra_mmap_table[CMN_RHODES_MAX_RA_SAM_ADDR_REGION]; + + /*! Number of entries in the \ref ra_mmap_table */ + size_t ra_mmap_count; + + /*! Table of remote agent ids start and end backed by the links */ + struct mod_cmn_rhodes_agentid_to_linkid_map + remote_agentid_to_linkid_map[CMN_RHODES_MAX_CCIX_PROTOCOL_LINKS]; + + /*! SMP Mode */ + bool smp_mode; +}; + /*! * \brief CMN_RHODES configuration data */ @@ -118,6 +236,15 @@ struct mod_cmn_rhodes_config { /*! Number of entries in the \ref mmap_table */ size_t mmap_count; + /*! Table of CCIX configuration */ + const struct mod_cmn_rhodes_ccix_config *ccix_config_table; + + /*! Number of entries in the \ref ccix_config_table table */ + const size_t ccix_table_count; + + /*! Address space size of the chip */ + uint64_t chip_addr_space; + /*! Identifier of the clock that this device depends on */ fwk_id_t clock_id; diff --git a/module/cmn_rhodes/src/Makefile b/module/cmn_rhodes/src/Makefile index b7b87dbf79f0bc8053d90cdab605f08532683fa1..00465fcc15eb00fb2ae43ef0887f0a9f7dc75123 100644 --- a/module/cmn_rhodes/src/Makefile +++ b/module/cmn_rhodes/src/Makefile @@ -8,6 +8,6 @@ BS_LIB_NAME := CMN_RHODES BS_LIB_SOURCES = mod_cmn_rhodes.c -BS_LIB_SOURCES += cmn_rhodes.c +BS_LIB_SOURCES += cmn_rhodes.c cmn_rhodes_ccix.c include $(BS_DIR)/lib.mk diff --git a/module/cmn_rhodes/src/cmn_rhodes.c b/module/cmn_rhodes/src/cmn_rhodes.c index d76390346c273856ae66ccd408055745d9d0ffb2..664f551b5d4ded03395fa9ad0f1060aedaa8e9cf 100644 --- a/module/cmn_rhodes/src/cmn_rhodes.c +++ b/module/cmn_rhodes/src/cmn_rhodes.c @@ -116,6 +116,9 @@ uint64_t sam_encode_region_size(uint64_t size) /* Size must be a multiple of SAM_GRANULARITY */ fwk_assert((size % SAM_GRANULARITY) == 0); + /* Size also must be a power of two */ + fwk_assert((size & (size - 1)) == 0); + blocks = size / SAM_GRANULARITY; result = fwk_math_log2(blocks); @@ -148,6 +151,8 @@ static const char * const type_to_name[] = { [NODE_TYPE_HN_F] = "HN-F", [NODE_TYPE_XP] = "XP", [NODE_TYPE_SBSX] = "SBSX", + [NODE_TYPE_MPAM_S] = "MPAM-S", + [NODE_TYPE_MPAM_NS] = "MPAM-NS", [NODE_TYPE_RN_I] = "RN-I", [NODE_TYPE_RN_D] = "RN-D", [NODE_TYPE_RN_SAM] = "RN-SAM", diff --git a/module/cmn_rhodes/src/cmn_rhodes.h b/module/cmn_rhodes/src/cmn_rhodes.h index 6a45cd6d8c7e339107ebc436368ae0028099765e..f8aea442cd611426446c2603f19033cbf35b3ea1 100644 --- a/module/cmn_rhodes/src/cmn_rhodes.h +++ b/module/cmn_rhodes/src/cmn_rhodes.h @@ -28,12 +28,34 @@ /* SAM Granularity of RN-SAM and HN-F SAM */ #define SAM_GRANULARITY (64 * FWK_MIB) +/* Macros to split 64 bit value two 32 bit values */ +#define HIGH_WORD(x) ((unsigned int)((((x) & 0xFFFFFFFF00000000ULL) >> 32))) +#define LOW_WORD(x) ((unsigned int)((x) & 0xFFFFFFFF)) + /* External nodes that require RN-SAM mapping during run-time */ struct external_rnsam_tuple { unsigned int node_id; struct cmn_rhodes_rnsam_reg *node; }; +/* Pair of CCIX Request Agent (CXG_RA) register and its node-id */ +struct cxg_ra_reg_tuple { + unsigned int node_id; + struct cmn_rhodes_cxg_ra_reg *cxg_ra_reg; +}; + +/* Pair of CCIX Request Agent (CXG_HA) register and its node-id */ +struct cxg_ha_reg_tuple { + unsigned int node_id; + struct cmn_rhodes_cxg_ha_reg *cxg_ha_reg; +}; + +/* Pair of CCIX Link Agent (CXLA) register and its node-id */ +struct cxla_reg_tuple { + unsigned int node_id; + struct cmn_rhodes_cxla_reg *cxla_reg; +}; + enum node_type { NODE_TYPE_INVALID = 0x0, NODE_TYPE_DVM = 0x1, @@ -43,6 +65,8 @@ enum node_type { NODE_TYPE_HN_F = 0x5, NODE_TYPE_XP = 0x6, NODE_TYPE_SBSX = 0x7, + NODE_TYPE_MPAM_S = 0x8, + NODE_TYPE_MPAM_NS = 0x9, NODE_TYPE_RN_I = 0xA, NODE_TYPE_RN_D = 0xD, NODE_TYPE_RN_SAM = 0xF, @@ -98,7 +122,8 @@ struct cmn_rhodes_rnsam_reg { FWK_RW uint64_t SYS_CACHE_GRP_SN_NODEID[16]; uint8_t RESERVED8[0x1100 - 0x1080]; FWK_RW uint64_t STATUS; - uint8_t RESERVED9[0x1120 - 0x1108]; + uint64_t GIC_MEM_REGION; + uint8_t RESERVED9[0x1120 - 0x1110]; FWK_RW uint64_t SYS_CACHE_GRP_CAL_MODE; }; @@ -114,10 +139,105 @@ struct cmn_rhodes_hnf_reg { uint8_t RESERVED2[0xD00 - 0x908]; FWK_RW uint64_t SAM_CONTROL; FWK_RW uint64_t SAM_MEMREGION[2]; - uint8_t RESERVED8[0x1C00 - 0xD18]; + uint8_t RESERVED3[0xD28 - 0xD18]; + FWK_RW uint64_t RN_PHYS_ID[32]; + uint8_t RESERVED4[0x1C00 - 0xE28]; FWK_RW uint64_t PPU_PWPR; }; +/* + * CCIX Gateway (CXG) protocol link control & status registers + */ +struct cxg_link_regs { + FWK_RW uint64_t CXG_PRTCL_LINK_CTRL; + FWK_R uint64_t CXG_PRTCL_LINK_STATUS; +}; + +/* + * CCIX Gateway (CXG) Requesting Agent (RA) registers + */ +struct cmn_rhodes_cxg_ra_reg { + FWK_R uint64_t CXG_RA_NODE_INFO; + uint8_t RESERVED0[0x80-0x8]; + FWK_R uint64_t CXG_RA_CHILD_INFO; + uint8_t RESERVED1[0x900-0x88]; + FWK_R uint64_t CXG_RA_UNIT_INFO; + uint8_t RESERVED2[0x980-0x908]; + FWK_RW uint64_t CXG_RA_SEC_REG_GRP_OVERRIDE; + uint8_t RESERVED3[0xA00-0x988]; + FWK_RW uint64_t CXG_RA_CFG_CTRL; + FWK_RW uint64_t CXG_RA_AUX_CTRL; + uint8_t RESERVED4[0xDA8-0xA10]; + FWK_RW uint64_t CXG_RA_SAM_ADDR_REGION_REG[8]; + uint8_t RESERVED5[0xE00-0xDE8]; + FWK_RW uint64_t CXG_RA_SAM_MEM_REGION_LIMIT_REG[8]; + uint8_t RESERVED6[0xE60-0xE40]; + FWK_RW uint64_t CXG_RA_AGENTID_TO_LINKID_REG[8]; + FWK_RW uint64_t CXG_RA_RNF_LDID_TO_RAID_REG[8]; + FWK_RW uint64_t CXG_RA_RNI_LDID_TO_RAID_REG[4]; + FWK_RW uint64_t CXG_RA_RND_LDID_TO_RAID_REG[4]; + FWK_RW uint64_t CXG_RA_AGENTID_TO_LINKID_VAL; + FWK_RW uint64_t CXG_RA_RNF_LDID_TO_RAID_VAL; + FWK_RW uint64_t CXG_RA_RNI_LDID_TO_RAID_VAL; + FWK_RW uint64_t CXG_RA_RND_LDID_TO_RAID_VAL; + uint8_t RESERVED7[0x1C00-0xF40]; + struct cxg_link_regs LINK_REGS[3]; + uint8_t RESERVED8[0x2000-0x1030]; + FWK_RW uint64_t CXG_RA_PMU_EVENT_SEL; +}; + +/* + * CCIX Gateway (CXG) Home Agent (HA) registers + */ +struct cmn_rhodes_cxg_ha_reg { + FWK_R uint64_t CXG_HA_NODE_INFO; + FWK_RW uint64_t CXG_HA_ID; + uint8_t RESERVED0[0x80-0x10]; + FWK_R uint64_t CXG_HA_CHILD_INFO; + uint8_t RESERVED1[0x900-0x88]; + FWK_R uint64_t CXG_HA_UNIT_INFO; + uint8_t RESERVED2[0x980-0x908]; + FWK_RW uint64_t CXG_HA_SEC_REG_GRP_OVERRIDE; + uint8_t RESERVED3[0xA08-0x988]; + FWK_RW uint64_t CXG_HA_AUX_CTRL; + uint8_t RESERVED4[0xC00-0xA10]; + FWK_RW uint64_t CXG_HA_RNF_RAID_TO_LDID_REG[8]; + FWK_RW uint64_t CXG_HA_AGENTID_TO_LINKID_REG[8]; + uint8_t RESERVED5[0xD00-0xC80]; + FWK_RW uint64_t CXG_HA_AGENTID_TO_LINKID_VAL; + FWK_RW uint64_t CXG_HA_RNF_RAID_TO_LDID_VAL; + uint8_t RESERVED6[0x1C00-0xD10]; + struct cxg_link_regs LINK_REGS[3]; + uint8_t RESERVED7[0x2000-0x1030]; + FWK_RW uint64_t CXG_HA_PMU_EVENT_SEL; +}; + +/* + * CCIX Gateway (CXG) Link Agent (LA) registers + */ +struct cmn_rhodes_cxla_reg { + FWK_R uint64_t CXLA_NODE_INFO; + uint8_t RESERVED0[0x80-0x8]; + FWK_R uint64_t CXLA_CHILD_INFO; + uint8_t RESERVED1[0x900-0x88]; + FWK_R uint64_t CXLA_UNIT_INFO; + uint8_t RESERVED2[0x980-0x908]; + FWK_RW uint64_t CXLA_SEC_REG_GRP_OVERRIDE; + uint8_t RESERVED3[0xA08-0x988]; + FWK_RW uint64_t CXLA_AUX_CTRL; + uint8_t RESERVED4[0xC00-0xA10]; + FWK_R uint64_t CXLA_CCIX_PROP_CAPABILITIES; + FWK_RW uint64_t CXLA_CCIX_PROP_CONFIGURED; + FWK_R uint64_t CXLA_TX_CXS_ATTR_CAPABILITIES; + FWK_R uint64_t CXLA_RX_CXS_ATTR_CAPABILITIES; + uint8_t RESERVED5[0xC30-0xC20]; + FWK_RW uint64_t CXLA_AGENTID_TO_LINKID_REG[8]; + FWK_RW uint64_t CXLA_AGENTID_TO_LINKID_VAL; + FWK_RW uint64_t CXLA_LINKID_TO_PCIE_BUS_NUM; + FWK_RW uint64_t CXLA_PCIE_HDR_FIELDS; +}; + + /* * Configuration slave registers */ diff --git a/module/cmn_rhodes/src/cmn_rhodes_ccix.c b/module/cmn_rhodes/src/cmn_rhodes_ccix.c new file mode 100644 index 0000000000000000000000000000000000000000..9cfd058224cb4d4f51a9f55e2eb66f51b2281f67 --- /dev/null +++ b/module/cmn_rhodes/src/cmn_rhodes_ccix.c @@ -0,0 +1,736 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include + +#include + +#include +#include +#include + +#define MOD_NAME "[CMN_RHODES_CCIX] " + +/* RAID value common to all function */ +static uint8_t raid_value; + +/* Pointer to the current CCIX configuration data */ +static const struct mod_cmn_rhodes_ccix_config *config; + +static bool cxg_link_wait_condition(void *data) +{ + uint64_t val1; + uint64_t val2; + uint8_t linkid; + struct cmn_rhodes_cxg_ra_reg *cxg_ra_reg; + struct cmn_rhodes_cxg_ha_reg *cxg_ha_reg; + + fwk_assert(data != NULL); + + struct cxg_wait_condition_data *wait_data = + (struct cxg_wait_condition_data *)data; + struct cmn_rhodes_device_ctx *ctx = wait_data->ctx; + linkid = wait_data->linkid; + + cxg_ra_reg = ctx->cxg_ra_reg_table[config->ldid].cxg_ra_reg; + cxg_ha_reg = ctx->cxg_ha_reg_table[config->ldid].cxg_ha_reg; + + switch (wait_data->cond) { + case CXG_LINK_CTRL_EN_BIT_SET: + val1 = cxg_ra_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_CTRL; + val2 = cxg_ha_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_CTRL; + return (((val1 & CXG_LINK_CTRL_EN_MASK) && + (val2 & CXG_LINK_CTRL_EN_MASK)) != 0); + + case CXG_LINK_CTRL_UP_BIT_CLR: + val1 = cxg_ra_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_CTRL; + val2 = cxg_ha_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_CTRL; + return ((((val1 & CXG_LINK_CTRL_UP_MASK) == 0) && + ((val2 & CXG_LINK_CTRL_UP_MASK) == 0)) != 0); + + case CXG_LINK_STATUS_DWN_BIT_SET: + val1 = cxg_ra_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_STATUS; + val2 = cxg_ha_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_STATUS; + return (((val1 & CXG_LINK_STATUS_DOWN_MASK) && + (val2 & CXG_LINK_STATUS_DOWN_MASK)) != 0); + + case CXG_LINK_STATUS_DWN_BIT_CLR: + val1 = cxg_ra_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_STATUS; + val2 = cxg_ha_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_STATUS; + return ((((val1 & CXG_LINK_STATUS_DOWN_MASK) == 0) && + ((val2 & CXG_LINK_STATUS_DOWN_MASK) == 0)) != 0); + + case CXG_LINK_STATUS_ACK_BIT_SET: + val1 = cxg_ra_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_STATUS; + val2 = cxg_ha_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_STATUS; + return (((val1 & CXG_LINK_STATUS_ACK_MASK) && + (val2 & CXG_LINK_STATUS_ACK_MASK)) != 0); + + case CXG_LINK_STATUS_ACK_BIT_CLR: + val1 = cxg_ra_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_STATUS; + val2 = cxg_ha_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_STATUS; + return ((((val1 & CXG_LINK_STATUS_ACK_MASK) == 0) && + ((val2 & CXG_LINK_STATUS_ACK_MASK) == 0)) != 0); + + case CXG_LINK_STATUS_HA_DVMDOMAIN_ACK_BIT_SET: + val1 = cxg_ha_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_STATUS; + return (((val1 & CXG_LINK_STATUS_DVMDOMAIN_ACK_MASK)) != 0); + + case CXG_LINK_STATUS_RA_DVMDOMAIN_ACK_BIT_SET: + val1 = cxg_ra_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_STATUS; + return (((val1 & CXG_LINK_STATUS_DVMDOMAIN_ACK_MASK)) != 0); + + default: + fwk_assert(false); + return false; + } +} + +static void program_cxg_ra_rnf_ldid_to_raid_reg( + struct cmn_rhodes_device_ctx *ctx, uint8_t ldid_value, uint8_t raid) +{ + uint32_t reg_offset = 0; + uint32_t ldid_value_offset = 0; + struct cmn_rhodes_cxg_ra_reg *cxg_ra_reg; + + cxg_ra_reg = ctx->cxg_ra_reg_table[config->ldid].cxg_ra_reg; + + /* Each 64-bit RA RNF LDID-to-RAID register holds 8 LDIDs */ + reg_offset = ldid_value / 8; + ldid_value_offset = ldid_value % 8; + + /* Adding raid_value into LDID-to-RAID register */ + cxg_ra_reg->CXG_RA_RNF_LDID_TO_RAID_REG[reg_offset] |= + ((uint64_t)raid << (ldid_value_offset * NUM_BITS_RESERVED_FOR_RAID)); + + /* Set corresponding valid bit */ + cxg_ra_reg->CXG_RA_RNF_LDID_TO_RAID_VAL |= ((uint64_t)0x1 << ldid_value); + + /* Increment the global raid_value */ + raid_value++; +} + +static void program_cxg_ra_rni_ldid_to_raid_reg( + struct cmn_rhodes_device_ctx * ctx, uint8_t ldid_value, uint8_t raid) +{ + uint32_t reg_offset = 0; + uint32_t ldid_value_offset = 0; + struct cmn_rhodes_cxg_ra_reg *cxg_ra_reg; + + cxg_ra_reg = ctx->cxg_ra_reg_table[config->ldid].cxg_ra_reg; + + /* Each 64-bit RA RNI LDID-to-RAID register holds 8 LDIDs */ + reg_offset = ldid_value / 8; + ldid_value_offset = ldid_value % 8; + + /* Adding raid_value into LDID-to-RAID register */ + cxg_ra_reg->CXG_RA_RNI_LDID_TO_RAID_REG[reg_offset] |= + ((uint64_t)raid << + (ldid_value_offset * NUM_BITS_RESERVED_FOR_RAID)); + + /* Set corresponding valid bit */ + cxg_ra_reg->CXG_RA_RNI_LDID_TO_RAID_VAL |= ((uint64_t)0x1 << ldid_value); + + /* Increment the global raid_value */ + raid_value++; +} + +static void program_cxg_ra_rnd_ldid_to_raid_reg( + struct cmn_rhodes_device_ctx *ctx, uint8_t ldid_value, uint8_t raid) +{ + uint32_t reg_offset = 0; + uint32_t ldid_value_offset = 0; + struct cmn_rhodes_cxg_ra_reg *cxg_ra_reg; + + cxg_ra_reg = ctx->cxg_ra_reg_table[config->ldid].cxg_ra_reg; + + /* Each 64-bit RA RND LDID-to-RAID register holds 8 LDIDs */ + reg_offset = ldid_value / 8; + ldid_value_offset = ldid_value % 8; + + /* Adding raid_value into LDID-to-RAID register */ + cxg_ra_reg->CXG_RA_RND_LDID_TO_RAID_REG[reg_offset] |= + ((uint64_t)raid << + (ldid_value_offset * NUM_BITS_RESERVED_FOR_RAID)); + + /* Set corresponding valid bit */ + cxg_ra_reg->CXG_RA_RND_LDID_TO_RAID_VAL |= ((uint64_t)0x1 << ldid_value); + + /* Increment the global raid_value */ + raid_value++; +} + +static void program_agentid_to_linkid_reg( + struct cmn_rhodes_device_ctx *ctx, + const struct mod_cmn_rhodes_ccix_config *config) +{ + uint32_t agentid; + uint32_t reg_index = 0; + uint8_t linkid = 0; + uint32_t agentid_bit_offset = 0; + struct cmn_rhodes_cxg_ra_reg *cxg_ra_reg; + struct cmn_rhodes_cxg_ha_reg *cxg_ha_reg; + struct cmn_rhodes_cxla_reg *cxla_reg; + cxg_ra_reg = ctx->cxg_ra_reg_table[config->ldid].cxg_ra_reg; + cxg_ha_reg = ctx->cxg_ha_reg_table[config->ldid].cxg_ha_reg; + cxla_reg = ctx->cxla_reg_table[config->ldid].cxla_reg; + + unsigned int remote_agentid_start; + unsigned int remote_agentid_end; + + for (linkid = 0; linkid < CMN_RHODES_MAX_CCIX_PROTOCOL_LINKS; linkid++) { + remote_agentid_start = + config->remote_agentid_to_linkid_map[linkid].remote_agentid_start; + remote_agentid_end = + config->remote_agentid_to_linkid_map[linkid].remote_agentid_end; + + /* + * Skip configuring link if both start and end are 0, indicating + * there's no link + */ + if ((remote_agentid_start == 0) && (remote_agentid_end == 0)) + continue; + + FWK_LOG_INFO( + MOD_NAME " Remote [AgentID %d - AgentID %d] Link %d", + remote_agentid_start, + remote_agentid_end, + linkid); + + for (agentid = remote_agentid_start; agentid <= remote_agentid_end; + agentid++) { + /* Each register is 64 bits and holds 8 AgentID/LinkID mappings */ + reg_index = agentid / 8; + agentid_bit_offset = agentid % 8; + + /* Writing AgentID-to-LinkID mappings */ + cxg_ra_reg->CXG_RA_AGENTID_TO_LINKID_REG[reg_index] |= + ((uint64_t)linkid << + (agentid_bit_offset * NUM_BITS_RESERVED_FOR_LINKID)); + + cxg_ha_reg->CXG_HA_AGENTID_TO_LINKID_REG[reg_index] |= + ((uint64_t)linkid << + (agentid_bit_offset * NUM_BITS_RESERVED_FOR_LINKID)); + + cxla_reg->CXLA_AGENTID_TO_LINKID_REG[reg_index] |= + ((uint64_t)linkid << + (agentid_bit_offset * NUM_BITS_RESERVED_FOR_LINKID)); + + /* Setting corresponding valid bits */ + cxg_ra_reg->CXG_RA_AGENTID_TO_LINKID_VAL |= + ((uint64_t)0x1 << agentid); + cxg_ha_reg->CXG_HA_AGENTID_TO_LINKID_VAL |= + ((uint64_t)0x1 << agentid); + cxla_reg->CXLA_AGENTID_TO_LINKID_VAL |= ((uint64_t)0x1 << agentid); + } + } +} + +static void program_cxg_ha_id(struct cmn_rhodes_device_ctx *ctx, uint8_t haid) +{ + struct cmn_rhodes_cxg_ha_reg *cxg_ha_reg; + + cxg_ha_reg = ctx->cxg_ha_reg_table[config->ldid].cxg_ha_reg; + + FWK_LOG_INFO( + MOD_NAME "HAID for CCIX %d with nodeid %d: HAID %d", + config->ldid, + get_node_id(cxg_ha_reg), + haid); + + cxg_ha_reg->CXG_HA_ID = haid; +} + +static void program_cxg_ha_raid_to_ldid_lut(struct cmn_rhodes_device_ctx *ctx, + uint8_t raid_id, uint8_t ldid_value) +{ + uint32_t reg_index = 0; + uint32_t raid_bit_offset = 0; + struct cmn_rhodes_cxg_ha_reg *cxg_ha_reg; + + cxg_ha_reg = ctx->cxg_ha_reg_table[config->ldid].cxg_ha_reg; + + /* Each 64-bit RAID-to-LDID register holds 8 mappings, 8 bits each. */ + reg_index = raid_id / 8; + raid_bit_offset = raid_id % 8; + + /* Write RAID-to-LDID mapping (with RNF bit set) */ + cxg_ha_reg->CXG_HA_RNF_RAID_TO_LDID_REG[reg_index] |= + ((uint64_t)(ldid_value | CXG_HA_RAID_TO_LDID_RNF_MASK) << + (raid_bit_offset * NUM_BITS_RESERVED_FOR_LDID)); + + /* Set corresponding valid bit */ + cxg_ha_reg->CXG_HA_RNF_RAID_TO_LDID_VAL |= ((uint64_t)0x1 << raid_id); +} + +static void program_hnf_ldid_to_chi_node_id_reg( + struct cmn_rhodes_device_ctx *ctx, + const struct mod_cmn_rhodes_ccix_config *config) +{ + uint32_t agentid; + uint32_t reg_index = 0; + uint32_t reg_bit_offset = 0; + uint32_t i = 0; + struct cmn_rhodes_hnf_reg *hnf_reg = NULL; + uint32_t nodeid_ra; + uint8_t linkid = 0; + + unsigned int remote_agentid_start; + unsigned int remote_agentid_end; + + /* Assign the NodeID of CXHA as the RA's NodeID */ + nodeid_ra = ctx->cxg_ha_reg_table[config->ldid].node_id; + + for (linkid = 0; linkid < CMN_RHODES_MAX_CCIX_PROTOCOL_LINKS; linkid++) { + remote_agentid_start = + config->remote_agentid_to_linkid_map[linkid].remote_agentid_start; + remote_agentid_end = + config->remote_agentid_to_linkid_map[linkid].remote_agentid_end; + + /* + * Skip configuring link if both start and end are 0, indicating + * there's no link + */ + if ((remote_agentid_start == 0) && (remote_agentid_end == 0)) + continue; + + FWK_LOG_INFO( + MOD_NAME " Remote [AgentID %d - AgentID %d] Link %d", + remote_agentid_start, + remote_agentid_end, + linkid); + + for (agentid = remote_agentid_start; agentid <= remote_agentid_end; + agentid++) { + /* Each 64-bit register holds 2 sets of config data, 32 bits each */ + reg_index = agentid / 2; + reg_bit_offset = agentid % 2; + + for (i = 0; i < ctx->hnf_count; i++) { + hnf_reg = (struct cmn_rhodes_hnf_reg *)ctx->hnf_node[i]; + /* Write CXHA NodeID, local/remote and valid bit */ + hnf_reg->RN_PHYS_ID[reg_index] |= + ((uint64_t)(nodeid_ra | + (REMOTE_CCIX_NODE << + HNF_RN_PHYS_RN_LOCAL_REMOTE_SHIFT_VAL) | + (UINT64_C(0x1) << + HNF_RN_PHYS_RN_ID_VALID_SHIFT_VAL)) << + (reg_bit_offset * NUM_BITS_RESERVED_FOR_PHYS_ID)); + } + } + } +} + +static int enable_smp_mode(struct cmn_rhodes_device_ctx *ctx, + const struct mod_cmn_rhodes_ccix_config *config) +{ + struct cmn_rhodes_cxg_ra_reg *cxg_ra_reg; + struct cmn_rhodes_cxg_ha_reg *cxg_ha_reg; + struct cmn_rhodes_cxla_reg *cxla_reg; + + cxg_ra_reg = ctx->cxg_ra_reg_table[config->ldid].cxg_ra_reg; + cxg_ha_reg = ctx->cxg_ha_reg_table[config->ldid].cxg_ha_reg; + cxla_reg = ctx->cxla_reg_table[config->ldid].cxla_reg; + + cxg_ra_reg->CXG_RA_AUX_CTRL |= (1 << CXG_RA_AUX_CTRL_SMP_MODE_EN_SHIFT_VAL); + cxg_ha_reg->CXG_HA_AUX_CTRL |= (1 << CXG_HA_AUX_CTRL_SMP_MODE_EN_SHIFT_VAL); + cxla_reg->CXLA_AUX_CTRL |= + (UINT64_C(0x1) << CXLA_AUX_CTRL_SMP_MODE_EN_SHIFT_VAL); + + FWK_LOG_INFO(MOD_NAME "SMP Mode Enabled"); + return FWK_SUCCESS; +} + +static void program_cxg_ra_sam_addr_region(struct cmn_rhodes_device_ctx *ctx, + const struct mod_cmn_rhodes_ccix_config *config) +{ + unsigned int i; + uint64_t blocks; + uint64_t size; + struct cmn_rhodes_cxg_ra_reg *cxg_ra_reg; + + cxg_ra_reg = ctx->cxg_ra_reg_table[config->ldid].cxg_ra_reg; + + FWK_LOG_INFO( + MOD_NAME "Configuring RA SAM for CXRA NodeID %d", + get_node_id(cxg_ra_reg)); + + for (i = 0; i < CMN_RHODES_MAX_RA_SAM_ADDR_REGION; i++) { + /* If the size is zero, skip that entry */ + if (config->ra_mmap_table[i].size == 0) + continue; + + /* Size must be a multiple of SAM_GRANULARITY */ + fwk_assert((config->ra_mmap_table[i].size % (64 * FWK_KIB)) == 0); + + /* Size also must be a power of two */ + fwk_assert((config->ra_mmap_table[i].size & + (config->ra_mmap_table[i].size - 1)) == 0); + + /* Region base should be naturally aligned to the region size */ + fwk_assert(config->ra_mmap_table[i].base % + config->ra_mmap_table[i].size == 0); + + FWK_LOG_INFO( + MOD_NAME " [0x%llx - 0x%llx] HAID %d", + config->ra_mmap_table[i].base, + config->ra_mmap_table[i].base + + config->ra_mmap_table[i].size - 1, + config->ra_mmap_table[i].remote_haid); + + blocks = config->ra_mmap_table[i].size / (64 * FWK_KIB); + size = fwk_math_log2(blocks); + + cxg_ra_reg->CXG_RA_SAM_ADDR_REGION_REG[i] = + size | (config->ra_mmap_table[i].base) | + ((uint64_t)config->ra_mmap_table[i].remote_haid << + SAM_ADDR_TARGET_HAID_SHIFT) | + (SAM_ADDR_REG_VALID_MASK); + + i++; + } +} + +static int enable_and_start_ccix_link_up_sequence( + struct cmn_rhodes_device_ctx *ctx, uint8_t linkid) +{ + int status; + struct cxg_wait_condition_data wait_data; + struct cmn_rhodes_cxg_ra_reg *cxg_ra_reg; + struct cmn_rhodes_cxg_ha_reg *cxg_ha_reg; + + cxg_ra_reg = ctx->cxg_ra_reg_table[config->ldid].cxg_ra_reg; + cxg_ha_reg = ctx->cxg_ha_reg_table[config->ldid].cxg_ha_reg; + + if (linkid > 2) + return FWK_E_PARAM; + + wait_data.ctx = ctx; + wait_data.linkid = linkid; + + FWK_LOG_INFO( + MOD_NAME "Enabling CCIX link %d...", linkid); + /* Set link enable bit to enable the CCIX link */ + cxg_ra_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_CTRL = + CXG_LINK_CTRL_EN_MASK; + cxg_ha_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_CTRL = + CXG_LINK_CTRL_EN_MASK; + + /* Wait until link enable bits are set */ + wait_data.cond = CXG_LINK_CTRL_EN_BIT_SET; + status = ctx->timer_api->wait(FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0), + CXG_PRTCL_LINK_CTRL_TIMEOUT, + cxg_link_wait_condition, + &wait_data); + if (status != FWK_SUCCESS) { + FWK_LOG_INFO( + MOD_NAME "Enabling CCIX link %d... Failed", linkid); + return status; + } + FWK_LOG_INFO( + MOD_NAME "Enabling CCIX link %d... Done", linkid); + + FWK_LOG_INFO( + MOD_NAME "Verifying link down status..."); + /* Wait till link up bits are cleared in control register */ + wait_data.cond = CXG_LINK_CTRL_UP_BIT_CLR; + status = ctx->timer_api->wait(FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0), + CXG_PRTCL_LINK_CTRL_TIMEOUT, + cxg_link_wait_condition, + &wait_data); + if (status != FWK_SUCCESS) { + FWK_LOG_INFO( + MOD_NAME "Verifying link down status... Failed"); + return status; + } + + /* Wait till link down bits are set in status register */ + wait_data.cond = CXG_LINK_STATUS_DWN_BIT_SET; + status = ctx->timer_api->wait(FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0), + CXG_PRTCL_LINK_CTRL_TIMEOUT, + cxg_link_wait_condition, + &wait_data); + if (status != FWK_SUCCESS) { + FWK_LOG_INFO( + MOD_NAME "Verifying link down status... Failed"); + return status; + } + + /* Wait till link ACK bits are cleared in status register */ + wait_data.cond = CXG_LINK_STATUS_ACK_BIT_CLR; + status = ctx->timer_api->wait(FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0), + CXG_PRTCL_LINK_CTRL_TIMEOUT, + cxg_link_wait_condition, + &wait_data); + if (status != FWK_SUCCESS) { + FWK_LOG_INFO( + MOD_NAME "Verifying link down status... Failed"); + return status; + } + FWK_LOG_INFO( + MOD_NAME "Verifying link down status... Done"); + + FWK_LOG_INFO(MOD_NAME "Bringing up link..."); + /* Bring up link using link request bit */ + cxg_ra_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_CTRL |= + CXG_LINK_CTRL_REQ_MASK; + cxg_ha_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_CTRL |= + CXG_LINK_CTRL_REQ_MASK; + + /* Wait till link ACK bits are set in status register */ + wait_data.cond = CXG_LINK_STATUS_ACK_BIT_SET; + status = ctx->timer_api->wait(FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0), + CXG_PRTCL_LINK_CTRL_TIMEOUT, + cxg_link_wait_condition, + &wait_data); + if (status != FWK_SUCCESS) { + FWK_LOG_INFO(MOD_NAME "Bringing up link... Failed"); + return status; + } + + /* Wait till link down bits are cleared in status register */ + wait_data.cond = CXG_LINK_STATUS_DWN_BIT_CLR; + status = ctx->timer_api->wait(FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0), + CXG_PRTCL_LINK_CTRL_TIMEOUT, + cxg_link_wait_condition, + &wait_data); + if (status != FWK_SUCCESS) { + FWK_LOG_INFO(MOD_NAME "Bringing up link... Failed"); + return status; + } + FWK_LOG_INFO(MOD_NAME "Bringing up link... Done"); + + return FWK_SUCCESS; +} + +int ccix_setup(const unsigned int chip_id, struct cmn_rhodes_device_ctx *ctx, + const struct mod_cmn_rhodes_ccix_config *ccix_config) +{ + unsigned int i; + unsigned int unique_remote_rnf_ldid_value; + uint8_t rnf_ldid; + uint8_t rni_ldid; + uint8_t rnd_ldid; + uint8_t agentid; + uint8_t remote_agentid; + uint8_t offset_id; + uint8_t local_ra_cnt; + int status; + + FWK_LOG_INFO( + MOD_NAME "Programming CCIX gateway..."); + + /* Assign the max count among the RNs as local_ra_cnt */ + if ((ctx->rnf_count > ctx->rnd_count) && (ctx->rnf_count > ctx->rni_count)) + local_ra_cnt = ctx->rnf_count; + else if (ctx->rnd_count > ctx->rni_count) + local_ra_cnt = ctx->rnd_count; + else + local_ra_cnt = ctx->rni_count; + + if (ccix_config->smp_mode == true) { + status = enable_smp_mode(ctx, ccix_config); + if (status != FWK_SUCCESS) + return status; + } + + + /* Set the global config data */ + config = ccix_config; + + /* + * In order to assign unique AgentIDs across multiple chips, chip_id is used + * as factor to offset the AgentID value + */ + raid_value = 0; + offset_id = chip_id * local_ra_cnt; + + for (rnf_ldid = 0; rnf_ldid < ctx->rnf_count; rnf_ldid++) { + agentid = raid_value + offset_id; + + /* Program RAID values in CXRA LDID to RAID LUT */ + program_cxg_ra_rnf_ldid_to_raid_reg(ctx, rnf_ldid, agentid); + } + + /* Program agentid to linkid LUT for remote agents in CXRA/CXHA/CXLA */ + program_agentid_to_linkid_reg(ctx, ccix_config); + + /* Program HN-F ldid to CHI NodeID for remote RN-F agents */ + program_hnf_ldid_to_chi_node_id_reg(ctx, ccix_config); + + /* + * unique_remote_rnf_ldid_value is used to keep track of the + * ldid of the remote RNF agents + */ + unique_remote_rnf_ldid_value = ctx->rnf_count; + + for (i = 0; i < ccix_config->remote_rnf_count; i++) { + /* + * The remote_agentid should not include the current chip's AgentIDs. + * If `block` is less than the current chip_id, then include the + * AgentIDs starting from chip 0 till (not including) current chip. If + * the `block` is equal or greater than the current chip, then include + * the AgentIDs from next chip till the max chip. + */ + if ((i / ctx->rnf_count) < chip_id) + remote_agentid = i; + else + remote_agentid = i + ctx->rnf_count; + + /* Program the CXHA raid to ldid LUT */ + program_cxg_ha_raid_to_ldid_lut(ctx, remote_agentid, + unique_remote_rnf_ldid_value); + + unique_remote_rnf_ldid_value++; + } + + /* Program the unique HAID for the CXHA block */ + program_cxg_ha_id(ctx, ccix_config->haid); + + raid_value = 0; + offset_id = chip_id * local_ra_cnt; + + for (rnd_ldid = 0; rnd_ldid < ctx->rnd_count; rnd_ldid++) { + /* Determine agentid of the remote agents */ + agentid = raid_value + offset_id; + + /* Program RAID values in CXRA LDID to RAID LUT */ + program_cxg_ra_rnd_ldid_to_raid_reg(ctx, rnd_ldid, agentid); + } + + raid_value = 0; + offset_id = chip_id * local_ra_cnt; + + for (rni_ldid = 0; rni_ldid < ctx->rni_count; rni_ldid++) { + /* Determine agentid of the remote agents */ + agentid = raid_value + offset_id; + + /* Program RAID values in CXRA LDID to RAID LUT */ + program_cxg_ra_rni_ldid_to_raid_reg(ctx, rni_ldid, agentid); + } + + /* + * Program the CXRA SAM with the address range and the corresponding remote + * HAID + */ + program_cxg_ra_sam_addr_region(ctx, ccix_config); + + /* Program the Link Control registers present in CXRA/CXHA/CXLA */ + status = enable_and_start_ccix_link_up_sequence(ctx, 0); + + return status; +} + +int ccix_exchange_protocol_credit(struct cmn_rhodes_device_ctx *ctx, + const struct mod_cmn_rhodes_ccix_config *ccix_config) +{ + int linkid; + struct cmn_rhodes_cxg_ra_reg *cxg_ra_reg; + struct cmn_rhodes_cxg_ha_reg *cxg_ha_reg; + + config = ccix_config; + cxg_ra_reg = ctx->cxg_ra_reg_table[config->ldid].cxg_ra_reg; + cxg_ha_reg = ctx->cxg_ha_reg_table[config->ldid].cxg_ha_reg; + + /* TODO Add support to enable multiple links */ + linkid = 0; + + FWK_LOG_INFO( + MOD_NAME "Exchanging protocol credits for link %d...", linkid); + /* Exchange protocol credits using link up bit */ + cxg_ra_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_CTRL |= + CXG_LINK_CTRL_UP_MASK; + cxg_ha_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_CTRL |= + CXG_LINK_CTRL_UP_MASK; + FWK_LOG_INFO( + MOD_NAME "Exchanging protocol credits for link %d... Done", linkid); + + return FWK_SUCCESS; +} + +int ccix_enter_system_coherency(struct cmn_rhodes_device_ctx *ctx, + const struct mod_cmn_rhodes_ccix_config *ccix_config) +{ + struct cxg_wait_condition_data wait_data; + int status; + int linkid; + struct cmn_rhodes_cxg_ha_reg *cxg_ha_reg; + + config = ccix_config; + cxg_ha_reg = ctx->cxg_ha_reg_table[config->ldid].cxg_ha_reg; + + /* TODO Add support to enable multiple links */ + linkid = 0; + + wait_data.ctx = ctx; + wait_data.linkid = linkid; + + FWK_LOG_INFO( + MOD_NAME "Entering system coherency for link %d...", linkid); + /* Enter system coherency by setting DVMDOMAIN request bit */ + cxg_ha_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_CTRL |= + CXG_LINK_CTRL_DVMDOMAIN_REQ_MASK; + + /* Wait till DVMDOMAIN ACK bit is set in status register */ + wait_data.cond = CXG_LINK_STATUS_HA_DVMDOMAIN_ACK_BIT_SET; + status = ctx->timer_api->wait(FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0), + CXG_PRTCL_LINK_DVMDOMAIN_TIMEOUT, + cxg_link_wait_condition, + &wait_data); + if (status != FWK_SUCCESS) { + FWK_LOG_INFO( + MOD_NAME "Entering system coherency for link %d... Failed", linkid); + return status; + } + FWK_LOG_INFO( + MOD_NAME "Entering system coherency for link %d... Done", linkid); + + return FWK_SUCCESS; +} + +int ccix_enter_dvm_domain(struct cmn_rhodes_device_ctx *ctx, + const struct mod_cmn_rhodes_ccix_config *ccix_config) +{ + struct cxg_wait_condition_data wait_data; + int status; + int linkid; + struct cmn_rhodes_cxg_ra_reg *cxg_ra_reg; + + config = ccix_config; + cxg_ra_reg = ctx->cxg_ra_reg_table[config->ldid].cxg_ra_reg; + + /* TODO Add support to enable multiple links */ + linkid = 0; + + wait_data.ctx = ctx; + wait_data.linkid = linkid; + + FWK_LOG_INFO( + MOD_NAME "Entering DVM domain for link %d...", linkid); + /* Enter system coherency by setting DVMDOMAIN request bit */ + cxg_ra_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_CTRL |= + CXG_LINK_CTRL_DVMDOMAIN_REQ_MASK; + + /* Wait till DVMDOMAIN ACK bit is set in status register */ + wait_data.cond = CXG_LINK_STATUS_RA_DVMDOMAIN_ACK_BIT_SET; + status = ctx->timer_api->wait(FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0), + CXG_PRTCL_LINK_DVMDOMAIN_TIMEOUT, + cxg_link_wait_condition, + &wait_data); + if (status != FWK_SUCCESS) { + FWK_LOG_INFO( + MOD_NAME "Entering DVM domain for link %d... Failed", linkid); + return status; + } + FWK_LOG_INFO( + MOD_NAME "Entering DVM domain for link %d... Done", linkid); + + return FWK_SUCCESS; +} diff --git a/module/cmn_rhodes/src/cmn_rhodes_ccix.h b/module/cmn_rhodes/src/cmn_rhodes_ccix.h new file mode 100644 index 0000000000000000000000000000000000000000..64da60ee926d21127f793a2b530d67dd8772e079 --- /dev/null +++ b/module/cmn_rhodes/src/cmn_rhodes_ccix.h @@ -0,0 +1,90 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Description: + * CMN-Rhodes CCIX Configuration Interface + */ + +#ifndef CMN_RHODES_CCIX_H +#define CMN_RHODES_CCIX_H + +#include +#include + +int ccix_setup(const unsigned int chip_id, struct cmn_rhodes_device_ctx *ctx, + const struct mod_cmn_rhodes_ccix_config *ccix_config); + +int ccix_exchange_protocol_credit(struct cmn_rhodes_device_ctx *ctx, + const struct mod_cmn_rhodes_ccix_config *ccix_config); + +int ccix_enter_system_coherency(struct cmn_rhodes_device_ctx *ctx, + const struct mod_cmn_rhodes_ccix_config *ccix_config); + +int ccix_enter_dvm_domain(struct cmn_rhodes_device_ctx *ctx, + const struct mod_cmn_rhodes_ccix_config *ccix_config); + +/* + * CCIX Link UP stages + */ +enum cxg_link_up_wait_cond { + CXG_LINK_CTRL_EN_BIT_SET, + CXG_LINK_CTRL_UP_BIT_CLR, + CXG_LINK_STATUS_DWN_BIT_SET, + CXG_LINK_STATUS_DWN_BIT_CLR, + CXG_LINK_STATUS_ACK_BIT_SET, + CXG_LINK_STATUS_ACK_BIT_CLR, + CXG_LINK_STATUS_HA_DVMDOMAIN_ACK_BIT_SET, + CXG_LINK_STATUS_RA_DVMDOMAIN_ACK_BIT_SET, + CXG_LINK_UP_SEQ_COUNT, +}; + +/* + * Structure defining data to be passed to timer API + */ +struct cxg_wait_condition_data { + struct cmn_rhodes_device_ctx *ctx; + uint8_t linkid; + enum cxg_link_up_wait_cond cond; +}; + +/* CCIX Gateway (CXG) Home Agent (HA) defines */ +#define CXG_HA_RAID_TO_LDID_RNF_MASK (0x80) + +#define CXLA_CCIX_PROP_MAX_PACK_SIZE_MASK UINT64_C(0x0000000000000380) +#define CXLA_CCIX_PROP_MAX_PACK_SIZE_SHIFT_VAL 7 +#define CXLA_CCIX_PROP_MAX_PACK_SIZE_128 0 +#define CXLA_CCIX_PROP_MAX_PACK_SIZE_256 1 +#define CXLA_CCIX_PROP_MAX_PACK_SIZE_512 2 + +/* CCIX Gateway (CXG) link control & status defines */ + +#define CXG_LINK_CTRL_EN_MASK UINT64_C(0x0000000000000001) +#define CXG_LINK_CTRL_REQ_MASK UINT64_C(0x0000000000000002) +#define CXG_LINK_CTRL_UP_MASK UINT64_C(0x0000000000000004) +#define CXG_LINK_CTRL_DVMDOMAIN_REQ_MASK UINT64_C(0x0000000000000008) +#define CXG_LINK_STATUS_ACK_MASK UINT64_C(0x0000000000000001) +#define CXG_LINK_STATUS_DOWN_MASK UINT64_C(0x0000000000000002) +#define CXG_LINK_STATUS_DVMDOMAIN_ACK_MASK UINT64_C(0x0000000000000004) +#define CXG_PRTCL_LINK_CTRL_TIMEOUT UINT32_C(100) +#define CXG_PRTCL_LINK_DVMDOMAIN_TIMEOUT UINT32_C(100) + +/* SMP Mode related defines */ +#define CXG_RA_AUX_CTRL_SMP_MODE_EN_SHIFT_VAL 16 +#define CXG_HA_AUX_CTRL_SMP_MODE_EN_SHIFT_VAL 16 +#define CXLA_AUX_CTRL_SMP_MODE_EN_SHIFT_VAL 47 + +#define HNF_RN_PHYS_RN_ID_VALID_SHIFT_VAL 31 +#define HNF_RN_PHYS_RN_LOCAL_REMOTE_SHIFT_VAL 16 +#define NUM_BITS_RESERVED_FOR_RAID 8 +#define NUM_BITS_RESERVED_FOR_LINKID 8 +#define NUM_BITS_RESERVED_FOR_LDID 8 +#define NUM_BITS_RESERVED_FOR_PHYS_ID 32 +#define LOCAL_CCIX_NODE 0 +#define REMOTE_CCIX_NODE 1 +#define SAM_ADDR_TARGET_HAID_SHIFT (52) +#define SAM_ADDR_REG_VALID_MASK UINT64_C(0x8000000000000000) + +#endif /* CMN_RHODES_CCIX_H */ diff --git a/module/cmn_rhodes/src/mod_cmn_rhodes.c b/module/cmn_rhodes/src/mod_cmn_rhodes.c index f022fdd1a04ee0a3e58e3d4e39c94f479be3a2b5..1d3afc98363dc62cd203770b8c63642e9d4e3e6a 100644 --- a/module/cmn_rhodes/src/mod_cmn_rhodes.c +++ b/module/cmn_rhodes/src/mod_cmn_rhodes.c @@ -6,12 +6,15 @@ */ #include +#include #include #include #include #include +#include +#include #include #include @@ -27,7 +30,15 @@ #define MOD_NAME "[CMN_RHODES] " -static struct cmn_rhodes_ctx *ctx; +static struct cmn_rhodes_device_ctx *ctx; + +/* Chip Information */ +static struct mod_system_info_get_info_api *system_info_api; +static const struct mod_system_info *system_info; + +/* Initialize default for multi-chip mode and chip-id */ +static unsigned int chip_id; +static bool multi_chip_mode; static void process_node_hnf(struct cmn_rhodes_hnf_reg *hnf) { @@ -38,6 +49,7 @@ static void process_node_hnf(struct cmn_rhodes_hnf_reg *hnf) unsigned int region_idx; unsigned int region_sub_count = 0; static unsigned int cal_mode_factor = 1; + uint64_t base; const struct mod_cmn_rhodes_mem_region_map *region; const struct mod_cmn_rhodes_config *config = ctx->config; @@ -46,18 +58,11 @@ static void process_node_hnf(struct cmn_rhodes_hnf_reg *hnf) /* * If CAL mode is set, only even numbered hnf node should be added to the - * sys_cache_grp_hn_nodeid registers and hnf_count should be incremented - * only for the even numbered hnf nodes. + * sys_cache_grp_hn_nodeid registers. */ if (config->hnf_cal_mode == true && (node_id % 2 == 1)) { /* Factor to manipulate the group and bit_pos */ cal_mode_factor = 2; - - /* - * Reduce the hnf_count as the current hnf node is not getting included - * in the sys_cache_grp_hn_nodeid register - */ - ctx->hnf_count--; } assert(logical_id < config->snf_count); @@ -74,11 +79,17 @@ static void process_node_hnf(struct cmn_rhodes_hnf_reg *hnf) * sys_cache_grp_hn_nodeid registers */ if (config->hnf_cal_mode == true) { - if (node_id % 2 == 0) + if (node_id % 2 == 0) { ctx->hnf_cache_group[group] += ((uint64_t)get_node_id(hnf)) << bit_pos; - } else + ctx->sn_nodeid_group[group] += + ((uint64_t)config->snf_table[logical_id]) << bit_pos; + } + } else { ctx->hnf_cache_group[group] += ((uint64_t)get_node_id(hnf)) << bit_pos; + ctx->sn_nodeid_group[group] += + ((uint64_t)config->snf_table[logical_id]) << bit_pos; + } /* Set target node */ hnf->SAM_CONTROL = config->snf_table[logical_id]; @@ -93,11 +104,15 @@ static void process_node_hnf(struct cmn_rhodes_hnf_reg *hnf) if (region->type != MOD_CMN_RHODES_REGION_TYPE_SYSCACHE_SUB) continue; + /* Offset the base with chip address space base on chip-id */ + base = ((uint64_t) (ctx->config->chip_addr_space * chip_id)) + + region->base; + /* Configure sub-region entry */ hnf->SAM_MEMREGION[region_sub_count] = region->node_id | (sam_encode_region_size(region->size) << CMN_RHODES_HNF_SAM_MEMREGION_SIZE_POS) | - ((region->base / SAM_GRANULARITY) << + ((base / SAM_GRANULARITY) << CMN_RHODES_HNF_SAM_MEMREGION_BASE_POS) | CMN_RHODES_HNF_SAM_MEMREGION_VALID; @@ -122,11 +137,18 @@ static int cmn_rhodes_discovery(void) unsigned int xp_idx; unsigned int node_count; unsigned int node_idx; + unsigned int cxg_ra_reg_count; + unsigned int cxg_ha_reg_count; + unsigned int cxla_reg_count; bool xp_port; struct cmn_rhodes_mxp_reg *xp; struct node_header *node; const struct mod_cmn_rhodes_config *config = ctx->config; + cxg_ra_reg_count = 0; + cxg_ha_reg_count = 0; + cxla_reg_count = 0; + FWK_LOG_INFO(MOD_NAME "Starting discovery..."); assert(get_node_type(ctx->root) == NODE_TYPE_CFG); @@ -159,6 +181,7 @@ static int cmn_rhodes_discovery(void) if ((get_device_type(xp, xp_port) == DEVICE_TYPE_CXRH) || (get_device_type(xp, xp_port) == DEVICE_TYPE_CXHA) || (get_device_type(xp, xp_port) == DEVICE_TYPE_CXRA)) { + cxla_reg_count++; FWK_LOG_INFO( MOD_NAME " Found CXLA at node ID: %d", get_child_node_id(xp, node_idx)); @@ -185,6 +208,44 @@ static int cmn_rhodes_discovery(void) ctx->internal_rnsam_count++; break; + case NODE_TYPE_RN_D: + if ((ctx->rnd_count) >= MAX_RND_COUNT) { + FWK_LOG_ERR( + MOD_NAME " rnd count %d >= max limit (%d)\n", + ctx->rnd_count, + MAX_RND_COUNT); + return FWK_E_DATA; + } + ctx->rnd_count++; + break; + + case NODE_TYPE_RN_I: + if ((ctx->rni_count++) >= MAX_RNI_COUNT) { + FWK_LOG_ERR( + MOD_NAME " rni count %d >= max limit (%d)\n", + ctx->rni_count, + MAX_RNI_COUNT); + return FWK_E_DATA; + } + ctx->rni_count++; + break; + + case NODE_TYPE_CXRA: + cxg_ra_reg_count++; + break; + + case NODE_TYPE_CXHA: + cxg_ha_reg_count++; + break; + + /* CXLA should not be an internal node */ + case NODE_TYPE_CXLA: + FWK_LOG_ERR(MOD_NAME + "CXLA node should not be internal node, " + "discovery failed"); + return FWK_E_DEVICE; + break; + default: /* Nothing to be done for other node types */ break; @@ -207,13 +268,57 @@ static int cmn_rhodes_discovery(void) return FWK_E_DATA; } - FWK_LOG_INFO( - MOD_NAME "Total internal RN-SAM nodes: %d" MOD_NAME - "Total external RN-SAM nodes: %d" MOD_NAME - "Total HN-F nodes: %d", - ctx->internal_rnsam_count, - ctx->external_rnsam_count, - ctx->hnf_count); + /* Total number of CXG_RA, CXG_HA and CXLA nodes should be equal */ + if ((cxg_ra_reg_count != cxg_ha_reg_count) || + (cxg_ha_reg_count != cxla_reg_count)) { + FWK_LOG_ERR(MOD_NAME + "Inconsistent count of CXG components detected, discovery failed.\n" + " CXG_RA count: %d\n" + " CXG_HA count: %d\n" + " CXLA count: %d\n", + cxg_ra_reg_count, + cxg_ha_reg_count, + cxla_reg_count); + return FWK_E_DEVICE; + } + + ctx->ccix_node_count = cxg_ra_reg_count; + + /* + * TODO Below need fixing + * RN-F nodes does not have node type identifier and hence the count cannot + * be determined during the discovery process. RN-F count will be total + * RN-SAM count minus the total RN-D, RN-I and CXHA count combined. + */ + ctx->rnf_count = ctx->internal_rnsam_count + ctx->external_rnsam_count - + (ctx->rnd_count + ctx->rni_count + cxg_ha_reg_count); + + if (ctx->rnf_count > MAX_RNF_COUNT) { + FWK_LOG_ERR( + MOD_NAME "rnf count %d > max limit (%d)\n", + ctx->rnf_count, + MAX_RNF_COUNT); + return FWK_E_RANGE; + } + + FWK_LOG_INFO(MOD_NAME + "Total internal RN-SAM nodes: %d", ctx->internal_rnsam_count); + FWK_LOG_INFO(MOD_NAME + "Total external RN-SAM nodes: %d", ctx->external_rnsam_count); + FWK_LOG_INFO(MOD_NAME + "Total HN-F nodes: %d", ctx->hnf_count); + FWK_LOG_INFO(MOD_NAME + "Total RN-D nodes: %d\n", ctx->rnd_count); + FWK_LOG_INFO(MOD_NAME + "Total RN-F nodes: %d\n", ctx->rnf_count); + FWK_LOG_INFO(MOD_NAME + "Total RN-I nodes: %d\n", ctx->rni_count); + FWK_LOG_INFO(MOD_NAME + "Total CCIX Request Agent nodes: %d", cxg_ra_reg_count); + FWK_LOG_INFO(MOD_NAME + "Total CCIX Home Agent nodes: %d", cxg_ha_reg_count); + FWK_LOG_INFO(MOD_NAME + "Total CCIX Link Agent nodes: %d", cxla_reg_count); return FWK_SUCCESS; } @@ -226,6 +331,9 @@ static void cmn_rhodes_configure(void) unsigned int xp_idx; unsigned int xrnsam_entry; unsigned int irnsam_entry; + unsigned int hnf_entry; + unsigned int ldid; + unsigned int node_id; bool xp_port; void *node; struct cmn_rhodes_mxp_reg *xp; @@ -235,6 +343,7 @@ static void cmn_rhodes_configure(void) xrnsam_entry = 0; irnsam_entry = 0; + hnf_entry = 0; /* Traverse cross points (XP) */ xp_count = get_node_child_count(ctx->root); @@ -247,23 +356,30 @@ static void cmn_rhodes_configure(void) for (node_idx = 0; node_idx < node_count; node_idx++) { node = get_child_node(config->base, xp, node_idx); if (is_child_external(xp, node_idx)) { - unsigned int node_id = get_child_node_id(xp, node_idx); + node_id = get_child_node_id(xp, node_idx); xp_port = get_port_number(get_child_node_id(xp, node_idx)); - /* Skip if the device type is CXG */ if ((get_device_type(xp, xp_port) == DEVICE_TYPE_CXRH) || (get_device_type(xp, xp_port) == DEVICE_TYPE_CXHA) || - (get_device_type(xp, xp_port) == DEVICE_TYPE_CXRA)) - continue; + (get_device_type(xp, xp_port) == DEVICE_TYPE_CXRA)) { + ldid = get_node_logical_id(node); + fwk_assert(ldid < ctx->ccix_node_count); - fwk_assert(xrnsam_entry < ctx->external_rnsam_count); + ctx->cxla_reg_table[ldid].node_id = + node_id; + ctx->cxla_reg_table[ldid].cxla_reg = + (struct cmn_rhodes_cxla_reg *)node; + } else { + fwk_assert(xrnsam_entry < ctx->external_rnsam_count); - ctx->external_rnsam_table[xrnsam_entry].node_id = node_id; - ctx->external_rnsam_table[xrnsam_entry].node = node; + ctx->external_rnsam_table[xrnsam_entry].node_id = node_id; + ctx->external_rnsam_table[xrnsam_entry].node = node; - xrnsam_entry++; + xrnsam_entry++; + } } else { enum node_type node_type = get_node_type(node); + node_id = get_node_id(node); if (node_type == NODE_TYPE_RN_SAM) { fwk_assert(irnsam_entry < ctx->internal_rnsam_count); @@ -271,8 +387,28 @@ static void cmn_rhodes_configure(void) ctx->internal_rnsam_table[irnsam_entry] = node; irnsam_entry++; - } else if (node_type == NODE_TYPE_HN_F) + } else if (node_type == NODE_TYPE_CXRA) { + ldid = get_node_logical_id(node); + fwk_assert(ldid < ctx->ccix_node_count); + + /* Use ldid as index of the cxg_ra table */ + ctx->cxg_ra_reg_table[ldid].node_id = node_id; + ctx->cxg_ra_reg_table[ldid].cxg_ra_reg = + (struct cmn_rhodes_cxg_ra_reg *)node; + } else if (node_type == NODE_TYPE_CXHA) { + ldid = get_node_logical_id(node); + fwk_assert(ldid < ctx->ccix_node_count); + + /* Use ldid as index of the cxg_ra table */ + ctx->cxg_ha_reg_table[ldid].node_id = node_id; + ctx->cxg_ha_reg_table[ldid].cxg_ha_reg = + (struct cmn_rhodes_cxg_ha_reg *)node; + } else if (node_type == NODE_TYPE_HN_F) { + fwk_assert(hnf_entry < ctx->hnf_count); + ctx->hnf_node[hnf_entry++] = (uintptr_t)(void *)node; + process_node_hnf(node); + } } } } @@ -282,6 +418,7 @@ static const char * const mmap_type_name[] = { [MOD_CMN_RHODES_MEM_REGION_TYPE_IO] = "I/O", [MOD_CMN_RHODES_MEM_REGION_TYPE_SYSCACHE] = "System Cache", [MOD_CMN_RHODES_REGION_TYPE_SYSCACHE_SUB] = "Sub-System Cache", + [MOD_CMN_RHODES_REGION_TYPE_CCIX] = "CCIX", }; static int cmn_rhodes_setup_sam(struct cmn_rhodes_rnsam_reg *rnsam) @@ -289,10 +426,15 @@ static int cmn_rhodes_setup_sam(struct cmn_rhodes_rnsam_reg *rnsam) unsigned int bit_pos; unsigned int group; unsigned int group_count; + unsigned int hnf_count; unsigned int region_idx; + unsigned int idx; unsigned int region_io_count = 0; unsigned int region_sys_count = 0; + unsigned int cxra_ldid; + unsigned int cxra_node_id; unsigned int scg_regions_enabled[MAX_SCG_COUNT] = {0, 0, 0, 0}; + uint64_t base; const struct mod_cmn_rhodes_mem_region_map *region; const struct mod_cmn_rhodes_config *config = ctx->config; @@ -301,19 +443,24 @@ static int cmn_rhodes_setup_sam(struct cmn_rhodes_rnsam_reg *rnsam) for (region_idx = 0; region_idx < config->mmap_count; region_idx++) { region = &config->mmap_table[region_idx]; - FWK_LOG_INFO( - MOD_NAME " [0x%" PRIx64 " - 0x%" PRIx64 "] %s", - region->base, - region->base + region->size - 1, - mmap_type_name[region->type]); + /* Offset the base with chip address space base on chip-id */ + base = ((uint64_t)(ctx->config->chip_addr_space * chip_id) + + region->base); switch (region->type) { case MOD_CMN_RHODES_MEM_REGION_TYPE_IO: /* * Configure memory region */ + FWK_LOG_INFO( + MOD_NAME " [0x%x%x - 0x%x%x] %s", + HIGH_WORD(base), LOW_WORD(base), + HIGH_WORD(base + region->size - 1), + LOW_WORD(base + region->size - 1), + mmap_type_name[region->type]); + configure_region(&rnsam->NON_HASH_MEM_REGION[region_io_count], - region->base, + base, region->size, SAM_NODE_TYPE_HN_I); @@ -339,6 +486,13 @@ static int cmn_rhodes_setup_sam(struct cmn_rhodes_rnsam_reg *rnsam) /* * Configure memory region */ + FWK_LOG_INFO( + MOD_NAME " [0x%x%x - 0x%x%x] %s", + HIGH_WORD(region->base), LOW_WORD(region->base), + HIGH_WORD(region->base + region->size - 1), + LOW_WORD(region->base + region->size - 1), + mmap_type_name[region->type]); + configure_region(&rnsam->SYS_CACHE_GRP_REGION[region_sys_count], region->base, region->size, @@ -352,7 +506,14 @@ static int cmn_rhodes_setup_sam(struct cmn_rhodes_rnsam_reg *rnsam) break; case MOD_CMN_RHODES_REGION_TYPE_SYSCACHE_SUB: - /* Do nothing. System cache sub-regions are handled by HN-Fs */ + FWK_LOG_INFO( + MOD_NAME " [0x%x%x - 0x%x%x] %s", + HIGH_WORD(region->base), LOW_WORD(region->base), + HIGH_WORD(region->base + region->size - 1), + LOW_WORD(region->base + region->size - 1), + mmap_type_name[region->type]); + + /* System cache sub-regions are handled by HN-Fs */ break; default: @@ -361,12 +522,69 @@ static int cmn_rhodes_setup_sam(struct cmn_rhodes_rnsam_reg *rnsam) } } - group_count = ctx->hnf_count / CMN_RHODES_HNF_CACHE_GROUP_ENTRIES_PER_GROUP; + /* Do configuration for CCIX Gateway Home Nodes */ + for (idx = 0; idx < config->ccix_table_count; idx++) { + region = &config->ccix_config_table[idx].remote_mmap_table; + + FWK_LOG_INFO( + MOD_NAME " [0x%x%x - 0x%x%x] %s", + HIGH_WORD(region->base), LOW_WORD(region->base), + HIGH_WORD(region->base + region->size - 1), + LOW_WORD(region->base + region->size - 1), + mmap_type_name[region->type]); + + switch (region->type) { + case MOD_CMN_RHODES_REGION_TYPE_CCIX: + /* + * Configure memory region + */ + configure_region(&rnsam->NON_HASH_MEM_REGION[region_io_count], + region->base, + region->size, + SAM_NODE_TYPE_CXRA); + + /* + * Configure target node + */ + cxra_ldid = config->ccix_config_table[idx].ldid; + cxra_node_id = ctx->cxg_ra_reg_table[cxra_ldid].node_id; + group = region_io_count / + CMN_RHODES_RNSAM_NON_HASH_TGT_NODEID_ENTRIES_PER_GROUP; + bit_pos = CMN_RHODES_RNSAM_NON_HASH_TGT_NODEID_ENTRY_BITS_WIDTH * + (region_io_count % + CMN_RHODES_RNSAM_NON_HASH_TGT_NODEID_ENTRIES_PER_GROUP); + + rnsam->NON_HASH_TGT_NODEID[group] &= + ~(CMN_RHODES_RNSAM_NON_HASH_TGT_NODEID_ENTRY_MASK << bit_pos); + rnsam->NON_HASH_TGT_NODEID[group] |= + (cxra_node_id & + CMN_RHODES_RNSAM_NON_HASH_TGT_NODEID_ENTRY_MASK) << bit_pos; + + region_io_count++; + break; + + default: + assert(false); + return FWK_E_DATA; + } + } + + /* + * If CAL mode is enabled, then only the even numbered HN-F nodes are + * programmed to the SYS_CACHE registers. Hence reduce the HN-F count by + * half if CAL mode is enabled. + */ + if (config->hnf_cal_mode) + hnf_count = ctx->hnf_count/2; + else + hnf_count = ctx->hnf_count; + + group_count = hnf_count / CMN_RHODES_HNF_CACHE_GROUP_ENTRIES_PER_GROUP; for (group = 0; group < group_count; group++) rnsam->SYS_CACHE_GRP_HN_NODEID[group] = ctx->hnf_cache_group[group]; /* Program the number of HNFs */ - rnsam->SYS_CACHE_GRP_HN_COUNT = ctx->hnf_count; + rnsam->SYS_CACHE_GRP_HN_COUNT = hnf_count; /* * If CAL mode is enabled by the configuration program the SCG CAL Mode @@ -374,7 +592,7 @@ static int cmn_rhodes_setup_sam(struct cmn_rhodes_rnsam_reg *rnsam) */ if (config->hnf_cal_mode) for (region_idx = 0; region_idx < MAX_SCG_COUNT; region_idx++) - rnsam->SYS_CACHE_GRP_CAL_MODE = scg_regions_enabled[region_idx] * + rnsam->SYS_CACHE_GRP_CAL_MODE |= scg_regions_enabled[region_idx] * (CMN_RHODES_RNSAM_SCG_HNF_CAL_MODE_EN << (region_idx * CMN_RHODES_RNSAM_SCG_HNF_CAL_MODE_SHIFT)); @@ -430,6 +648,10 @@ static int cmn_rhodes_setup(void) * Allocate enough group descriptors to accommodate all expected * HN-F nodes in the system. */ + ctx->hnf_node = fwk_mm_calloc(ctx->hnf_count, + sizeof(*ctx->hnf_node)); + if (ctx->hnf_node == NULL) + return FWK_E_NOMEM; ctx->hnf_cache_group = fwk_mm_calloc( ctx->hnf_count / CMN_RHODES_HNF_CACHE_GROUP_ENTRIES_PER_GROUP, sizeof(*ctx->hnf_cache_group)); @@ -438,6 +660,24 @@ static int cmn_rhodes_setup(void) CMN_RHODES_RNSAM_SYS_CACHE_GRP_SN_NODEID_ENTRIES_PER_GROUP, sizeof(*ctx->sn_nodeid_group)); } + + /* Allocate resource for the CCIX Gateway nodes */ + if (ctx->ccix_node_count != 0) { + ctx->cxg_ra_reg_table = fwk_mm_calloc(ctx->ccix_node_count, + sizeof(*ctx->cxg_ra_reg_table)); + if (ctx->cxg_ra_reg_table == NULL) + return FWK_E_NOMEM; + + ctx->cxg_ha_reg_table = fwk_mm_calloc(ctx->ccix_node_count, + sizeof(*ctx->cxg_ha_reg_table)); + if (ctx->cxg_ha_reg_table == NULL) + return FWK_E_NOMEM; + + ctx->cxla_reg_table = fwk_mm_calloc(ctx->ccix_node_count, + sizeof(*ctx->cxla_reg_table)); + if (ctx->cxla_reg_table == NULL) + return FWK_E_NOMEM; + } } cmn_rhodes_configure(); @@ -453,6 +693,27 @@ static int cmn_rhodes_setup(void) return FWK_SUCCESS; } +static int cmn_rhodes_ccix_setup(void) +{ + unsigned int idx; + const struct mod_cmn_rhodes_config *config = ctx->config; + + /* Do configuration for CCIX Gateway Nodes and enable the links */ + for (idx = 0; idx < config->ccix_table_count; idx++) + ccix_setup(chip_id, ctx, &config->ccix_config_table[idx]); + + /* + * Exchange protocol credits and enter system coherecy and dvm domain for + * multichip SMP mode operation. + */ + for (idx = 0; idx < config->ccix_table_count; idx++) { + ccix_exchange_protocol_credit(ctx, &config->ccix_config_table[idx]); + ccix_enter_system_coherency(ctx, &config->ccix_config_table[idx]); + ccix_enter_dvm_domain(ctx, &config->ccix_config_table[idx]); + } + return FWK_SUCCESS; +} + static int cmn_rhodes_setup_rnsam(unsigned int node_id) { unsigned int node_idx; @@ -486,36 +747,78 @@ cmn_rhodes_observer_api = { * Framework handlers */ -static int cmn_rhodes_init(fwk_id_t module_id, unsigned int element_count, +static int cmn_rhodes_init(fwk_id_t module_id, unsigned int device_count, const void *data) { - const struct mod_cmn_rhodes_config *config = data; - - /* No elements support */ - if (element_count > 0) + /* Atleast one device should be passed as element */ + if (device_count == 0) return FWK_E_DATA; - /* Allocate space for the context */ - ctx = fwk_mm_calloc(1, sizeof(*ctx)); + /* Allocate space for the device context table */ + ctx = fwk_mm_calloc(device_count, sizeof(struct cmn_rhodes_device_ctx)); + + return FWK_SUCCESS; +} + +static int cmn_rhodes_device_init(fwk_id_t element_id, + unsigned int element_count, + const void *data) +{ + struct cmn_rhodes_device_ctx *device_ctx; - if (config->base == 0) + assert(data != NULL); + + device_ctx = ctx + fwk_id_get_element_idx(element_id); + device_ctx->config = data; + + if (device_ctx->config->base == 0) return FWK_E_DATA; - if ((config->mesh_size_x == 0) || - (config->mesh_size_x > CMN_RHODES_MESH_X_MAX)) + if ((device_ctx->config->mesh_size_x == 0) || + (device_ctx->config->mesh_size_x > CMN_RHODES_MESH_X_MAX)) return FWK_E_DATA; - if ((config->mesh_size_y == 0) || - (config->mesh_size_y > CMN_RHODES_MESH_Y_MAX)) + if ((device_ctx->config->mesh_size_y == 0) || + (device_ctx->config->mesh_size_y > CMN_RHODES_MESH_Y_MAX)) return FWK_E_DATA; - if (config->snf_count > CMN_RHODES_HNF_CACHE_GROUP_ENTRIES_MAX) + if (device_ctx->config->snf_count > CMN_RHODES_HNF_CACHE_GROUP_ENTRIES_MAX) return FWK_E_DATA; - ctx->root = get_root_node(config->base, config->hnd_node_id, - config->mesh_size_x, config->mesh_size_y); + device_ctx->root = get_root_node(device_ctx->config->base, + device_ctx->config->hnd_node_id, + device_ctx->config->mesh_size_x, + device_ctx->config->mesh_size_y); + + return FWK_SUCCESS; +} + +static int cmn_rhodes_bind(fwk_id_t id, unsigned int round) +{ + int status; + struct cmn_rhodes_device_ctx *device_ctx; + + if (fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) { + /* Bind to system info module to obtain multi-chip info */ + status = fwk_module_bind(FWK_ID_MODULE(FWK_MODULE_IDX_SYSTEM_INFO), + FWK_ID_API(FWK_MODULE_IDX_SYSTEM_INFO, + MOD_SYSTEM_INFO_GET_API_IDX), + &system_info_api); + return status; + } - ctx->config = config; + /* Use second round only (round numbering is zero-indexed) */ + if (round == 1) { + device_ctx = ctx + fwk_id_get_element_idx(id); + + /* Bind to the timer component */ + status = fwk_module_bind(FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0), + FWK_ID_API(FWK_MODULE_IDX_TIMER, + MOD_TIMER_API_IDX_TIMER), + &device_ctx->timer_api); + if (status != FWK_SUCCESS) + return FWK_E_PANIC; + } return FWK_SUCCESS; } @@ -529,8 +832,31 @@ static int cmn_rhodes_process_bind_request(fwk_id_t requester_id, int cmn_rhodes_start(fwk_id_t id) { + int status; + + /* No need to do anything for element */ + if (!fwk_module_is_valid_element_id(id)) + return FWK_SUCCESS; + + status = system_info_api->get_system_info(&system_info); + if (status == FWK_SUCCESS) { + chip_id = system_info->chip_id; + multi_chip_mode = system_info->multi_chip_mode; + } + + /* No need to anything for other elements */ + if (fwk_id_get_element_idx(id) != chip_id) + return FWK_SUCCESS; + + /* Pickup the context based on the chip_id */ + ctx = ctx + fwk_id_get_element_idx(id); + + FWK_LOG_INFO(MOD_NAME "Multichip mode: %d Chip ID: %d\n", + multi_chip_mode, chip_id); + if (fwk_id_is_equal(ctx->config->clock_id, FWK_ID_NONE)) { cmn_rhodes_setup(); + cmn_rhodes_ccix_setup(); return FWK_SUCCESS; } @@ -545,12 +871,15 @@ static int cmn_rhodes_process_notification( { struct clock_notification_params *params; - assert(fwk_id_is_equal(event->id, mod_clock_notification_id_state_changed)); - assert(fwk_id_is_type(event->target_id, FWK_ID_TYPE_MODULE)); + fwk_assert(fwk_id_is_equal(event->id, + mod_clock_notification_id_state_changed)); + fwk_assert(fwk_id_is_type(event->target_id, FWK_ID_TYPE_ELEMENT)); params = (struct clock_notification_params *)event->params; - if (params->new_state == MOD_CLOCK_STATE_RUNNING) + if (params->new_state == MOD_CLOCK_STATE_RUNNING) { cmn_rhodes_setup(); + cmn_rhodes_ccix_setup(); + } return FWK_SUCCESS; } @@ -560,6 +889,8 @@ const struct fwk_module module_cmn_rhodes = { .type = FWK_MODULE_TYPE_DRIVER, .api_count = MOD_CMN_RHODES_API_COUNT, .init = cmn_rhodes_init, + .element_init = cmn_rhodes_device_init, + .bind = cmn_rhodes_bind, .start = cmn_rhodes_start, .process_bind_request = cmn_rhodes_process_bind_request, .process_notification = cmn_rhodes_process_notification, diff --git a/product/rddaniel/scp_ramfw/config_cmn_rhodes.c b/product/rddaniel/scp_ramfw/config_cmn_rhodes.c index 55683ddaa41793ef263b397fdf510082b35b4dd4..5cc38d18bfa2a8649f3ec51d65f41cea4c5d3f8c 100644 --- a/product/rddaniel/scp_ramfw/config_cmn_rhodes.c +++ b/product/rddaniel/scp_ramfw/config_cmn_rhodes.c @@ -110,19 +110,33 @@ static const struct mod_cmn_rhodes_mem_region_map mmap[] = { }, }; +static const struct fwk_element cmn_rhodes_device_table[] = { + [0] = { + .name = "Chip-0 CMN-Rhodes Mesh Config", + .data = &((struct mod_cmn_rhodes_config) { + .base = SCP_CMN_RHODES_BASE, + .mesh_size_x = 3, + .mesh_size_y = 5, + .hnd_node_id = NODE_ID_HND, + .snf_table = snf_table, + .snf_count = FWK_ARRAY_SIZE(snf_table), + .mmap_table = mmap, + .mmap_count = FWK_ARRAY_SIZE(mmap), + .chip_addr_space = UINT64_C(4) * FWK_TIB, + .clock_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_CLOCK, + CLOCK_IDX_INTERCONNECT), + .hnf_cal_mode = true, + }) + }, + [1] = { 0 } +}; + +static const struct fwk_element *cmn_rhodes_get_device_table(fwk_id_t module_id) +{ + return cmn_rhodes_device_table; +} + const struct fwk_module_config config_cmn_rhodes = { - .get_element_table = NULL, - .data = &((struct mod_cmn_rhodes_config) { - .base = SCP_CMN_RHODES_BASE, - .mesh_size_x = 3, - .mesh_size_y = 5, - .hnd_node_id = NODE_ID_HND, - .snf_table = snf_table, - .snf_count = FWK_ARRAY_SIZE(snf_table), - .mmap_table = mmap, - .mmap_count = FWK_ARRAY_SIZE(mmap), - .clock_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_CLOCK, - CLOCK_IDX_INTERCONNECT), - .hnf_cal_mode = true, - }), + .get_element_table = cmn_rhodes_get_device_table, + .data = NULL }; diff --git a/product/rddaniel/scp_ramfw/firmware.mk b/product/rddaniel/scp_ramfw/firmware.mk index 41770300fcef0716c8fa7efd5cef778bb761e44f..79f38b3adba1f1c4f1264e7736e5dd1244b479e1 100644 --- a/product/rddaniel/scp_ramfw/firmware.mk +++ b/product/rddaniel/scp_ramfw/firmware.mk @@ -17,6 +17,13 @@ BS_FIRMWARE_MODULES := \ pcid \ pl011 \ log \ + pik_clock \ + css_clock \ + clock \ + gtimer \ + timer \ + cmn_rhodes \ + apcontext \ ppu_v1 \ system_power \ mhu2 \ @@ -24,16 +31,9 @@ BS_FIRMWARE_MODULES := \ scmi \ sds \ system_pll \ - pik_clock \ - css_clock \ - clock \ - gtimer \ - timer \ - apcontext \ power_domain \ scmi_power_domain \ scmi_system_power \ - cmn_rhodes \ rddaniel_system BS_FIRMWARE_SOURCES := \