From 9a9f2f36351c387fdaad22bf9d3413828f89beb6 Mon Sep 17 00:00:00 2001 From: Vedashree Vidwans Date: Wed, 22 Feb 2023 13:59:48 -0800 Subject: [PATCH] tegra: hwpm: read MC config fuse On production board, MC config details are available through fuses. Add function to read MC config fuse. Use the floorsweep fuse info to find available elements. Bug 3936487 Signed-off-by: Vedashree Vidwans Change-Id: I9e1549e3dfb9c06d8013ca2e1d43eb21bf0289f4 (cherry picked from commit f38e98a94ab8d478af3ebe1c922da606df9b67dc) Reviewed-on: https://git-master.nvidia.com/r/c/linux-hwpm/+/2888554 Reviewed-by: Adeel Raza GVS: Gerrit_Virtual_Submit --- drivers/tegra/hwpm/common/aperture.c | 14 +++- drivers/tegra/hwpm/hal/t234/t234_ip.c | 96 +++++++++++++++++++++++++ drivers/tegra/hwpm/include/tegra_hwpm.h | 6 ++ 3 files changed, 115 insertions(+), 1 deletion(-) diff --git a/drivers/tegra/hwpm/common/aperture.c b/drivers/tegra/hwpm/common/aperture.c index fb836d2..0757129 100644 --- a/drivers/tegra/hwpm/common/aperture.c +++ b/drivers/tegra/hwpm/common/aperture.c @@ -301,11 +301,23 @@ static int tegra_hwpm_func_single_element(struct tegra_soc_hwpm *hwpm, e_info->element_arr[idx] = element; break; case TEGRA_HWPM_UPDATE_IP_INST_MASK: - /* HWPM perfmuxes can be assumed to be available */ + /* HWPM perfmuxes (PMA,RTR) can be assumed to be available */ if (element->element_type == HWPM_ELEMENT_PERFMUX) { break; } + /* Handle IPs with some value of fuse_fs_mask */ + if (ip_inst->fuse_fs_mask != 0U) { + if ((element->element_index_mask & + ip_inst->fuse_fs_mask) == 0U) { + /* This element is floorswept */ + tegra_hwpm_dbg(hwpm, hwpm_dbg_floorsweep_info, + "skip floorswept element 0x%llx", + element->start_abs_pa); + break; + } + } + /* Validate perfmux availability by reading 1st alist offset */ ret = tegra_hwpm_regops_readl(hwpm, ip_inst, element, tegra_hwpm_safe_add_u64(element->start_abs_pa, diff --git a/drivers/tegra/hwpm/hal/t234/t234_ip.c b/drivers/tegra/hwpm/hal/t234/t234_ip.c index fc9b11f..5095c2a 100644 --- a/drivers/tegra/hwpm/hal/t234/t234_ip.c +++ b/drivers/tegra/hwpm/hal/t234/t234_ip.c @@ -198,6 +198,96 @@ fail: return ret; } +static int t234_hwpm_validate_emc_config(struct tegra_soc_hwpm *hwpm) +{ + struct tegra_soc_hwpm_chip *active_chip = hwpm->active_chip; +# if defined(CONFIG_T234_HWPM_IP_MSS_CHANNEL) || \ + defined(CONFIG_T234_HWPM_IP_MSS_ISO_NISO_HUBS) || \ + defined(CONFIG_T234_HWPM_IP_MSS_MCF) + struct hwpm_ip *chip_ip = NULL; + struct hwpm_ip_inst *ip_inst = NULL; + u32 inst_idx = 0U; + u32 element_mask_max = 0U; +#endif + u32 emc_disable_fuse_val = 0U; + u32 emc_disable_fuse_val_mask = 0xFU; + u32 emc_element_floorsweep_mask = 0U; + u32 idx = 0U; + int err; + + tegra_hwpm_fn(hwpm, " "); + +#define TEGRA_FUSE_EMC_DISABLE 0x8c0U + err = tegra_hwpm_fuse_readl(hwpm, + TEGRA_FUSE_EMC_DISABLE, &emc_disable_fuse_val); + if (err != 0) { + tegra_hwpm_err(hwpm, "emc_disable fuse read failed"); + return err; + } + + /* + * In floorsweep fuse value, + * each bit corresponds to 4 elements. + * Bit value 0 indicates those elements are + * available and bit value 1 indicates + * corresponding elements are floorswept. + * + * Convert floorsweep fuse value to available EMC elements. + */ + do { + if (emc_disable_fuse_val & 0x1U) { + emc_element_floorsweep_mask = + (emc_element_floorsweep_mask << 4U) | 0xFU; + } + emc_disable_fuse_val = (emc_disable_fuse_val >> 1U); + emc_disable_fuse_val_mask = (emc_disable_fuse_val_mask >> 1U); + } while (emc_disable_fuse_val_mask != 0U); + + /* Set fuse value in MSS IP instances */ + for (idx = 0U; idx < active_chip->get_ip_max_idx(hwpm); idx++) { + switch (idx) { +#if defined(CONFIG_T234_HWPM_IP_MSS_CHANNEL) + case T234_HWPM_IP_MSS_CHANNEL: +#endif +#if defined(CONFIG_T234_HWPM_IP_MSS_ISO_NISO_HUBS) + case T234_HWPM_IP_MSS_ISO_NISO_HUBS: +#endif +#if defined(CONFIG_T234_HWPM_IP_MSS_MCF) + case T234_HWPM_IP_MSS_MCF: +#endif +# if defined(CONFIG_T234_HWPM_IP_MSS_CHANNEL) || \ + defined(CONFIG_T234_HWPM_IP_MSS_ISO_NISO_HUBS) || \ + defined(CONFIG_T234_HWPM_IP_MSS_MCF) + chip_ip = active_chip->chip_ips[idx]; + for (inst_idx = 0U; inst_idx < chip_ip->num_instances; + inst_idx++) { + ip_inst = &chip_ip->ip_inst_static_array[ + inst_idx]; + + /* + * Hence use max element mask to get correct + * fs info to use in HWPM driver. + */ + element_mask_max = tegra_hwpm_safe_sub_u32( + tegra_hwpm_safe_cast_u64_to_u32(BIT( + ip_inst->num_core_elements_per_inst)), + 1U); + ip_inst->fuse_fs_mask = + (emc_element_floorsweep_mask & + element_mask_max); + tegra_hwpm_dbg(hwpm, hwpm_info, + "ip %d, fuse_mask 0x%x", + idx, ip_inst->fuse_fs_mask); + } + break; +#endif + default: + continue; + } + } + return 0; +} + int t234_hwpm_validate_current_config(struct tegra_soc_hwpm *hwpm) { u32 production_mode = 0U; @@ -215,6 +305,12 @@ int t234_hwpm_validate_current_config(struct tegra_soc_hwpm *hwpm) return 0; } + err = t234_hwpm_validate_emc_config(hwpm); + if (err != 0) { + tegra_hwpm_err(hwpm, "failed to validate emc config"); + return err; + } + /* Read production mode fuse */ err = tegra_hwpm_fuse_readl_prod_mode(hwpm, &production_mode); if (err != 0) { diff --git a/drivers/tegra/hwpm/include/tegra_hwpm.h b/drivers/tegra/hwpm/include/tegra_hwpm.h index e468dad..36ab391 100644 --- a/drivers/tegra/hwpm/include/tegra_hwpm.h +++ b/drivers/tegra/hwpm/include/tegra_hwpm.h @@ -335,6 +335,12 @@ struct hwpm_ip_inst { */ struct tegra_hwpm_ip_ops ip_ops; + /* + * Some IPs set fuses to indicate floorsweeping info on platforms. + * This mask will contain fuse fs info if any. + */ + u32 fuse_fs_mask; + /* * An IP contains perfmux-perfmon groups that correspond to each other. * If a perfmux is present, it indicates that the corresponding