From: Ion Agorria Date: Thu, 26 Dec 2024 09:52:04 +0000 (+0100) Subject: ARM: tegra: Relocate fuse code from warmboot file X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=aaf4c26187907043d4f14a414df882c0acd16a13;p=thirdparty%2Fu-boot.git ARM: tegra: Relocate fuse code from warmboot file Move a set of helpers used in warmboot code to more appropriate AP and FUSE locations. Signed-off-by: Ion Agorria --- 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;