]> nv-tegra.nvidia Code Review - linux-4.9.git/commitdiff
tegra: fuse: add redundant AID WAR support
authorDaniel Fu <danifu@nvidia.com>
Fri, 28 Sep 2018 08:49:34 +0000 (16:49 +0800)
committermobile promotions <svcmobile_promotions@nvidia.com>
Tue, 30 Oct 2018 10:30:53 +0000 (03:30 -0700)
Kernel v3.10 assumed AID fuse as redundant.
This is a WAR to align with legacy kernel and clients
for reading the same value.

Bug 200414304

Change-Id: I35a83f1372c060ed5449c7b4884395b888cc27c4
Signed-off-by: Daniel Fu <danifu@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1850902
(cherry picked from commit 3b1bead2ab980d28f85397d89b3053f2e053f433)
Reviewed-on: https://git-master.nvidia.com/r/1935041
Reviewed-by: Mihir Joshi <mihirj@nvidia.com>
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
drivers/soc/tegra/fuse/fuse-burn.c

index 9d14e6692c0d54adc533ef4a8b9806400d8d1f28..5d25a36d0edb7b1253c5747e04a7660c0e95d32f 100644 (file)
@@ -71,6 +71,7 @@ struct fuse_burn_data {
        u32 reg_offset;
        bool is_redundant;
        bool is_big_endian;
+       bool redundant_war;
        struct device_attribute attr;
 };
 
@@ -343,9 +344,10 @@ static void tegra_fuse_get_fuse(struct fuse_burn_data *data, u32 *macro_buf)
        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);
@@ -355,7 +357,8 @@ static void tegra_fuse_get_fuse(struct fuse_burn_data *data, u32 *macro_buf)
                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);
                        }
@@ -534,6 +537,7 @@ static ssize_t tegra_fuse_calc_h2_code(struct device *dev,
                .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,                               \
@@ -714,6 +718,26 @@ static int tegra_fuse_burn_probe(struct platform_device *pdev)
                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");