tegra: hwpm: th500: soc: 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

Change-Id: I28e92c6186ba35fc19bfac67ed137b5c7fca645a
Signed-off-by: Vedashree Vidwans <vvidwans@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-hwpm/+/3006813
(cherry picked from commit 228851f45b787c93044d9ff0daf28baecda73f82)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-hwpm/+/3115439
Reviewed-by: Seema Khowala <seemaj@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
Vedashree Vidwans
2023-11-06 14:50:37 -08:00
committed by mobile promotions
parent 3a69716646
commit 6a90ec671c

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
/* SPDX-FileCopyrightText: Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. /* SPDX-FileCopyrightText: Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"), * copy of this software and associated documentation files (the "Software"),
@@ -292,6 +292,87 @@ fail:
return ret; return ret;
} }
static int th500_hwpm_validate_emc_config(struct tegra_soc_hwpm *hwpm)
{
struct tegra_soc_hwpm_chip *active_chip = hwpm->active_chip;
#if defined(CONFIG_TH500_HWPM_IP_MSS_CHANNEL)
struct hwpm_ip *chip_ip = NULL;
struct hwpm_ip_inst *ip_inst = NULL;
u32 element_mask_max = 0U;
u32 inst_idx = 0U;
#endif
u32 emc_disable_fuse_val = 0U;
u32 emc_disable_fuse_val_mask = 0xFU;
u32 emc_disable_fuse_bit_idx = 0U;
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_disable_fuse_bit_idx)) {
emc_element_floorsweep_mask |=
(0xFU << (emc_disable_fuse_bit_idx * 4U));
}
emc_disable_fuse_bit_idx++;
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(); idx++) {
switch (idx) {
#if defined(CONFIG_TH500_HWPM_IP_MSS_CHANNEL)
case TH500_HWPM_IP_MSS_CHANNEL:
#endif
# if defined(CONFIG_TH500_HWPM_IP_MSS_CHANNEL)
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:
break;
}
}
return 0;
}
int th500_hwpm_validate_current_config(struct tegra_soc_hwpm *hwpm) int th500_hwpm_validate_current_config(struct tegra_soc_hwpm *hwpm)
{ {
u32 production_mode = 0U; u32 production_mode = 0U;
@@ -310,6 +391,12 @@ int th500_hwpm_validate_current_config(struct tegra_soc_hwpm *hwpm)
return 0; return 0;
} }
err = th500_hwpm_validate_emc_config(hwpm);
if (err != 0) {
tegra_hwpm_err(hwpm, "failed to validate emc config");
return err;
}
/* Read production mode fuse */ /* Read production mode fuse */
err = tegra_hwpm_fuse_readl_prod_mode(hwpm, &production_mode); err = tegra_hwpm_fuse_readl_prod_mode(hwpm, &production_mode);
if (err != 0) { if (err != 0) {