Add support for LLCC V6. V6 adds several additional usecase IDs, rearrages several registers and offsets, and supports slice IDs over 31, so add a new function for programming LLCC V6. Signed-off-by: Melody Olvera <quic_molvera@xxxxxxxxxxx> --- drivers/soc/qcom/llcc-qcom.c | 215 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 211 insertions(+), 4 deletions(-) diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c index 56823b6a2facc4345265e29b60da24a391e3707d..ae271b112246e50fa6165b92a5562457f23d9e4b 100644 --- a/drivers/soc/qcom/llcc-qcom.c +++ b/drivers/soc/qcom/llcc-qcom.c @@ -35,6 +35,9 @@ #define ATTR0_RES_WAYS_MASK GENMASK(15, 0) #define ATTR0_BONUS_WAYS_MASK GENMASK(31, 16) #define ATTR0_BONUS_WAYS_SHIFT 16 +#define ATTR2_PROBE_TARGET_WAYS_MASK BIT(4) +#define ATTR2_FIXED_SIZE_MASK BIT(8) +#define ATTR2_PRIORITY_MASK GENMASK(14, 12) #define LLCC_STATUS_READ_DELAY 100 #define CACHE_LINE_SIZE_SHIFT 6 @@ -49,6 +52,10 @@ #define LLCC_TRP_ATTR0_CFGn(n) (0x21000 + SZ_8 * n) #define LLCC_TRP_ATTR1_CFGn(n) (0x21004 + SZ_8 * n) #define LLCC_TRP_ATTR2_CFGn(n) (0x21100 + SZ_4 * n) +#define LLCC_V6_TRP_ATTR0_CFGn(n) (cfg->reg_offset[LLCC_TRP_ATTR0_CFG] + SZ_64 * n) +#define LLCC_V6_TRP_ATTR1_CFGn(n) (cfg->reg_offset[LLCC_TRP_ATTR1_CFG] + SZ_64 * n) +#define LLCC_V6_TRP_ATTR2_CFGn(n) (cfg->reg_offset[LLCC_TRP_ATTR2_CFG] + SZ_64 * n) +#define LLCC_V6_TRP_ATTR3_CFGn(n) (cfg->reg_offset[LLCC_TRP_ATTR3_CFG] + SZ_64 * n) #define LLCC_TRP_SCID_DIS_CAP_ALLOC 0x21f00 #define LLCC_TRP_PCB_ACT 0x21f04 @@ -66,6 +73,7 @@ #define LLCC_VERSION_2_0_0_0 0x02000000 #define LLCC_VERSION_2_1_0_0 0x02010000 #define LLCC_VERSION_4_1_0_0 0x04010000 +#define LLCC_VERSION_6_0_0_0 0X06000000 /** * struct llcc_slice_config - Data associated with the llcc slice @@ -153,6 +161,21 @@ struct qcom_sct_config { enum llcc_reg_offset { LLCC_COMMON_HW_INFO, LLCC_COMMON_STATUS0, + LLCC_TRP_ATTR0_CFG, + LLCC_TRP_ATTR1_CFG, + LLCC_TRP_ATTR2_CFG, + LLCC_TRP_ATTR3_CFG, + LLCC_TRP_SID_DIS_CAP_ALLOC, + LLCC_TRP_ALGO_STALE_EN, + LLCC_TRP_ALGO_STALE_CAP_EN, + LLCC_TRP_ALGO_MRU0, + LLCC_TRP_ALGO_MRU1, + LLCC_TRP_ALGO_ALLOC0, + LLCC_TRP_ALGO_ALLOC1, + LLCC_TRP_ALGO_ALLOC2, + LLCC_TRP_ALGO_ALLOC3, + LLCC_TRP_WRS_EN, + LLCC_TRP_WRS_CACHEABLE_EN, }; static const struct llcc_slice_config ipq5424_data[] = { @@ -3161,6 +3184,33 @@ static const struct llcc_edac_reg_offset llcc_v2_1_edac_reg_offset = { .drp_ecc_db_err_syn0 = 0x52120, }; +static const struct llcc_edac_reg_offset llcc_v6_edac_reg_offset = { + .trp_ecc_error_status0 = 0x47448, + .trp_ecc_error_status1 = 0x47450, + .trp_ecc_sb_err_syn0 = 0x47490, + .trp_ecc_db_err_syn0 = 0x474d0, + .trp_ecc_error_cntr_clear = 0x47444, + .trp_interrupt_0_status = 0x47600, + .trp_interrupt_0_clear = 0x47604, + .trp_interrupt_0_enable = 0x47608, + + /* LLCC Common registers */ + .cmn_status0 = 0x6400c, + .cmn_interrupt_0_enable = 0x6401c, + .cmn_interrupt_2_enable = 0x6403c, + + /* LLCC DRP registers */ + .drp_ecc_error_cfg = 0x80000, + .drp_ecc_error_cntr_clear = 0x80004, + .drp_interrupt_status = 0x80020, + .drp_interrupt_clear = 0x80028, + .drp_interrupt_enable = 0x8002c, + .drp_ecc_error_status0 = 0x820f4, + .drp_ecc_error_status1 = 0x820f8, + .drp_ecc_sb_err_syn0 = 0x820fc, + .drp_ecc_db_err_syn0 = 0x82120, +}; + /* LLCC register offset starting from v1.0.0 */ static const u32 llcc_v1_reg_offset[] = { [LLCC_COMMON_HW_INFO] = 0x00030000, @@ -3173,6 +3223,27 @@ static const u32 llcc_v2_1_reg_offset[] = { [LLCC_COMMON_STATUS0] = 0x0003400c, }; +/* LLCC register offset starting from v6.0.0 */ +static const u32 llcc_v6_reg_offset[] = { + [LLCC_COMMON_HW_INFO] = 0x00064000, + [LLCC_COMMON_STATUS0] = 0x0006400c, + [LLCC_TRP_ATTR0_CFG] = 0x00041000, + [LLCC_TRP_ATTR1_CFG] = 0x00041008, + [LLCC_TRP_ATTR2_CFG] = 0x00041010, + [LLCC_TRP_ATTR3_CFG] = 0x00041014, + [LLCC_TRP_SID_DIS_CAP_ALLOC] = 0x00042000, + [LLCC_TRP_ALGO_STALE_EN] = 0x00042008, + [LLCC_TRP_ALGO_STALE_CAP_EN] = 0x00042010, + [LLCC_TRP_ALGO_MRU0] = 0x00042018, + [LLCC_TRP_ALGO_MRU1] = 0x00042020, + [LLCC_TRP_ALGO_ALLOC0] = 0x00042028, + [LLCC_TRP_ALGO_ALLOC1] = 0x00042030, + [LLCC_TRP_ALGO_ALLOC2] = 0x00042038, + [LLCC_TRP_ALGO_ALLOC3] = 0x00042040, + [LLCC_TRP_WRS_EN] = 0x00042080, + [LLCC_TRP_WRS_CACHEABLE_EN] = 0x00042088, +}; + static const struct qcom_llcc_config qcs615_cfg[] = { { .sct_data = qcs615_data, @@ -3869,6 +3940,134 @@ static int _qcom_llcc_cfg_program(const struct llcc_slice_config *config, return ret; } +static int _qcom_llcc_cfg_program_v6(const struct llcc_slice_config *config, + const struct qcom_llcc_config *cfg) +{ + u32 stale_en, stale_cap_en, mru_uncap_en, mru_rollover; + u32 alloc_oneway_en, ovcap_en, ovcap_prio, vict_prio; + u32 attr0_cfg, attr1_cfg, attr2_cfg, attr3_cfg; + u32 attr0_val, attr1_val, attr2_val, attr3_val; + u32 disable_cap_alloc, wren, wr_cache_en; + u32 slice_offset, reg_offset; + struct llcc_slice_desc *desc; + int ret; + + attr0_cfg = LLCC_V6_TRP_ATTR0_CFGn(config->slice_id); + attr1_cfg = LLCC_V6_TRP_ATTR1_CFGn(config->slice_id); + attr2_cfg = LLCC_V6_TRP_ATTR2_CFGn(config->slice_id); + attr3_cfg = LLCC_V6_TRP_ATTR3_CFGn(config->slice_id); + + attr0_val = config->res_ways; + attr1_val = config->bonus_ways; + attr2_val = config->cache_mode; + attr2_val |= FIELD_PREP(ATTR2_PROBE_TARGET_WAYS_MASK, config->probe_target_ways); + attr2_val |= FIELD_PREP(ATTR2_FIXED_SIZE_MASK, config->fixed_size); + attr2_val |= FIELD_PREP(ATTR2_PRIORITY_MASK, config->priority); + + attr3_val = MAX_CAP_TO_BYTES(config->max_cap); + attr3_val /= drv_data->num_banks; + attr3_val >>= CACHE_LINE_SIZE_SHIFT; + + ret = regmap_write(drv_data->bcast_regmap, attr0_cfg, attr0_val); + if (ret) + return ret; + + ret = regmap_write(drv_data->bcast_regmap, attr1_cfg, attr1_val); + if (ret) + return ret; + + ret = regmap_write(drv_data->bcast_regmap, attr2_cfg, attr2_val); + if (ret) + return ret; + + ret = regmap_write(drv_data->bcast_regmap, attr3_cfg, attr3_val); + if (ret) + return ret; + + slice_offset = config->slice_id % 32; + reg_offset = (config->slice_id / 32) * 4; + + wren = config->write_scid_en << slice_offset; + ret = regmap_update_bits(drv_data->bcast_regmap, + cfg->reg_offset[LLCC_TRP_WRS_EN] + reg_offset, + BIT(slice_offset), wren); + if (ret) + return ret; + + wr_cache_en = config->write_scid_cacheable_en << slice_offset; + ret = regmap_update_bits(drv_data->bcast_regmap, + cfg->reg_offset[LLCC_TRP_WRS_CACHEABLE_EN] + reg_offset, + BIT(slice_offset), wr_cache_en); + if (ret) + return ret; + + stale_en = config->stale_en << slice_offset; + ret = regmap_update_bits(drv_data->bcast_regmap, + cfg->reg_offset[LLCC_TRP_ALGO_STALE_EN] + reg_offset, + BIT(slice_offset), stale_en); + if (ret) + return ret; + + stale_cap_en = config->stale_cap_en << slice_offset; + ret = regmap_update_bits(drv_data->bcast_regmap, + cfg->reg_offset[LLCC_TRP_ALGO_STALE_CAP_EN] + reg_offset, + BIT(slice_offset), stale_cap_en); + if (ret) + return ret; + + mru_uncap_en = config->mru_uncap_en << slice_offset; + ret = regmap_update_bits(drv_data->bcast_regmap, + cfg->reg_offset[LLCC_TRP_ALGO_MRU0] + reg_offset, + BIT(slice_offset), mru_uncap_en); + if (ret) + return ret; + + mru_rollover = config->mru_rollover << slice_offset; + ret = regmap_update_bits(drv_data->bcast_regmap, + cfg->reg_offset[LLCC_TRP_ALGO_MRU1] + reg_offset, + BIT(slice_offset), mru_rollover); + if (ret) + return ret; + + alloc_oneway_en = config->alloc_oneway_en << slice_offset; + ret = regmap_update_bits(drv_data->bcast_regmap, + cfg->reg_offset[LLCC_TRP_ALGO_ALLOC0] + reg_offset, + BIT(slice_offset), alloc_oneway_en); + if (ret) + return ret; + + ovcap_en = config->ovcap_en << slice_offset; + ret = regmap_update_bits(drv_data->bcast_regmap, + cfg->reg_offset[LLCC_TRP_ALGO_ALLOC1] + reg_offset, + BIT(slice_offset), ovcap_en); + if (ret) + return ret; + + ovcap_prio = config->ovcap_prio << slice_offset; + ret = regmap_update_bits(drv_data->bcast_regmap, + cfg->reg_offset[LLCC_TRP_ALGO_ALLOC2] + reg_offset, + BIT(slice_offset), ovcap_prio); + if (ret) + return ret; + + vict_prio = config->vict_prio << slice_offset; + ret = regmap_update_bits(drv_data->bcast_regmap, + cfg->reg_offset[LLCC_TRP_ALGO_ALLOC3] + reg_offset, + BIT(slice_offset), vict_prio); + if (ret) + return ret; + + if (config->activate_on_init) { + desc = llcc_slice_getd(config->usecase_id); + if (PTR_ERR_OR_ZERO(desc)) + return -EINVAL; + + ret = llcc_slice_activate(desc); + } + + return ret; +} + static int qcom_llcc_cfg_program(struct platform_device *pdev, const struct qcom_llcc_config *cfg) { @@ -3880,10 +4079,18 @@ static int qcom_llcc_cfg_program(struct platform_device *pdev, sz = drv_data->cfg_size; llcc_table = drv_data->cfg; - for (i = 0; i < sz; i++) { - ret = _qcom_llcc_cfg_program(&llcc_table[i], cfg); - if (ret) - return ret; + if (drv_data->version >= LLCC_VERSION_6_0_0_0) { + for (i = 0; i < sz; i++) { + ret = _qcom_llcc_cfg_program_v6(&llcc_table[i], cfg); + if (ret) + return ret; + } + } else { + for (i = 0; i < sz; i++) { + ret = _qcom_llcc_cfg_program(&llcc_table[i], cfg); + if (ret) + return ret; + } } return ret; -- 2.46.1