u32 reg_offset;
bool is_redundant;
bool is_big_endian;
+ bool redundant_war;
struct device_attribute attr;
};
int nbits = data->size_bits;
int offset = data->start_offset;
bool is_redundant = data->is_redundant;
+ bool redundant_war = data->redundant_war;
int bit_position = 0;
int i, loops;
- u32 actual_val, redun_val;
+ u32 actual_val, redun_val = 0;
do {
actual_val = fuse_cmd_read(offset);
for (i = 0; i < loops; i++) {
if (actual_val & (BIT(start_bit + i)))
*macro_buf |= BIT(bit_position);
- if (is_redundant) {
+ /* If redundant WAR enable, skip redun_val */
+ if (is_redundant && !redundant_war) {
if (redun_val & (BIT(start_bit + i)))
*macro_buf |= BIT(bit_position);
}
.reg_offset = c_off, \
.is_redundant = is_red, \
.is_big_endian = is_be, \
+ .redundant_war = false, \
.attr.show = tegra_fuse_show, \
.attr.store = tegra_fuse_store, \
.attr.attr.name = #fname, \
return -EINVAL;
}
+ /* Since T210, we support the bit offset and we will have redundant fuse
+ * for some of the fuse. But one exception(AID fuse) is not redundant.
+ * Unfortunately, some legacy kernel(eg. Kernel v3.10) will assume the
+ * AID fuse as redundant and read the fuse value in redundant way, from
+ * address X and address X+2, which should be address X and address X+1
+ * instead.
+ * To align the platform we release with legacy kernel and client, add
+ * the "redundant-aid-war" for reading the same value as in the past.
+ * Or the inconsistent value may cause an issue in some case.
+ */
+ if (of_property_read_bool(np, "nvidia,redundant-aid-war")) {
+ for (i = 0; i < ARRAY_SIZE(fuse_dev->hw->burn_data) &&
+ fuse_dev->hw->burn_data[i].name != NULL; i++)
+ if (!strcmp(fuse_dev->hw->burn_data[i].name, "aid")) {
+ fuse_dev->hw->burn_data[i].is_redundant = true;
+ fuse_dev->hw->burn_data[i].redundant_war =
+ true;
+ }
+ }
+
fuse_dev->pgm_clk = devm_clk_get(&pdev->dev, "clk_m");
if (IS_ERR(fuse_dev->pgm_clk)) {
dev_err(&pdev->dev, "failed to get clk_m err\n");