[FOSS_TLK]platform: tegra: cleanup fuse handling
Scott Long [Wed, 19 Nov 2014 23:31:46 +0000 (15:31 -0800)]
Move chip-specific details on fuse handling into arch-specific
file (e.g. platform/tegra4/fuse.c).

This code exports interfaces (fuse_read, fuse_make_visible,
fuse_make_invisible) to the common tegra fuse code that hides
details like register offsets/layouts, etc.

Change-Id: I6472861f89a50bee7541395bd1ea048a27c181e3
Signed-off-by: Scott Long <scottl@nvidia.com>
Reviewed-on: http://git-master/r/707295
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Varun Wadekar <vwadekar@nvidia.com>
Tested-by: Varun Wadekar <vwadekar@nvidia.com>

platform/tegra/common/fuse.c
platform/tegra/common/platform.c
platform/tegra/include/platform/platform_fuse.h
platform/tegra/include/platform/tegra4/fuse_ext.h [new file with mode: 0644]
platform/tegra/tegra4/fuse.c [new file with mode: 0644]
platform/tegra/tegra4/rules.mk

index a0ab508..17f0c65 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2014, NVIDIA CORPORATION. All rights reserved
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files
 #include <debug.h>
 #include <string.h>
 #include <platform.h>
-#include <reg.h>
 
 #include <platform/platform_fuse.h>
-#include <platform/memmap.h>
-
-/*
- * Fuse location information.
- */
-#if defined(TARGET_T124) || defined(TARGET_T132)
-
-#define ODM_PROD_ADDR                  (0x0)
-#define ODM_PROD_START_BIT             (11)
-
-#define ODM_RESERVED0_ADDR             (0x2E)
-#define ODM_RESERVED0_START_BIT                (5)
-
-#elif defined(TARGET_T210) || defined(TARGET_T186)
-
-#define ODM_PROD_ADDR                  (0x0)
-#define ODM_PROD_START_BIT             (11)
-
-#define ODM_RESERVED0_ADDR             (0x2E)
-#define ODM_RESERVED0_START_BIT                (17)
-
-#else
-
-#error unknown architecture
-
-#endif
-
-/*
- * The rollback protection fuses are in the ODM reserved fuse range.
- * ODM reserved fuses are 256bits wide.  To calculate the location of
- * a given fuse we need to determine its offset from ODM_RESERVED0's
- * address/start bit.
- *
- * Note that ODM reserved addresses increment by 2 (so if ODM_RESERVED0
- * is 0x2e then ODM_RESERVED1 is 0x30, etc).
- */
-
-/* calculate ODM_RESERVED1[13:12] bit offset from start of reserved block */
-#define RB_ENABLE_BIT                  (ODM_RESERVED0_START_BIT + 32 + 12)
-#define RB_KEY_PROGRAMMED_BIT          (ODM_RESERVED0_START_BIT + 32 + 13)
-
-/* given bit offset from start of reserved block get address */
-#define GET_ADDR(b)                    (ODM_RESERVED0_ADDR + (((b) / 32) * 2))
-
-/* given bit offset from start of reserved block get addr-relative start bit */
-#define GET_START_BIT(b)               ((b) % 32)
-
-/* get fuse-specific address/start bit */
-#define RB_ENABLE_ADDR                 GET_ADDR(RB_ENABLE_BIT)
-#define RB_ENABLE_START_BIT            GET_START_BIT(RB_ENABLE_BIT)
-
-#define RB_KEY_PROGRAMMED_ADDR         GET_ADDR(RB_KEY_PROGRAMMED_BIT)
-#define RB_KEY_PROGRAMMED_START_BIT    GET_START_BIT(RB_KEY_PROGRAMMED_BIT)
 
 /* fuse values table */
 static uint32_t fuse_values[FUSE_ID_MAX];
-
-/* fuse register information */
-#define FUSECTRL_0                     (0x0)
-#define FUSEADDR_0                     (0x4)
-#define FUSERDATA_0                    (0x8)
-#define FUSEWDATA_0                    (0xC)
-
-#define FUSECTRL_STATE_MASK            (0x1F << 16)
-#define FUSECTRL_STATE_IDLE            (0x4 << 16)
-
-#define FUSECTRL_CMD_MASK              (0x3 << 0)
-#define FUSECTRL_CMD_READ              (0x1)
-#define FUSECTRL_CMD_WRITE             (0x2)
-#define FUSECTRL_CMD_SENSE             (0x3)
-
-#define FUSE_WRITE32(o,v)              writel((v), TEGRA_FUSE_BASE + (o))
-#define FUSE_READ32(o)                         readl(TEGRA_FUSE_BASE + (o))
-
-/* car register information */
-#define CLK_MASK_ARM_0                 (0x48)
-#define CLK_MASK_ARM_CFG_ALL_VISIBLE   (0x10000000)
-
-#define RST_DEVICES_H_0                        (0x8)
-#define RST_DEVICES_H_SWR_FUSE_RST     (0x80)
-
-#define CLK_OUT_ENB_H_0                        (0x14)
-#define CLK_OUT_ENB_H_CLK_ENB_FUSE     (0x80)
-
-#define CAR_WRITE32(o,v)               writel((v), TEGRA_CLK_RESET_BASE + (o))
-#define CAR_READ32(o)                  readl(TEGRA_CLK_RESET_BASE + (o))
-
-static void fuse_wait_for_idle(void)
-{
-       uint32_t data;
-
-       do {
-               spin(1);
-               data = FUSE_READ32(FUSECTRL_0);
-       } while ((data & FUSECTRL_STATE_MASK) != FUSECTRL_STATE_IDLE);
-}
-
-static void fuse_cmd_sense(void)
-{
-       uint32_t data;
-
-       fuse_wait_for_idle();
-
-       data = FUSE_READ32(FUSECTRL_0);
-       data &= ~FUSECTRL_CMD_MASK;
-       data |= FUSECTRL_CMD_SENSE;
-       FUSE_WRITE32(FUSECTRL_0, data);
-
-       fuse_wait_for_idle();
-}
-
-static uint32_t fuse_read(uint32_t addr)
-{
-       uint32_t data;
-
-       fuse_cmd_sense();
-
-       fuse_wait_for_idle();
-
-       FUSE_WRITE32(FUSEADDR_0, addr);
-       data = FUSE_READ32(FUSECTRL_0);
-       data &= ~FUSECTRL_CMD_MASK;
-       data |= FUSECTRL_CMD_READ;
-       FUSE_WRITE32(FUSECTRL_0, data);
-
-       fuse_wait_for_idle();
-
-       data = FUSE_READ32(FUSERDATA_0);
-
-       return data;
-}
+static bool fuse_init_done;
 
 void platform_fuse_init(void)
 {
-       uint32_t fuse_data, clk_mask_arm_data = 0;
-       bool made_visible = false;
+       uint32_t fuse_data;
+       bool made_visible;
 
-       /* for now assume fuse block is out of reset with clock enabled */
-       ASSERT(!(CAR_READ32(RST_DEVICES_H_0) & RST_DEVICES_H_SWR_FUSE_RST));
-       ASSERT(CAR_READ32(CLK_OUT_ENB_H_0) & CLK_OUT_ENB_H_CLK_ENB_FUSE);
+       /* expose fuse registers for access */
+       made_visible = fuse_make_visible();
 
        /* clear fuse values */
        memset(fuse_values, 0, sizeof(fuse_values));
 
-       /* make all fuse registers visible */
-       clk_mask_arm_data = CAR_READ32(CLK_MASK_ARM_0);
-       if ((clk_mask_arm_data & CLK_MASK_ARM_CFG_ALL_VISIBLE) == 0) {
-               CAR_WRITE32(CLK_MASK_ARM_0,
-                       clk_mask_arm_data | CLK_MASK_ARM_CFG_ALL_VISIBLE);
-               made_visible = true;
-       }
-
        /* save odm production fuse value */
        fuse_data = fuse_read(ODM_PROD_ADDR);
        if (fuse_data & (1 << ODM_PROD_START_BIT))
@@ -194,22 +57,25 @@ void platform_fuse_init(void)
        if (fuse_data & (1 << RB_KEY_PROGRAMMED_START_BIT))
                fuse_values[FUSE_ID_RB_KEY_PROGRAMMED] = true;
 
-       dprintf(SPEW, "%s: odm_prod %d rpb_en %d rpb_key_prgrm %d\n",
+       dprintf(INFO, "%s: odm_prod %d rpb_en %d rpb_key_prgrm %d\n",
                __func__,
                fuse_values[FUSE_ID_ODM_PROD],
                fuse_values[FUSE_ID_RB_ENABLE],
                fuse_values[FUSE_ID_RB_KEY_PROGRAMMED]);
 
        /* move fuses back to invisible if necessary */
-       if (made_visible) {
-               CAR_WRITE32(CLK_MASK_ARM_0, clk_mask_arm_data);
-       }
+       if (made_visible)
+               fuse_make_invisible();
+
+       fuse_init_done = true;
 
        return;
 }
 
-uint32_t platform_fuse_show(enum fuse_ids fuse_id)
+uint32_t platform_fuse_get(enum fuse_ids fuse_id)
 {
+       ASSERT(fuse_init_done);
+
        if (fuse_id >= FUSE_ID_MAX)
                return false;
 
index 1e18645..fa9095a 100644 (file)
@@ -236,10 +236,10 @@ int platform_ss_get_config(uint32_t *ss_config)
         * indicating if rollback protection should be enabled and
         * if so, should key provisioning be performed.
         */
-       if (platform_fuse_show(FUSE_ID_ODM_PROD)) {
-               if (platform_fuse_show(FUSE_ID_RB_ENABLE)) {
+       if (platform_fuse_get(FUSE_ID_ODM_PROD)) {
+               if (platform_fuse_get(FUSE_ID_RB_ENABLE)) {
                        *ss_config |= OTE_SS_CONFIG_RB_ENABLE;
-                       if (!platform_fuse_show(FUSE_ID_RB_KEY_PROGRAMMED)) {
+                       if (!platform_fuse_get(FUSE_ID_RB_KEY_PROGRAMMED)) {
                                *ss_config |= OTE_SS_CONFIG_RB_PROGRAM_KEY;
                        }
                }
index 84c60c5..f5d41f9 100644 (file)
@@ -23,6 +23,8 @@
 #ifndef __PLATFORM_FUSE_H
 #define __PLATFORM_FUSE_H
 
+#include <fuse_ext.h>
+
 /*
  * ODM_PROD          -> ODM production fuse set
  * RB_ENABLE         -> enable rollback protection feature
@@ -36,6 +38,6 @@ enum fuse_ids {
 };
 
 void platform_fuse_init(void);
-uint32_t platform_fuse_show(enum fuse_ids fuse);
+uint32_t platform_fuse_get(enum fuse_ids fuse);
 
 #endif
diff --git a/platform/tegra/include/platform/tegra4/fuse_ext.h b/platform/tegra/include/platform/tegra4/fuse_ext.h
new file mode 100644 (file)
index 0000000..84387d6
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __FUSE_EXT_H
+#define __FUSE_EXT_H
+
+/*
+ * Fuse location information.
+ */
+#if defined(TARGET_T124) || defined(TARGET_T132)
+
+#define ODM_PROD_ADDR                  (0x0)
+#define ODM_PROD_START_BIT             (11)
+
+#define ODM_RESERVED0_ADDR             (0x2E)
+#define ODM_RESERVED0_START_BIT                (5)
+
+#elif defined(TARGET_T210) || defined(TARGET_T186)
+
+#define ODM_PROD_ADDR                  (0x0)
+#define ODM_PROD_START_BIT             (11)
+
+#define ODM_RESERVED0_ADDR             (0x2E)
+#define ODM_RESERVED0_START_BIT                (17)
+
+#else
+
+#error unknown architecture
+
+#endif
+
+/*
+ * The rollback protection fuses are in the ODM reserved fuse range.
+ * ODM reserved fuses are 256bits wide.  To calculate the location of
+ * a given fuse we need to determine its offset from ODM_RESERVED0's
+ * address/start bit.
+ *
+ * Note that ODM reserved addresses increment by 2 (so if ODM_RESERVED0
+ * is 0x2e then ODM_RESERVED1 is 0x30, etc).
+ */
+
+/* calculate ODM_RESERVED1[13:12] bit offset from start of reserved block */
+#define RB_ENABLE_BIT                  (ODM_RESERVED0_START_BIT + 32 + 12)
+#define RB_KEY_PROGRAMMED_BIT          (ODM_RESERVED0_START_BIT + 32 + 13)
+
+/* given bit offset from start of reserved block get address */
+#define GET_ADDR(b)                    (ODM_RESERVED0_ADDR + (((b) / 32) * 2))
+
+/* given bit offset from start of reserved block get addr-relative start bit */
+#define GET_START_BIT(b)               ((b) % 32)
+
+/* get fuse-specific address/start bit */
+#define RB_ENABLE_ADDR                 GET_ADDR(RB_ENABLE_BIT)
+#define RB_ENABLE_START_BIT            GET_START_BIT(RB_ENABLE_BIT)
+
+#define RB_KEY_PROGRAMMED_ADDR         GET_ADDR(RB_KEY_PROGRAMMED_BIT)
+#define RB_KEY_PROGRAMMED_START_BIT    GET_START_BIT(RB_KEY_PROGRAMMED_BIT)
+
+/* platform-dependent routines */
+bool fuse_make_visible(void);
+void fuse_make_invisible(void);
+uint32_t fuse_read(uint32_t addr);
+
+#endif
diff --git a/platform/tegra/tegra4/fuse.c b/platform/tegra/tegra4/fuse.c
new file mode 100644 (file)
index 0000000..ce80bd2
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <assert.h>
+#include <debug.h>
+#include <platform.h>
+#include <reg.h>
+
+#include <platform/memmap.h>
+
+/* fuse register information */
+#define FUSECTRL_0                     (0x0)
+#define FUSEADDR_0                     (0x4)
+#define FUSERDATA_0                    (0x8)
+#define FUSEWDATA_0                    (0xC)
+
+#define FUSECTRL_STATE_MASK            (0x1F << 16)
+#define FUSECTRL_STATE_IDLE            (0x4 << 16)
+
+#define FUSECTRL_CMD_MASK              (0x3 << 0)
+#define FUSECTRL_CMD_READ              (0x1)
+#define FUSECTRL_CMD_WRITE             (0x2)
+#define FUSECTRL_CMD_SENSE             (0x3)
+
+#define FUSE_WRITE32(o,v)              writel((v), TEGRA_FUSE_BASE + (o))
+#define FUSE_READ32(o)                         readl(TEGRA_FUSE_BASE + (o))
+
+/* car register information */
+#define CLK_MASK_ARM_0                 (0x48)
+#define CLK_MASK_ARM_CFG_ALL_VISIBLE   (0x10000000)
+
+#define RST_DEVICES_H_0                        (0x8)
+#define RST_DEVICES_H_SWR_FUSE_RST     (0x80)
+
+#define CLK_OUT_ENB_H_0                        (0x14)
+#define CLK_OUT_ENB_H_CLK_ENB_FUSE     (0x80)
+
+#define CAR_WRITE32(o,v)               writel((v), TEGRA_CLK_RESET_BASE + (o))
+#define CAR_READ32(o)                  readl(TEGRA_CLK_RESET_BASE + (o))
+
+static void fuse_wait_for_idle(void)
+{
+       uint32_t data;
+
+       do {
+               spin(1);
+               data = FUSE_READ32(FUSECTRL_0);
+       } while ((data & FUSECTRL_STATE_MASK) != FUSECTRL_STATE_IDLE);
+}
+
+static void fuse_cmd_sense(void)
+{
+       uint32_t data;
+
+       fuse_wait_for_idle();
+
+       data = FUSE_READ32(FUSECTRL_0);
+       data &= ~FUSECTRL_CMD_MASK;
+       data |= FUSECTRL_CMD_SENSE;
+       FUSE_WRITE32(FUSECTRL_0, data);
+
+       fuse_wait_for_idle();
+}
+
+bool fuse_make_visible(void)
+{
+       uint32_t clk_mask_arm_data = 0;
+
+       /* for now assume fuse block is out of reset with clock enabled */
+       ASSERT(!(CAR_READ32(RST_DEVICES_H_0) & RST_DEVICES_H_SWR_FUSE_RST));
+       ASSERT(CAR_READ32(CLK_OUT_ENB_H_0) & CLK_OUT_ENB_H_CLK_ENB_FUSE);
+
+       /* make all fuse registers visible */
+       clk_mask_arm_data = CAR_READ32(CLK_MASK_ARM_0);
+       if ((clk_mask_arm_data & CLK_MASK_ARM_CFG_ALL_VISIBLE) == 0) {
+               CAR_WRITE32(CLK_MASK_ARM_0,
+                       clk_mask_arm_data | CLK_MASK_ARM_CFG_ALL_VISIBLE);
+               return true;
+       }
+
+       return false;
+}
+
+void fuse_make_invisible(void)
+{
+       uint32_t clk_mask_arm_data = 0;
+
+       /* hide fuse registers */
+       clk_mask_arm_data = CAR_READ32(CLK_MASK_ARM_0);
+       clk_mask_arm_data &= ~CLK_MASK_ARM_CFG_ALL_VISIBLE;
+       CAR_WRITE32(CLK_MASK_ARM_0, clk_mask_arm_data);
+
+       return;
+}
+
+uint32_t fuse_read(uint32_t addr)
+{
+       uint32_t data;
+
+       fuse_cmd_sense();
+
+       fuse_wait_for_idle();
+
+       FUSE_WRITE32(FUSEADDR_0, addr);
+       data = FUSE_READ32(FUSECTRL_0);
+       data &= ~FUSECTRL_CMD_MASK;
+       data |= FUSECTRL_CMD_READ;
+       FUSE_WRITE32(FUSECTRL_0, data);
+
+       fuse_wait_for_idle();
+
+       data = FUSE_READ32(FUSERDATA_0);
+
+       return data;
+}
+
index 683acb7..bd73b01 100644 (file)
@@ -13,4 +13,5 @@ DEFINES += \
 endif
 
 MODULE_SRCS += \
+        $(LOCAL_DIR)/tegra4/fuse.c     \
         $(LOCAL_DIR)/tegra4/platform.c