From b625fd324eb1532965f51a2b8482125e85cac813 Mon Sep 17 00:00:00 2001 From: hexkyz Date: Fri, 13 Nov 2020 17:46:25 +0000 Subject: [PATCH] fusee/sept: update fuse driver code --- fusee/fusee-mtc/src/fuse.c | 126 +++++++++++++------- fusee/fusee-mtc/src/fuse.h | 7 +- fusee/fusee-primary/src/fuse.c | 126 +++++++++++++------- fusee/fusee-primary/src/fuse.h | 7 +- fusee/fusee-secondary/src/fuse.c | 121 ++++++++++++------- fusee/fusee-secondary/src/fuse.h | 8 +- fusee/fusee-secondary/src/key_derivation.c | 6 +- fusee/fusee-secondary/src/nxboot.c | 14 +-- sept/sept-primary/src/fuse.c | 130 ++++++++++++++------- sept/sept-primary/src/fuse.h | 7 +- sept/sept-secondary/src/fuse.c | 126 +++++++++++++------- sept/sept-secondary/src/fuse.h | 7 +- 12 files changed, 466 insertions(+), 219 deletions(-) diff --git a/fusee/fusee-mtc/src/fuse.c b/fusee/fusee-mtc/src/fuse.c index 8ef10e11b..1b49f30d5 100644 --- a/fusee/fusee-mtc/src/fuse.c +++ b/fusee/fusee-mtc/src/fuse.c @@ -24,11 +24,6 @@ #include "pmc.h" #include "timers.h" -/* Prototypes for internal commands. */ -void fuse_enable_power(void); -void fuse_disable_power(void); -void fuse_wait_idle(void); - /* Initialize the fuse driver */ void fuse_init(void) { /* Make all fuse registers visible, disable the private key and disable programming. */ @@ -43,7 +38,7 @@ void fuse_disable_private_key(void) { fuse->FUSE_PRIVATEKEYDISABLE = 0x10; } -/* Disables all fuse programming. */ +/* Disable all fuse programming. */ void fuse_disable_programming(void) { volatile tegra_fuse_t *fuse = fuse_get_regs(); fuse->FUSE_DISABLEREGPROGRAM = 1; @@ -68,7 +63,7 @@ void fuse_disable_power(void) { } /* Wait for the fuse driver to go idle. */ -void fuse_wait_idle(void) { +static void fuse_wait_idle(void) { volatile tegra_fuse_t *fuse = fuse_get_regs(); uint32_t ctrl_val = 0; @@ -120,7 +115,7 @@ void fuse_hw_write(uint32_t value, uint32_t addr) { fuse_wait_idle(); } -/* Sense the fuse hardware array into the shadow cache. */ +/* Sense the fuse hardware array into the fuse cache. */ void fuse_hw_sense(void) { volatile tegra_fuse_t *fuse = fuse_get_regs(); @@ -137,19 +132,19 @@ void fuse_hw_sense(void) { fuse_wait_idle(); } -/* Read the SKU info register from the shadow cache. */ +/* Read the SKU info register. */ uint32_t fuse_get_sku_info(void) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); return fuse_chip->FUSE_SKU_INFO; } -/* Read the bootrom patch version from a register in the shadow cache. */ +/* Read the bootrom patch version. */ uint32_t fuse_get_bootrom_patch_version(void) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); return fuse_chip->FUSE_SOC_SPEEDO_1_CALIB; } -/* Read a spare bit register from the shadow cache */ +/* Read a spare bit register. */ uint32_t fuse_get_spare_bit(uint32_t idx) { if (idx < 32) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); @@ -159,7 +154,7 @@ uint32_t fuse_get_spare_bit(uint32_t idx) { } } -/* Read a reserved ODM register from the shadow cache. */ +/* Read a reserved ODM register. */ uint32_t fuse_get_reserved_odm(uint32_t idx) { if (idx < 8) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); @@ -169,12 +164,12 @@ uint32_t fuse_get_reserved_odm(uint32_t idx) { } } -/* Get the DRAM ID using values in the shadow cache. */ +/* Get the DramId. */ uint32_t fuse_get_dram_id(void) { return ((fuse_get_reserved_odm(4) >> 3) & 0x7); } -/* Derive the Device ID using values in the shadow cache. */ +/* Derive the DeviceId. */ uint64_t fuse_get_device_id(void) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); @@ -200,46 +195,72 @@ uint64_t fuse_get_device_id(void) { return device_id; } -/* Derive the Hardware Type using values in the shadow cache. */ -uint32_t fuse_get_hardware_type(uint32_t target_firmware) { +/* Derive the HardwareType with firmware specific checks. */ +uint32_t fuse_get_hardware_type_with_firmware_check(uint32_t target_firmware) { uint32_t fuse_reserved_odm4 = fuse_get_reserved_odm(4); uint32_t hardware_type = (((fuse_reserved_odm4 >> 7) & 2) | ((fuse_reserved_odm4 >> 2) & 1)); - /* Firmware from versions 1.0.0 to 3.0.2. */ if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); - if (hardware_type >= 1) { - return (hardware_type > 2) ? 3 : hardware_type - 1; - } else if ((fuse_chip->FUSE_SPARE_BIT[9] & 1) == 0) { - return 0; - } else { - return 3; + uint32_t fuse_spare_bit9 = (fuse_chip->FUSE_SPARE_BIT[9] & 1); + + switch (hardware_type) { + case 0x00: return (fuse_spare_bit9 == 0) ? 0 : 3; + case 0x01: return 0; /* HardwareType_Icosa */ + case 0x02: return 1; /* HardwareType_Copper */ + default: return 3; /* HardwareType_Undefined */ } - } else if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) { /* Firmware versions from 4.0.0 to 6.2.0. */ - static const uint32_t types[] = {0,1,4,3}; + } else { hardware_type |= ((fuse_reserved_odm4 >> 14) & 0x3C); - hardware_type--; - return (hardware_type > 3) ? 4 : types[hardware_type]; - } else { /* Firmware versions from 7.0.0 onwards. */ - /* Always return 0 in retail. */ - return 0; + + if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) { + switch (hardware_type) { + case 0x01: return 0; /* HardwareType_Icosa */ + case 0x02: return 1; /* HardwareType_Copper */ + case 0x04: return 3; /* HardwareType_Iowa */ + default: return 4; /* HardwareType_Undefined */ + } + } else { + if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_10_0_0) { + switch (hardware_type) { + case 0x01: return 0; /* HardwareType_Icosa */ + case 0x02: return 4; /* HardwareType_Calcio */ + case 0x04: return 3; /* HardwareType_Iowa */ + case 0x08: return 2; /* HardwareType_Hoag */ + default: return 0xF; /* HardwareType_Undefined */ + } + } else { + switch (hardware_type) { + case 0x01: return 0; /* HardwareType_Icosa */ + case 0x02: return 4; /* HardwareType_Calcio */ + case 0x04: return 3; /* HardwareType_Iowa */ + case 0x08: return 2; /* HardwareType_Hoag */ + case 0x10: return 5; /* HardwareType_Five */ + default: return 0xF; /* HardwareType_Undefined */ + } + } + } } } -/* Derive the Retail Type using values in the shadow cache. */ -uint32_t fuse_get_retail_type(void) { - /* Retail Type = IS_RETAIL | UNIT_TYPE. */ +/* Derive the HardwareType. */ +uint32_t fuse_get_hardware_type(void) { + return fuse_get_hardware_type_with_firmware_check(ATMOSPHERE_TARGET_FIRMWARE_CURRENT); +} + +/* Derive the HardwareState. */ +uint32_t fuse_get_hardware_state(void) { uint32_t fuse_reserved_odm4 = fuse_get_reserved_odm(4); - uint32_t retail_type = (((fuse_reserved_odm4 >> 7) & 4) | (fuse_reserved_odm4 & 3)); - if (retail_type == 4) { /* Standard retail unit, IS_RETAIL | 0. */ - return 1; - } else if (retail_type == 3) { /* Standard dev unit, 0 | DEV_UNIT. */ - return 0; + uint32_t hardware_state = (((fuse_reserved_odm4 >> 7) & 4) | (fuse_reserved_odm4 & 3)); + + switch (hardware_state) { + case 0x03: return 0; /* HardwareState_Development */ + case 0x04: return 1; /* HardwareState_Production */ + default: return 2; /* HardwareState_Undefined */ } - return 2; /* IS_RETAIL | DEV_UNIT */ } -/* Derive the 16-byte Hardware Info using values in the shadow cache, and copy to output buffer. */ +/* Derive the 16-byte HardwareInfo and copy to output buffer. */ void fuse_get_hardware_info(void *dst) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); uint32_t hw_info[0x4]; @@ -261,3 +282,28 @@ void fuse_get_hardware_info(void *dst) { memcpy(dst, hw_info, 0x10); } + +/* Get the DeviceUniqueKeyGeneration. */ +uint32_t fuse_get_device_unique_key_generation(void) { + if ((fuse_get_reserved_odm(4) & 0x800) && (fuse_get_reserved_odm(0) == 0x8E61ECAE) && (fuse_get_reserved_odm(1) == 0xF2BA3BB2)) { + return (fuse_get_reserved_odm(2) & 0x1F); + } else { + return 0; + } +} + +/* Get the SocType from the HardwareType. */ +uint32_t fuse_get_soc_type(void) { + switch (fuse_get_hardware_type()) { + case 0: + case 1: + return 0; /* SocType_Erista */ + case 3: + case 2: + case 4: + case 5: + return 1; /* SocType_Mariko */ + default: + return 0xF; /* SocType_Undefined */ + } +} diff --git a/fusee/fusee-mtc/src/fuse.h b/fusee/fusee-mtc/src/fuse.h index 0e15cbe63..8bfec2b25 100644 --- a/fusee/fusee-mtc/src/fuse.h +++ b/fusee/fusee-mtc/src/fuse.h @@ -209,6 +209,8 @@ static inline volatile tegra_fuse_chip_t *fuse_chip_get_regs(void) void fuse_init(void); void fuse_disable_programming(void); void fuse_disable_private_key(void); +void fuse_enable_power(void); +void fuse_disable_power(void); uint32_t fuse_get_sku_info(void); uint32_t fuse_get_spare_bit(uint32_t idx); @@ -216,9 +218,12 @@ uint32_t fuse_get_reserved_odm(uint32_t idx); uint32_t fuse_get_bootrom_patch_version(void); uint64_t fuse_get_device_id(void); uint32_t fuse_get_dram_id(void); -uint32_t fuse_get_hardware_type(uint32_t target_firmware); +uint32_t fuse_get_hardware_type_with_firmware_check(uint32_t target_firmware); +uint32_t fuse_get_hardware_type(void); uint32_t fuse_get_retail_type(void); void fuse_get_hardware_info(void *dst); +uint32_t fuse_get_device_unique_key_generation(void); +uint32_t fuse_get_soc_type(void); uint32_t fuse_hw_read(uint32_t addr); void fuse_hw_write(uint32_t value, uint32_t addr); diff --git a/fusee/fusee-primary/src/fuse.c b/fusee/fusee-primary/src/fuse.c index 8ef10e11b..1b49f30d5 100644 --- a/fusee/fusee-primary/src/fuse.c +++ b/fusee/fusee-primary/src/fuse.c @@ -24,11 +24,6 @@ #include "pmc.h" #include "timers.h" -/* Prototypes for internal commands. */ -void fuse_enable_power(void); -void fuse_disable_power(void); -void fuse_wait_idle(void); - /* Initialize the fuse driver */ void fuse_init(void) { /* Make all fuse registers visible, disable the private key and disable programming. */ @@ -43,7 +38,7 @@ void fuse_disable_private_key(void) { fuse->FUSE_PRIVATEKEYDISABLE = 0x10; } -/* Disables all fuse programming. */ +/* Disable all fuse programming. */ void fuse_disable_programming(void) { volatile tegra_fuse_t *fuse = fuse_get_regs(); fuse->FUSE_DISABLEREGPROGRAM = 1; @@ -68,7 +63,7 @@ void fuse_disable_power(void) { } /* Wait for the fuse driver to go idle. */ -void fuse_wait_idle(void) { +static void fuse_wait_idle(void) { volatile tegra_fuse_t *fuse = fuse_get_regs(); uint32_t ctrl_val = 0; @@ -120,7 +115,7 @@ void fuse_hw_write(uint32_t value, uint32_t addr) { fuse_wait_idle(); } -/* Sense the fuse hardware array into the shadow cache. */ +/* Sense the fuse hardware array into the fuse cache. */ void fuse_hw_sense(void) { volatile tegra_fuse_t *fuse = fuse_get_regs(); @@ -137,19 +132,19 @@ void fuse_hw_sense(void) { fuse_wait_idle(); } -/* Read the SKU info register from the shadow cache. */ +/* Read the SKU info register. */ uint32_t fuse_get_sku_info(void) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); return fuse_chip->FUSE_SKU_INFO; } -/* Read the bootrom patch version from a register in the shadow cache. */ +/* Read the bootrom patch version. */ uint32_t fuse_get_bootrom_patch_version(void) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); return fuse_chip->FUSE_SOC_SPEEDO_1_CALIB; } -/* Read a spare bit register from the shadow cache */ +/* Read a spare bit register. */ uint32_t fuse_get_spare_bit(uint32_t idx) { if (idx < 32) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); @@ -159,7 +154,7 @@ uint32_t fuse_get_spare_bit(uint32_t idx) { } } -/* Read a reserved ODM register from the shadow cache. */ +/* Read a reserved ODM register. */ uint32_t fuse_get_reserved_odm(uint32_t idx) { if (idx < 8) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); @@ -169,12 +164,12 @@ uint32_t fuse_get_reserved_odm(uint32_t idx) { } } -/* Get the DRAM ID using values in the shadow cache. */ +/* Get the DramId. */ uint32_t fuse_get_dram_id(void) { return ((fuse_get_reserved_odm(4) >> 3) & 0x7); } -/* Derive the Device ID using values in the shadow cache. */ +/* Derive the DeviceId. */ uint64_t fuse_get_device_id(void) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); @@ -200,46 +195,72 @@ uint64_t fuse_get_device_id(void) { return device_id; } -/* Derive the Hardware Type using values in the shadow cache. */ -uint32_t fuse_get_hardware_type(uint32_t target_firmware) { +/* Derive the HardwareType with firmware specific checks. */ +uint32_t fuse_get_hardware_type_with_firmware_check(uint32_t target_firmware) { uint32_t fuse_reserved_odm4 = fuse_get_reserved_odm(4); uint32_t hardware_type = (((fuse_reserved_odm4 >> 7) & 2) | ((fuse_reserved_odm4 >> 2) & 1)); - /* Firmware from versions 1.0.0 to 3.0.2. */ if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); - if (hardware_type >= 1) { - return (hardware_type > 2) ? 3 : hardware_type - 1; - } else if ((fuse_chip->FUSE_SPARE_BIT[9] & 1) == 0) { - return 0; - } else { - return 3; + uint32_t fuse_spare_bit9 = (fuse_chip->FUSE_SPARE_BIT[9] & 1); + + switch (hardware_type) { + case 0x00: return (fuse_spare_bit9 == 0) ? 0 : 3; + case 0x01: return 0; /* HardwareType_Icosa */ + case 0x02: return 1; /* HardwareType_Copper */ + default: return 3; /* HardwareType_Undefined */ } - } else if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) { /* Firmware versions from 4.0.0 to 6.2.0. */ - static const uint32_t types[] = {0,1,4,3}; + } else { hardware_type |= ((fuse_reserved_odm4 >> 14) & 0x3C); - hardware_type--; - return (hardware_type > 3) ? 4 : types[hardware_type]; - } else { /* Firmware versions from 7.0.0 onwards. */ - /* Always return 0 in retail. */ - return 0; + + if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) { + switch (hardware_type) { + case 0x01: return 0; /* HardwareType_Icosa */ + case 0x02: return 1; /* HardwareType_Copper */ + case 0x04: return 3; /* HardwareType_Iowa */ + default: return 4; /* HardwareType_Undefined */ + } + } else { + if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_10_0_0) { + switch (hardware_type) { + case 0x01: return 0; /* HardwareType_Icosa */ + case 0x02: return 4; /* HardwareType_Calcio */ + case 0x04: return 3; /* HardwareType_Iowa */ + case 0x08: return 2; /* HardwareType_Hoag */ + default: return 0xF; /* HardwareType_Undefined */ + } + } else { + switch (hardware_type) { + case 0x01: return 0; /* HardwareType_Icosa */ + case 0x02: return 4; /* HardwareType_Calcio */ + case 0x04: return 3; /* HardwareType_Iowa */ + case 0x08: return 2; /* HardwareType_Hoag */ + case 0x10: return 5; /* HardwareType_Five */ + default: return 0xF; /* HardwareType_Undefined */ + } + } + } } } -/* Derive the Retail Type using values in the shadow cache. */ -uint32_t fuse_get_retail_type(void) { - /* Retail Type = IS_RETAIL | UNIT_TYPE. */ +/* Derive the HardwareType. */ +uint32_t fuse_get_hardware_type(void) { + return fuse_get_hardware_type_with_firmware_check(ATMOSPHERE_TARGET_FIRMWARE_CURRENT); +} + +/* Derive the HardwareState. */ +uint32_t fuse_get_hardware_state(void) { uint32_t fuse_reserved_odm4 = fuse_get_reserved_odm(4); - uint32_t retail_type = (((fuse_reserved_odm4 >> 7) & 4) | (fuse_reserved_odm4 & 3)); - if (retail_type == 4) { /* Standard retail unit, IS_RETAIL | 0. */ - return 1; - } else if (retail_type == 3) { /* Standard dev unit, 0 | DEV_UNIT. */ - return 0; + uint32_t hardware_state = (((fuse_reserved_odm4 >> 7) & 4) | (fuse_reserved_odm4 & 3)); + + switch (hardware_state) { + case 0x03: return 0; /* HardwareState_Development */ + case 0x04: return 1; /* HardwareState_Production */ + default: return 2; /* HardwareState_Undefined */ } - return 2; /* IS_RETAIL | DEV_UNIT */ } -/* Derive the 16-byte Hardware Info using values in the shadow cache, and copy to output buffer. */ +/* Derive the 16-byte HardwareInfo and copy to output buffer. */ void fuse_get_hardware_info(void *dst) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); uint32_t hw_info[0x4]; @@ -261,3 +282,28 @@ void fuse_get_hardware_info(void *dst) { memcpy(dst, hw_info, 0x10); } + +/* Get the DeviceUniqueKeyGeneration. */ +uint32_t fuse_get_device_unique_key_generation(void) { + if ((fuse_get_reserved_odm(4) & 0x800) && (fuse_get_reserved_odm(0) == 0x8E61ECAE) && (fuse_get_reserved_odm(1) == 0xF2BA3BB2)) { + return (fuse_get_reserved_odm(2) & 0x1F); + } else { + return 0; + } +} + +/* Get the SocType from the HardwareType. */ +uint32_t fuse_get_soc_type(void) { + switch (fuse_get_hardware_type()) { + case 0: + case 1: + return 0; /* SocType_Erista */ + case 3: + case 2: + case 4: + case 5: + return 1; /* SocType_Mariko */ + default: + return 0xF; /* SocType_Undefined */ + } +} diff --git a/fusee/fusee-primary/src/fuse.h b/fusee/fusee-primary/src/fuse.h index 0e15cbe63..8bfec2b25 100644 --- a/fusee/fusee-primary/src/fuse.h +++ b/fusee/fusee-primary/src/fuse.h @@ -209,6 +209,8 @@ static inline volatile tegra_fuse_chip_t *fuse_chip_get_regs(void) void fuse_init(void); void fuse_disable_programming(void); void fuse_disable_private_key(void); +void fuse_enable_power(void); +void fuse_disable_power(void); uint32_t fuse_get_sku_info(void); uint32_t fuse_get_spare_bit(uint32_t idx); @@ -216,9 +218,12 @@ uint32_t fuse_get_reserved_odm(uint32_t idx); uint32_t fuse_get_bootrom_patch_version(void); uint64_t fuse_get_device_id(void); uint32_t fuse_get_dram_id(void); -uint32_t fuse_get_hardware_type(uint32_t target_firmware); +uint32_t fuse_get_hardware_type_with_firmware_check(uint32_t target_firmware); +uint32_t fuse_get_hardware_type(void); uint32_t fuse_get_retail_type(void); void fuse_get_hardware_info(void *dst); +uint32_t fuse_get_device_unique_key_generation(void); +uint32_t fuse_get_soc_type(void); uint32_t fuse_hw_read(uint32_t addr); void fuse_hw_write(uint32_t value, uint32_t addr); diff --git a/fusee/fusee-secondary/src/fuse.c b/fusee/fusee-secondary/src/fuse.c index 3236a3955..1b49f30d5 100644 --- a/fusee/fusee-secondary/src/fuse.c +++ b/fusee/fusee-secondary/src/fuse.c @@ -24,11 +24,6 @@ #include "pmc.h" #include "timers.h" -/* Prototypes for internal commands. */ -void fuse_enable_power(void); -void fuse_disable_power(void); -void fuse_wait_idle(void); - /* Initialize the fuse driver */ void fuse_init(void) { /* Make all fuse registers visible, disable the private key and disable programming. */ @@ -43,7 +38,7 @@ void fuse_disable_private_key(void) { fuse->FUSE_PRIVATEKEYDISABLE = 0x10; } -/* Disables all fuse programming. */ +/* Disable all fuse programming. */ void fuse_disable_programming(void) { volatile tegra_fuse_t *fuse = fuse_get_regs(); fuse->FUSE_DISABLEREGPROGRAM = 1; @@ -68,7 +63,7 @@ void fuse_disable_power(void) { } /* Wait for the fuse driver to go idle. */ -void fuse_wait_idle(void) { +static void fuse_wait_idle(void) { volatile tegra_fuse_t *fuse = fuse_get_regs(); uint32_t ctrl_val = 0; @@ -120,7 +115,7 @@ void fuse_hw_write(uint32_t value, uint32_t addr) { fuse_wait_idle(); } -/* Sense the fuse hardware array into the shadow cache. */ +/* Sense the fuse hardware array into the fuse cache. */ void fuse_hw_sense(void) { volatile tegra_fuse_t *fuse = fuse_get_regs(); @@ -137,19 +132,19 @@ void fuse_hw_sense(void) { fuse_wait_idle(); } -/* Read the SKU info register from the shadow cache. */ +/* Read the SKU info register. */ uint32_t fuse_get_sku_info(void) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); return fuse_chip->FUSE_SKU_INFO; } -/* Read the bootrom patch version from a register in the shadow cache. */ +/* Read the bootrom patch version. */ uint32_t fuse_get_bootrom_patch_version(void) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); return fuse_chip->FUSE_SOC_SPEEDO_1_CALIB; } -/* Read a spare bit register from the shadow cache */ +/* Read a spare bit register. */ uint32_t fuse_get_spare_bit(uint32_t idx) { if (idx < 32) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); @@ -159,7 +154,7 @@ uint32_t fuse_get_spare_bit(uint32_t idx) { } } -/* Read a reserved ODM register from the shadow cache. */ +/* Read a reserved ODM register. */ uint32_t fuse_get_reserved_odm(uint32_t idx) { if (idx < 8) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); @@ -169,12 +164,12 @@ uint32_t fuse_get_reserved_odm(uint32_t idx) { } } -/* Get the DRAM ID using values in the shadow cache. */ +/* Get the DramId. */ uint32_t fuse_get_dram_id(void) { return ((fuse_get_reserved_odm(4) >> 3) & 0x7); } -/* Derive the Device ID using values in the shadow cache. */ +/* Derive the DeviceId. */ uint64_t fuse_get_device_id(void) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); @@ -200,46 +195,72 @@ uint64_t fuse_get_device_id(void) { return device_id; } -/* Derive the Hardware Type using values in the shadow cache. */ -uint32_t fuse_get_hardware_type(uint32_t target_firmware) { +/* Derive the HardwareType with firmware specific checks. */ +uint32_t fuse_get_hardware_type_with_firmware_check(uint32_t target_firmware) { uint32_t fuse_reserved_odm4 = fuse_get_reserved_odm(4); uint32_t hardware_type = (((fuse_reserved_odm4 >> 7) & 2) | ((fuse_reserved_odm4 >> 2) & 1)); - /* Firmware from versions 1.0.0 to 3.0.2. */ if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); - if (hardware_type >= 1) { - return (hardware_type > 2) ? 3 : hardware_type - 1; - } else if ((fuse_chip->FUSE_SPARE_BIT[9] & 1) == 0) { - return 0; - } else { - return 3; + uint32_t fuse_spare_bit9 = (fuse_chip->FUSE_SPARE_BIT[9] & 1); + + switch (hardware_type) { + case 0x00: return (fuse_spare_bit9 == 0) ? 0 : 3; + case 0x01: return 0; /* HardwareType_Icosa */ + case 0x02: return 1; /* HardwareType_Copper */ + default: return 3; /* HardwareType_Undefined */ } - } else if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) { /* Firmware versions from 4.0.0 to 6.2.0. */ - static const uint32_t types[] = {0,1,4,3}; + } else { hardware_type |= ((fuse_reserved_odm4 >> 14) & 0x3C); - hardware_type--; - return (hardware_type > 3) ? 4 : types[hardware_type]; - } else { /* Firmware versions from 7.0.0 onwards. */ - /* Always return 0 in retail. */ - return 0; + + if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) { + switch (hardware_type) { + case 0x01: return 0; /* HardwareType_Icosa */ + case 0x02: return 1; /* HardwareType_Copper */ + case 0x04: return 3; /* HardwareType_Iowa */ + default: return 4; /* HardwareType_Undefined */ + } + } else { + if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_10_0_0) { + switch (hardware_type) { + case 0x01: return 0; /* HardwareType_Icosa */ + case 0x02: return 4; /* HardwareType_Calcio */ + case 0x04: return 3; /* HardwareType_Iowa */ + case 0x08: return 2; /* HardwareType_Hoag */ + default: return 0xF; /* HardwareType_Undefined */ + } + } else { + switch (hardware_type) { + case 0x01: return 0; /* HardwareType_Icosa */ + case 0x02: return 4; /* HardwareType_Calcio */ + case 0x04: return 3; /* HardwareType_Iowa */ + case 0x08: return 2; /* HardwareType_Hoag */ + case 0x10: return 5; /* HardwareType_Five */ + default: return 0xF; /* HardwareType_Undefined */ + } + } + } } } -/* Derive the Retail Type using values in the shadow cache. */ -uint32_t fuse_get_retail_type(void) { - /* Retail Type = IS_RETAIL | UNIT_TYPE. */ +/* Derive the HardwareType. */ +uint32_t fuse_get_hardware_type(void) { + return fuse_get_hardware_type_with_firmware_check(ATMOSPHERE_TARGET_FIRMWARE_CURRENT); +} + +/* Derive the HardwareState. */ +uint32_t fuse_get_hardware_state(void) { uint32_t fuse_reserved_odm4 = fuse_get_reserved_odm(4); - uint32_t retail_type = (((fuse_reserved_odm4 >> 7) & 4) | (fuse_reserved_odm4 & 3)); - if (retail_type == 4) { /* Standard retail unit, IS_RETAIL | 0. */ - return 1; - } else if (retail_type == 3) { /* Standard dev unit, 0 | DEV_UNIT. */ - return 0; + uint32_t hardware_state = (((fuse_reserved_odm4 >> 7) & 4) | (fuse_reserved_odm4 & 3)); + + switch (hardware_state) { + case 0x03: return 0; /* HardwareState_Development */ + case 0x04: return 1; /* HardwareState_Production */ + default: return 2; /* HardwareState_Undefined */ } - return 2; /* IS_RETAIL | DEV_UNIT */ } -/* Derive the 16-byte Hardware Info using values in the shadow cache, and copy to output buffer. */ +/* Derive the 16-byte HardwareInfo and copy to output buffer. */ void fuse_get_hardware_info(void *dst) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); uint32_t hw_info[0x4]; @@ -262,11 +283,27 @@ void fuse_get_hardware_info(void *dst) { memcpy(dst, hw_info, 0x10); } -/* Get the Key Generation value. */ -uint32_t fuse_get_5x_key_generation(void) { +/* Get the DeviceUniqueKeyGeneration. */ +uint32_t fuse_get_device_unique_key_generation(void) { if ((fuse_get_reserved_odm(4) & 0x800) && (fuse_get_reserved_odm(0) == 0x8E61ECAE) && (fuse_get_reserved_odm(1) == 0xF2BA3BB2)) { return (fuse_get_reserved_odm(2) & 0x1F); } else { return 0; } } + +/* Get the SocType from the HardwareType. */ +uint32_t fuse_get_soc_type(void) { + switch (fuse_get_hardware_type()) { + case 0: + case 1: + return 0; /* SocType_Erista */ + case 3: + case 2: + case 4: + case 5: + return 1; /* SocType_Mariko */ + default: + return 0xF; /* SocType_Undefined */ + } +} diff --git a/fusee/fusee-secondary/src/fuse.h b/fusee/fusee-secondary/src/fuse.h index 71a4f85aa..8bfec2b25 100644 --- a/fusee/fusee-secondary/src/fuse.h +++ b/fusee/fusee-secondary/src/fuse.h @@ -209,6 +209,8 @@ static inline volatile tegra_fuse_chip_t *fuse_chip_get_regs(void) void fuse_init(void); void fuse_disable_programming(void); void fuse_disable_private_key(void); +void fuse_enable_power(void); +void fuse_disable_power(void); uint32_t fuse_get_sku_info(void); uint32_t fuse_get_spare_bit(uint32_t idx); @@ -216,10 +218,12 @@ uint32_t fuse_get_reserved_odm(uint32_t idx); uint32_t fuse_get_bootrom_patch_version(void); uint64_t fuse_get_device_id(void); uint32_t fuse_get_dram_id(void); -uint32_t fuse_get_hardware_type(uint32_t target_firmware); +uint32_t fuse_get_hardware_type_with_firmware_check(uint32_t target_firmware); +uint32_t fuse_get_hardware_type(void); uint32_t fuse_get_retail_type(void); void fuse_get_hardware_info(void *dst); -uint32_t fuse_get_5x_key_generation(void); +uint32_t fuse_get_device_unique_key_generation(void); +uint32_t fuse_get_soc_type(void); uint32_t fuse_hw_read(uint32_t addr); void fuse_hw_write(uint32_t value, uint32_t addr); diff --git a/fusee/fusee-secondary/src/key_derivation.c b/fusee/fusee-secondary/src/key_derivation.c index 73a052bdf..91c566545 100644 --- a/fusee/fusee-secondary/src/key_derivation.c +++ b/fusee/fusee-secondary/src/key_derivation.c @@ -169,7 +169,7 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui if (memcmp(g_dec_keyblobs[desired_keyblob].master_kek, zeroes, 0x10) == 0) { /* Try reading the keys from a file. */ - const char *keyfile = fuse_get_retail_type() != 0 ? "atmosphere/prod.keys" : "atmosphere/dev.keys"; + const char *keyfile = fuse_get_hardware_state() != 0 ? "atmosphere/prod.keys" : "atmosphere/dev.keys"; FILE *extkey_file = fopen(keyfile, "r"); AL16 fusee_extkeys_t extkeys = {0}; if (extkey_file == NULL) { @@ -212,7 +212,7 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui decrypt_data_into_keyslot(0xD, 0xD, masterkey_seed, 0x10); /* Setup master key revision, derive older master keys for use. */ - return mkey_detect_revision(fuse_get_retail_type() != 0); + return mkey_detect_revision(fuse_get_hardware_state() != 0); } static void generate_specific_aes_key(void *dst, const void *wrapped_key, bool should_mask, uint32_t target_firmware, uint32_t generation) { @@ -273,7 +273,7 @@ void derive_bis_key(void *dst, BisPartition partition_id, uint32_t target_firmwa } }; - uint32_t bis_key_generation = fuse_get_5x_key_generation(); + uint32_t bis_key_generation = fuse_get_device_unique_key_generation(); if (bis_key_generation > 0) { bis_key_generation -= 1; } diff --git a/fusee/fusee-secondary/src/nxboot.c b/fusee/fusee-secondary/src/nxboot.c index ac33cdbec..953c77faa 100644 --- a/fusee/fusee-secondary/src/nxboot.c +++ b/fusee/fusee-secondary/src/nxboot.c @@ -794,7 +794,7 @@ uint32_t nxboot_main(void) { } if (tsec_fw_size == 0x3000) { - if (fuse_get_retail_type() != 0) { + if (fuse_get_hardware_state() != 0) { sept_secondary_enc = sept_secondary_00_enc; sept_secondary_enc_size = sept_secondary_00_enc_size; } else { @@ -802,7 +802,7 @@ uint32_t nxboot_main(void) { sept_secondary_enc_size = sept_secondary_dev_00_enc_size; } } else if (tsec_fw_size == 0x3300) { - if (fuse_get_retail_type() != 0) { + if (fuse_get_hardware_state() != 0) { sept_secondary_enc = sept_secondary_01_enc; sept_secondary_enc_size = sept_secondary_01_enc_size; } else { @@ -817,7 +817,7 @@ uint32_t nxboot_main(void) { fatal_error("[NXBOOT] Failed to read the TSEC firmware from Package1loader!\n"); } if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_8_1_0) { - if (fuse_get_retail_type() != 0) { + if (fuse_get_hardware_state() != 0) { sept_secondary_enc = sept_secondary_01_enc; sept_secondary_enc_size = sept_secondary_01_enc_size; } else { @@ -826,7 +826,7 @@ uint32_t nxboot_main(void) { } tsec_fw_size = 0x3300; } else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_7_0_0) { - if (fuse_get_retail_type() != 0) { + if (fuse_get_hardware_state() != 0) { sept_secondary_enc = sept_secondary_00_enc; sept_secondary_enc_size = sept_secondary_00_enc_size; } else { @@ -851,7 +851,7 @@ uint32_t nxboot_main(void) { if (!get_and_clear_has_run_sept()) { reboot_to_sept(tsec_fw, tsec_fw_size, sept_secondary_enc, sept_secondary_enc_size); } else { - if (mkey_detect_revision(fuse_get_retail_type() != 0) != 0) { + if (mkey_detect_revision(fuse_get_hardware_state() != 0) != 0) { fatal_error("[NXBOOT] Sept derived incorrect keys!\n"); } } @@ -885,7 +885,7 @@ uint32_t nxboot_main(void) { /* Derive new device keys. */ { - derive_new_device_keys(fuse_get_retail_type() != 0, KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY, target_firmware); + derive_new_device_keys(fuse_get_hardware_state() != 0, KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY, target_firmware); } /* Set the system partition's keys. */ @@ -957,7 +957,7 @@ uint32_t nxboot_main(void) { ams_header->ams_metadata.target_firmware = target_firmware; /* Set RSA modulus */ - const uint8_t *pkc_modulus = fuse_get_retail_type() != 0 ? retail_pkc_modulus : dev_pkc_modulus; + const uint8_t *pkc_modulus = fuse_get_hardware_state() != 0 ? retail_pkc_modulus : dev_pkc_modulus; memcpy(ams_header->rsa_modulus, pkc_modulus, sizeof(ams_header->rsa_modulus)); } } diff --git a/sept/sept-primary/src/fuse.c b/sept/sept-primary/src/fuse.c index 3a1eecd99..5edbbbc7f 100644 --- a/sept/sept-primary/src/fuse.c +++ b/sept/sept-primary/src/fuse.c @@ -24,15 +24,12 @@ #include "pmc.h" #include "timers.h" -/* Prototypes for internal commands. */ -void fuse_enable_power(void); -void fuse_disable_power(void); -void fuse_wait_idle(void); - /* Initialize the fuse driver */ void fuse_init(void) { - /* Make all fuse registers visible. */ + /* Make all fuse registers visible, disable the private key and disable programming. */ clkrst_enable_fuse_regs(true); + /* fuse_disable_private_key(); */ + /* fuse_disable_programming(); */ } /* Disable access to the private key and set the TZ sticky bit. */ @@ -41,7 +38,7 @@ void fuse_disable_private_key(void) { fuse->FUSE_PRIVATEKEYDISABLE = 0x10; } -/* Disables all fuse programming. */ +/* Disable all fuse programming. */ void fuse_disable_programming(void) { volatile tegra_fuse_t *fuse = fuse_get_regs(); fuse->FUSE_DISABLEREGPROGRAM = 1; @@ -66,7 +63,7 @@ void fuse_disable_power(void) { } /* Wait for the fuse driver to go idle. */ -void fuse_wait_idle(void) { +static void fuse_wait_idle(void) { volatile tegra_fuse_t *fuse = fuse_get_regs(); uint32_t ctrl_val = 0; @@ -118,7 +115,7 @@ void fuse_hw_write(uint32_t value, uint32_t addr) { fuse_wait_idle(); } -/* Sense the fuse hardware array into the shadow cache. */ +/* Sense the fuse hardware array into the fuse cache. */ void fuse_hw_sense(void) { volatile tegra_fuse_t *fuse = fuse_get_regs(); @@ -135,19 +132,19 @@ void fuse_hw_sense(void) { fuse_wait_idle(); } -/* Read the SKU info register from the shadow cache. */ +/* Read the SKU info register. */ uint32_t fuse_get_sku_info(void) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); return fuse_chip->FUSE_SKU_INFO; } -/* Read the bootrom patch version from a register in the shadow cache. */ +/* Read the bootrom patch version. */ uint32_t fuse_get_bootrom_patch_version(void) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); return fuse_chip->FUSE_SOC_SPEEDO_1_CALIB; } -/* Read a spare bit register from the shadow cache */ +/* Read a spare bit register. */ uint32_t fuse_get_spare_bit(uint32_t idx) { if (idx < 32) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); @@ -157,7 +154,7 @@ uint32_t fuse_get_spare_bit(uint32_t idx) { } } -/* Read a reserved ODM register from the shadow cache. */ +/* Read a reserved ODM register. */ uint32_t fuse_get_reserved_odm(uint32_t idx) { if (idx < 8) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); @@ -167,12 +164,12 @@ uint32_t fuse_get_reserved_odm(uint32_t idx) { } } -/* Get the DRAM ID using values in the shadow cache. */ +/* Get the DramId. */ uint32_t fuse_get_dram_id(void) { return ((fuse_get_reserved_odm(4) >> 3) & 0x7); } -/* Derive the Device ID using values in the shadow cache. */ +/* Derive the DeviceId. */ uint64_t fuse_get_device_id(void) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); @@ -198,46 +195,72 @@ uint64_t fuse_get_device_id(void) { return device_id; } -/* Derive the Hardware Type using values in the shadow cache. */ -uint32_t fuse_get_hardware_type(uint32_t target_firmware) { +/* Derive the HardwareType with firmware specific checks. */ +uint32_t fuse_get_hardware_type_with_firmware_check(uint32_t target_firmware) { uint32_t fuse_reserved_odm4 = fuse_get_reserved_odm(4); uint32_t hardware_type = (((fuse_reserved_odm4 >> 7) & 2) | ((fuse_reserved_odm4 >> 2) & 1)); - /* Firmware from versions 1.0.0 to 3.0.2. */ if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); - if (hardware_type >= 1) { - return (hardware_type > 2) ? 3 : hardware_type - 1; - } else if ((fuse_chip->FUSE_SPARE_BIT[9] & 1) == 0) { - return 0; - } else { - return 3; + uint32_t fuse_spare_bit9 = (fuse_chip->FUSE_SPARE_BIT[9] & 1); + + switch (hardware_type) { + case 0x00: return (fuse_spare_bit9 == 0) ? 0 : 3; + case 0x01: return 0; /* HardwareType_Icosa */ + case 0x02: return 1; /* HardwareType_Copper */ + default: return 3; /* HardwareType_Undefined */ } - } else if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) { /* Firmware versions from 4.0.0 to 6.2.0. */ - static const uint32_t types[] = {0,1,4,3}; + } else { hardware_type |= ((fuse_reserved_odm4 >> 14) & 0x3C); - hardware_type--; - return (hardware_type > 3) ? 4 : types[hardware_type]; - } else { /* Firmware versions from 7.0.0 onwards. */ - /* Always return 0 in retail. */ - return 0; + + if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) { + switch (hardware_type) { + case 0x01: return 0; /* HardwareType_Icosa */ + case 0x02: return 1; /* HardwareType_Copper */ + case 0x04: return 3; /* HardwareType_Iowa */ + default: return 4; /* HardwareType_Undefined */ + } + } else { + if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_10_0_0) { + switch (hardware_type) { + case 0x01: return 0; /* HardwareType_Icosa */ + case 0x02: return 4; /* HardwareType_Calcio */ + case 0x04: return 3; /* HardwareType_Iowa */ + case 0x08: return 2; /* HardwareType_Hoag */ + default: return 0xF; /* HardwareType_Undefined */ + } + } else { + switch (hardware_type) { + case 0x01: return 0; /* HardwareType_Icosa */ + case 0x02: return 4; /* HardwareType_Calcio */ + case 0x04: return 3; /* HardwareType_Iowa */ + case 0x08: return 2; /* HardwareType_Hoag */ + case 0x10: return 5; /* HardwareType_Five */ + default: return 0xF; /* HardwareType_Undefined */ + } + } + } } } -/* Derive the Retail Type using values in the shadow cache. */ -uint32_t fuse_get_retail_type(void) { - /* Retail Type = IS_RETAIL | UNIT_TYPE. */ +/* Derive the HardwareType. */ +uint32_t fuse_get_hardware_type(void) { + return fuse_get_hardware_type_with_firmware_check(ATMOSPHERE_TARGET_FIRMWARE_CURRENT); +} + +/* Derive the HardwareState. */ +uint32_t fuse_get_hardware_state(void) { uint32_t fuse_reserved_odm4 = fuse_get_reserved_odm(4); - uint32_t retail_type = (((fuse_reserved_odm4 >> 7) & 4) | (fuse_reserved_odm4 & 3)); - if (retail_type == 4) { /* Standard retail unit, IS_RETAIL | 0. */ - return 1; - } else if (retail_type == 3) { /* Standard dev unit, 0 | DEV_UNIT. */ - return 0; + uint32_t hardware_state = (((fuse_reserved_odm4 >> 7) & 4) | (fuse_reserved_odm4 & 3)); + + switch (hardware_state) { + case 0x03: return 0; /* HardwareState_Development */ + case 0x04: return 1; /* HardwareState_Production */ + default: return 2; /* HardwareState_Undefined */ } - return 2; /* IS_RETAIL | DEV_UNIT */ } -/* Derive the 16-byte Hardware Info using values in the shadow cache, and copy to output buffer. */ +/* Derive the 16-byte HardwareInfo and copy to output buffer. */ void fuse_get_hardware_info(void *dst) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); uint32_t hw_info[0x4]; @@ -259,3 +282,28 @@ void fuse_get_hardware_info(void *dst) { memcpy(dst, hw_info, 0x10); } + +/* Get the DeviceUniqueKeyGeneration. */ +uint32_t fuse_get_device_unique_key_generation(void) { + if ((fuse_get_reserved_odm(4) & 0x800) && (fuse_get_reserved_odm(0) == 0x8E61ECAE) && (fuse_get_reserved_odm(1) == 0xF2BA3BB2)) { + return (fuse_get_reserved_odm(2) & 0x1F); + } else { + return 0; + } +} + +/* Get the SocType from the HardwareType. */ +uint32_t fuse_get_soc_type(void) { + switch (fuse_get_hardware_type()) { + case 0: + case 1: + return 0; /* SocType_Erista */ + case 3: + case 2: + case 4: + case 5: + return 1; /* SocType_Mariko */ + default: + return 0xF; /* SocType_Undefined */ + } +} diff --git a/sept/sept-primary/src/fuse.h b/sept/sept-primary/src/fuse.h index 0e15cbe63..8bfec2b25 100644 --- a/sept/sept-primary/src/fuse.h +++ b/sept/sept-primary/src/fuse.h @@ -209,6 +209,8 @@ static inline volatile tegra_fuse_chip_t *fuse_chip_get_regs(void) void fuse_init(void); void fuse_disable_programming(void); void fuse_disable_private_key(void); +void fuse_enable_power(void); +void fuse_disable_power(void); uint32_t fuse_get_sku_info(void); uint32_t fuse_get_spare_bit(uint32_t idx); @@ -216,9 +218,12 @@ uint32_t fuse_get_reserved_odm(uint32_t idx); uint32_t fuse_get_bootrom_patch_version(void); uint64_t fuse_get_device_id(void); uint32_t fuse_get_dram_id(void); -uint32_t fuse_get_hardware_type(uint32_t target_firmware); +uint32_t fuse_get_hardware_type_with_firmware_check(uint32_t target_firmware); +uint32_t fuse_get_hardware_type(void); uint32_t fuse_get_retail_type(void); void fuse_get_hardware_info(void *dst); +uint32_t fuse_get_device_unique_key_generation(void); +uint32_t fuse_get_soc_type(void); uint32_t fuse_hw_read(uint32_t addr); void fuse_hw_write(uint32_t value, uint32_t addr); diff --git a/sept/sept-secondary/src/fuse.c b/sept/sept-secondary/src/fuse.c index bd8d9dac2..6f07da8ea 100644 --- a/sept/sept-secondary/src/fuse.c +++ b/sept/sept-secondary/src/fuse.c @@ -24,11 +24,6 @@ #include "pmc.h" #include "timers.h" -/* Prototypes for internal commands. */ -void fuse_enable_power(void); -void fuse_disable_power(void); -void fuse_wait_idle(void); - /* Initialize the fuse driver */ void fuse_init(void) { /* Make all fuse registers visible, disable the private key and disable programming. */ @@ -43,7 +38,7 @@ void fuse_disable_private_key(void) { fuse->FUSE_PRIVATEKEYDISABLE = 0x10; } -/* Disables all fuse programming. */ +/* Disable all fuse programming. */ void fuse_disable_programming(void) { volatile tegra_fuse_t *fuse = fuse_get_regs(); fuse->FUSE_DISABLEREGPROGRAM = 1; @@ -68,7 +63,7 @@ void fuse_disable_power(void) { } /* Wait for the fuse driver to go idle. */ -void fuse_wait_idle(void) { +static void fuse_wait_idle(void) { volatile tegra_fuse_t *fuse = fuse_get_regs(); uint32_t ctrl_val = 0; @@ -120,7 +115,7 @@ void fuse_hw_write(uint32_t value, uint32_t addr) { fuse_wait_idle(); } -/* Sense the fuse hardware array into the shadow cache. */ +/* Sense the fuse hardware array into the fuse cache. */ void fuse_hw_sense(void) { volatile tegra_fuse_t *fuse = fuse_get_regs(); @@ -137,19 +132,19 @@ void fuse_hw_sense(void) { fuse_wait_idle(); } -/* Read the SKU info register from the shadow cache. */ +/* Read the SKU info register. */ uint32_t fuse_get_sku_info(void) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); return fuse_chip->FUSE_SKU_INFO; } -/* Read the bootrom patch version from a register in the shadow cache. */ +/* Read the bootrom patch version. */ uint32_t fuse_get_bootrom_patch_version(void) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); return fuse_chip->FUSE_SOC_SPEEDO_1_CALIB; } -/* Read a spare bit register from the shadow cache */ +/* Read a spare bit register. */ uint32_t fuse_get_spare_bit(uint32_t idx) { if (idx < 32) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); @@ -159,7 +154,7 @@ uint32_t fuse_get_spare_bit(uint32_t idx) { } } -/* Read a reserved ODM register from the shadow cache. */ +/* Read a reserved ODM register. */ uint32_t fuse_get_reserved_odm(uint32_t idx) { if (idx < 8) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); @@ -169,12 +164,12 @@ uint32_t fuse_get_reserved_odm(uint32_t idx) { } } -/* Get the DRAM ID using values in the shadow cache. */ +/* Get the DramId. */ uint32_t fuse_get_dram_id(void) { return ((fuse_get_reserved_odm(4) >> 3) & 0x7); } -/* Derive the Device ID using values in the shadow cache. */ +/* Derive the DeviceId. */ uint64_t fuse_get_device_id(void) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); @@ -200,46 +195,72 @@ uint64_t fuse_get_device_id(void) { return device_id; } -/* Derive the Hardware Type using values in the shadow cache. */ -uint32_t fuse_get_hardware_type(uint32_t target_firmware) { +/* Derive the HardwareType with firmware specific checks. */ +uint32_t fuse_get_hardware_type_with_firmware_check(uint32_t target_firmware) { uint32_t fuse_reserved_odm4 = fuse_get_reserved_odm(4); uint32_t hardware_type = (((fuse_reserved_odm4 >> 7) & 2) | ((fuse_reserved_odm4 >> 2) & 1)); - /* Firmware from versions 1.0.0 to 3.0.2. */ if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); - if (hardware_type >= 1) { - return (hardware_type > 2) ? 3 : hardware_type - 1; - } else if ((fuse_chip->FUSE_SPARE_BIT[9] & 1) == 0) { - return 0; - } else { - return 3; + uint32_t fuse_spare_bit9 = (fuse_chip->FUSE_SPARE_BIT[9] & 1); + + switch (hardware_type) { + case 0x00: return (fuse_spare_bit9 == 0) ? 0 : 3; + case 0x01: return 0; /* HardwareType_Icosa */ + case 0x02: return 1; /* HardwareType_Copper */ + default: return 3; /* HardwareType_Undefined */ } - } else if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) { /* Firmware versions from 4.0.0 to 6.2.0. */ - static const uint32_t types[] = {0,1,4,3}; + } else { hardware_type |= ((fuse_reserved_odm4 >> 14) & 0x3C); - hardware_type--; - return (hardware_type > 3) ? 4 : types[hardware_type]; - } else { /* Firmware versions from 7.0.0 onwards. */ - /* Always return 0 in retail. */ - return 0; + + if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) { + switch (hardware_type) { + case 0x01: return 0; /* HardwareType_Icosa */ + case 0x02: return 1; /* HardwareType_Copper */ + case 0x04: return 3; /* HardwareType_Iowa */ + default: return 4; /* HardwareType_Undefined */ + } + } else { + if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_10_0_0) { + switch (hardware_type) { + case 0x01: return 0; /* HardwareType_Icosa */ + case 0x02: return 4; /* HardwareType_Calcio */ + case 0x04: return 3; /* HardwareType_Iowa */ + case 0x08: return 2; /* HardwareType_Hoag */ + default: return 0xF; /* HardwareType_Undefined */ + } + } else { + switch (hardware_type) { + case 0x01: return 0; /* HardwareType_Icosa */ + case 0x02: return 4; /* HardwareType_Calcio */ + case 0x04: return 3; /* HardwareType_Iowa */ + case 0x08: return 2; /* HardwareType_Hoag */ + case 0x10: return 5; /* HardwareType_Five */ + default: return 0xF; /* HardwareType_Undefined */ + } + } + } } } -/* Derive the Retail Type using values in the shadow cache. */ -uint32_t fuse_get_retail_type(void) { - /* Retail Type = IS_RETAIL | UNIT_TYPE. */ +/* Derive the HardwareType. */ +uint32_t fuse_get_hardware_type(void) { + return fuse_get_hardware_type_with_firmware_check(ATMOSPHERE_TARGET_FIRMWARE_CURRENT); +} + +/* Derive the HardwareState. */ +uint32_t fuse_get_hardware_state(void) { uint32_t fuse_reserved_odm4 = fuse_get_reserved_odm(4); - uint32_t retail_type = (((fuse_reserved_odm4 >> 7) & 4) | (fuse_reserved_odm4 & 3)); - if (retail_type == 4) { /* Standard retail unit, IS_RETAIL | 0. */ - return 1; - } else if (retail_type == 3) { /* Standard dev unit, 0 | DEV_UNIT. */ - return 0; + uint32_t hardware_state = (((fuse_reserved_odm4 >> 7) & 4) | (fuse_reserved_odm4 & 3)); + + switch (hardware_state) { + case 0x03: return 0; /* HardwareState_Development */ + case 0x04: return 1; /* HardwareState_Production */ + default: return 2; /* HardwareState_Undefined */ } - return 2; /* IS_RETAIL | DEV_UNIT */ } -/* Derive the 16-byte Hardware Info using values in the shadow cache, and copy to output buffer. */ +/* Derive the 16-byte HardwareInfo and copy to output buffer. */ void fuse_get_hardware_info(void *dst) { volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); uint32_t hw_info[0x4]; @@ -261,3 +282,28 @@ void fuse_get_hardware_info(void *dst) { memcpy(dst, hw_info, 0x10); } + +/* Get the DeviceUniqueKeyGeneration. */ +uint32_t fuse_get_device_unique_key_generation(void) { + if ((fuse_get_reserved_odm(4) & 0x800) && (fuse_get_reserved_odm(0) == 0x8E61ECAE) && (fuse_get_reserved_odm(1) == 0xF2BA3BB2)) { + return (fuse_get_reserved_odm(2) & 0x1F); + } else { + return 0; + } +} + +/* Get the SocType from the HardwareType. */ +uint32_t fuse_get_soc_type(void) { + switch (fuse_get_hardware_type()) { + case 0: + case 1: + return 0; /* SocType_Erista */ + case 3: + case 2: + case 4: + case 5: + return 1; /* SocType_Mariko */ + default: + return 0xF; /* SocType_Undefined */ + } +} diff --git a/sept/sept-secondary/src/fuse.h b/sept/sept-secondary/src/fuse.h index 0e15cbe63..8bfec2b25 100644 --- a/sept/sept-secondary/src/fuse.h +++ b/sept/sept-secondary/src/fuse.h @@ -209,6 +209,8 @@ static inline volatile tegra_fuse_chip_t *fuse_chip_get_regs(void) void fuse_init(void); void fuse_disable_programming(void); void fuse_disable_private_key(void); +void fuse_enable_power(void); +void fuse_disable_power(void); uint32_t fuse_get_sku_info(void); uint32_t fuse_get_spare_bit(uint32_t idx); @@ -216,9 +218,12 @@ uint32_t fuse_get_reserved_odm(uint32_t idx); uint32_t fuse_get_bootrom_patch_version(void); uint64_t fuse_get_device_id(void); uint32_t fuse_get_dram_id(void); -uint32_t fuse_get_hardware_type(uint32_t target_firmware); +uint32_t fuse_get_hardware_type_with_firmware_check(uint32_t target_firmware); +uint32_t fuse_get_hardware_type(void); uint32_t fuse_get_retail_type(void); void fuse_get_hardware_info(void *dst); +uint32_t fuse_get_device_unique_key_generation(void); +uint32_t fuse_get_soc_type(void); uint32_t fuse_hw_read(uint32_t addr); void fuse_hw_write(uint32_t value, uint32_t addr);