[PATCH v1 1/6] ARM: tegra: Relocate fuse code from warmboot file

Svyatoslav Ryhel clamor95 at gmail.com
Sun Jun 29 13:01:58 CEST 2025


From: Ion Agorria <ion at agorria.com>

Move a set of helpers used in warmboot code to more appropriate AP and FUSE
locations.

Signed-off-by: Ion Agorria <ion at agorria.com>
---
 arch/arm/include/asm/arch-tegra/ap.h       |  7 ++
 arch/arm/include/asm/arch-tegra/fuse.h     | 21 ++++++
 arch/arm/include/asm/arch-tegra/warmboot.h |  6 --
 arch/arm/mach-tegra/ap.c                   |  8 +++
 arch/arm/mach-tegra/cpu.h                  |  1 +
 arch/arm/mach-tegra/fuse.c                 | 63 +++++++++++++++++-
 arch/arm/mach-tegra/tegra20/warmboot.c     | 75 +---------------------
 7 files changed, 98 insertions(+), 83 deletions(-)

diff --git a/arch/arm/include/asm/arch-tegra/ap.h b/arch/arm/include/asm/arch-tegra/ap.h
index b922b2d30ea..295c3287737 100644
--- a/arch/arm/include/asm/arch-tegra/ap.h
+++ b/arch/arm/include/asm/arch-tegra/ap.h
@@ -54,6 +54,13 @@ int tegra_get_chip_sku(void);
  */
 int tegra_get_chip(void);
 
+/**
+ * Returns the pure SOC major version from the HIDREV register
+ *
+ * Return:	SOC major version
+ */
+u32 tegra_get_major_version(void);
+
 /**
  * Returns the SKU ID from the sku_info register
  *
diff --git a/arch/arm/include/asm/arch-tegra/fuse.h b/arch/arm/include/asm/arch-tegra/fuse.h
index f3f2ad8e3f2..631ebbb283c 100644
--- a/arch/arm/include/asm/arch-tegra/fuse.h
+++ b/arch/arm/include/asm/arch-tegra/fuse.h
@@ -17,8 +17,22 @@ struct fuse_regs {
 	u32 fa;				/* 0x148: FUSE_FA */
 	u32 reserved3[21];		/* 0x14C - 0x19C: */
 	u32 security_mode;		/* 0x1A0: FUSE_SECURITY_MODE */
+	u32 sbk[4];			/* 0x1A4 - 0x1B4 */
 };
 
+/* Defines the supported operating modes */
+enum fuse_operating_mode {
+	MODE_UNDEFINED = 0,
+	MODE_PRODUCTION = 3,
+	MODE_ODM_PRODUCTION_SECURE = 4,
+	MODE_ODM_PRODUCTION_OPEN = 5,
+};
+
+/**
+ * Initializes fuse hardware
+ */
+void tegra_fuse_init(void);
+
 /**
  * Calculate SoC UID
  *
@@ -26,4 +40,11 @@ struct fuse_regs {
  */
 unsigned long long tegra_chip_uid(void);
 
+/**
+ * Gives the current operating mode from fuses
+ *
+ * @return current operating mode
+ */
+enum fuse_operating_mode tegra_fuse_get_operation_mode(void);
+
 #endif	/* ifndef _FUSE_H_ */
diff --git a/arch/arm/include/asm/arch-tegra/warmboot.h b/arch/arm/include/asm/arch-tegra/warmboot.h
index 9a53456370f..402f93aac48 100644
--- a/arch/arm/include/asm/arch-tegra/warmboot.h
+++ b/arch/arm/include/asm/arch-tegra/warmboot.h
@@ -10,12 +10,6 @@
 #define STRAP_OPT_A_RAM_CODE_SHIFT	4
 #define STRAP_OPT_A_RAM_CODE_MASK	(0xf << STRAP_OPT_A_RAM_CODE_SHIFT)
 
-/* Defines the supported operating modes */
-enum fuse_operating_mode {
-	MODE_PRODUCTION = 3,
-	MODE_UNDEFINED,
-};
-
 /* Defines the CMAC-AES-128 hash length in 32 bit words. (128 bits = 4 words) */
 enum {
 	HASH_LENGTH = 4
diff --git a/arch/arm/mach-tegra/ap.c b/arch/arm/mach-tegra/ap.c
index f35bdba4d48..a7938ed7910 100644
--- a/arch/arm/mach-tegra/ap.c
+++ b/arch/arm/mach-tegra/ap.c
@@ -37,6 +37,14 @@ int tegra_get_chip(void)
 	return rev;
 }
 
+u32 tegra_get_major_version(void)
+{
+	struct apb_misc_gp_ctlr *gp =
+		(struct apb_misc_gp_ctlr *)NV_PA_APB_MISC_GP_BASE;
+
+	return (readl(&gp->hidrev) & HIDREV_MAJORPREV_MASK) >> HIDREV_MAJORPREV_SHIFT;
+}
+
 int tegra_get_sku_info(void)
 {
 	int sku_id;
diff --git a/arch/arm/mach-tegra/cpu.h b/arch/arm/mach-tegra/cpu.h
index 006aae3d070..5477423f4d0 100644
--- a/arch/arm/mach-tegra/cpu.h
+++ b/arch/arm/mach-tegra/cpu.h
@@ -71,6 +71,7 @@ void powerup_cpu(void);
 void reset_A9_cpu(int reset);
 void start_cpu(u32 reset_vector);
 int tegra_get_chip(void);
+u32 tegra_get_major_version(void);
 int tegra_get_sku_info(void);
 int tegra_get_chip_sku(void);
 void adjust_pllp_out_freqs(void);
diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c
index e9b5259ac70..abdf6504161 100644
--- a/arch/arm/mach-tegra/fuse.c
+++ b/arch/arm/mach-tegra/fuse.c
@@ -39,7 +39,7 @@ static u32 tegra_fuse_readl(unsigned long offset)
 	return readl(NV_PA_FUSE_BASE + offset);
 }
 
-static void tegra_fuse_init(void)
+void tegra_fuse_init(void)
 {
 	u32 reg;
 
@@ -49,8 +49,11 @@ static void tegra_fuse_init(void)
 	 * this bit fuse region will not work.
 	 */
 	reg = readl_relaxed(NV_PA_CLK_RST_BASE + 0x48);
-	reg |= BIT(28);
-	writel(reg, NV_PA_CLK_RST_BASE + 0x48);
+
+	if (reg & BIT(28))
+		return;
+
+	writel(reg | BIT(28), NV_PA_CLK_RST_BASE + 0x48);
 
 	clock_enable(PERIPH_ID_FUSE);
 	udelay(2);
@@ -148,3 +151,57 @@ unsigned long long tegra_chip_uid(void)
 
 	return uid;
 }
+
+static int tegra_is_production_mode_fuse_set(struct fuse_regs *fuse)
+{
+	return readl(&fuse->production_mode);
+}
+
+static int tegra_is_odm_production_mode_fuse_set(struct fuse_regs *fuse)
+{
+	return readl(&fuse->security_mode);
+}
+
+static int tegra_is_failure_analysis_mode(struct fuse_regs *fuse)
+{
+	return readl(&fuse->fa);
+}
+
+static int tegra_is_sbk_zeroes(struct fuse_regs *fuse)
+{
+	int i;
+
+	for (i = 0; i < 4; i++)
+		if (readl(&fuse->sbk[i]))
+			return 0;
+
+	return 1;
+}
+
+static int tegra_is_production_mode(struct fuse_regs *fuse)
+{
+	if (!tegra_get_major_version())
+		return 1;
+
+	return !tegra_is_failure_analysis_mode(fuse) &&
+	       tegra_is_production_mode_fuse_set(fuse);
+}
+
+enum fuse_operating_mode tegra_fuse_get_operation_mode(void)
+{
+	struct fuse_regs *fuse = (struct fuse_regs *)NV_PA_FUSE_BASE;
+
+	tegra_fuse_init();
+
+	if (tegra_is_production_mode(fuse)) {
+		if (!tegra_is_odm_production_mode_fuse_set(fuse))
+			return MODE_PRODUCTION;
+		else
+			if (tegra_is_sbk_zeroes(fuse))
+				return MODE_ODM_PRODUCTION_OPEN;
+			else
+				return MODE_ODM_PRODUCTION_SECURE;
+	}
+
+	return MODE_UNDEFINED;
+}
diff --git a/arch/arm/mach-tegra/tegra20/warmboot.c b/arch/arm/mach-tegra/tegra20/warmboot.c
index 18034c83a1c..059388f7231 100644
--- a/arch/arm/mach-tegra/tegra20/warmboot.c
+++ b/arch/arm/mach-tegra/tegra20/warmboot.c
@@ -182,83 +182,10 @@ int warmboot_save_sdram_params(void)
 	return 0;
 }
 
-static u32 get_major_version(void)
-{
-	u32 major_id;
-	struct apb_misc_gp_ctlr *gp =
-		(struct apb_misc_gp_ctlr *)NV_PA_APB_MISC_GP_BASE;
-
-	major_id = (readl(&gp->hidrev) & HIDREV_MAJORPREV_MASK) >>
-			HIDREV_MAJORPREV_SHIFT;
-	return major_id;
-}
-
-static int is_production_mode_fuse_set(struct fuse_regs *fuse)
-{
-	return readl(&fuse->production_mode);
-}
-
-static int is_odm_production_mode_fuse_set(struct fuse_regs *fuse)
-{
-	return readl(&fuse->security_mode);
-}
-
-static int is_failure_analysis_mode(struct fuse_regs *fuse)
-{
-	return readl(&fuse->fa);
-}
-
-static int ap20_is_odm_production_mode(void)
-{
-	struct fuse_regs *fuse = (struct fuse_regs *)NV_PA_FUSE_BASE;
-
-	if (!is_failure_analysis_mode(fuse) &&
-	    is_odm_production_mode_fuse_set(fuse))
-		return 1;
-	else
-		return 0;
-}
-
-static int ap20_is_production_mode(void)
-{
-	struct fuse_regs *fuse = (struct fuse_regs *)NV_PA_FUSE_BASE;
-
-	if (get_major_version() == 0)
-		return 1;
-
-	if (!is_failure_analysis_mode(fuse) &&
-	    is_production_mode_fuse_set(fuse) &&
-	    !is_odm_production_mode_fuse_set(fuse))
-		return 1;
-	else
-		return 0;
-}
-
-static enum fuse_operating_mode fuse_get_operation_mode(void)
-{
-	u32 chip_id;
-	struct apb_misc_gp_ctlr *gp =
-		(struct apb_misc_gp_ctlr *)NV_PA_APB_MISC_GP_BASE;
-
-	chip_id = (readl(&gp->hidrev) & HIDREV_CHIPID_MASK) >>
-			HIDREV_CHIPID_SHIFT;
-	if (chip_id == CHIPID_TEGRA20) {
-		if (ap20_is_odm_production_mode()) {
-			printf("!! odm_production_mode is not supported !!\n");
-			return MODE_UNDEFINED;
-		} else
-			if (ap20_is_production_mode())
-				return MODE_PRODUCTION;
-			else
-				return MODE_UNDEFINED;
-	}
-	return MODE_UNDEFINED;
-}
-
 static void determine_crypto_options(int *is_encrypted, int *is_signed,
 				     int *use_zero_key)
 {
-	switch (fuse_get_operation_mode()) {
+	switch (tegra_fuse_get_operation_mode()) {
 	case MODE_PRODUCTION:
 		*is_encrypted = 0;
 		*is_signed = 1;
-- 
2.48.1



More information about the U-Boot mailing list