Fuses
The Nintendo Switch makes use of Tegra's efuse driver for a number of operations. This driver is mapped to physical address 0x7000F800 with a total size of 0x400 bytes and exposes several registers for fuse programming and other miscellaneous functions.
Registers
Below is a list of fuse driver registers used by the Switch's bootloaders.
Name | Address | Width |
---|---|---|
FUSE_CTRL | 0x7000F800 | 0x04 |
FUSE_REG_ADDR | 0x7000F804 | 0x04 |
FUSE_REG_READ | 0x7000F808 | 0x04 |
FUSE_REG_WRITE | 0x7000F80C | 0x04 |
FUSE_TIME_PGM2 | 0x7000F81C | 0x04 |
FUSE_DIS_PGM | 0x7000F82C | 0x04 |
FUSE_WRITE_ACCESS | 0x7000F830 | 0x04 |
FUSE_SKU_INFO | 0x7000F910 | 0x04 |
FUSE_SPEEDO_1_CALIB_0 | 0x7000F938 | 0x04 |
FUSE_GCPLEX_CONFIG_FUSE_0 | 0x7000F9C8 | 0x04 |
FUSE_GCPLEX_CONFIG_FUSE_1 | 0x7000F9CC | 0x04 |
FUSE_GCPLEX_CONFIG_FUSE_2 | 0x7000F9D0 | 0x04 |
FUSE_GCPLEX_CONFIG_FUSE_3 | 0x7000F9D4 | 0x04 |
FUSE_GCPLEX_CONFIG_FUSE_4 | 0x7000F9D8 | 0x04 |
FUSE_GCPLEX_CONFIG_FUSE_5 | 0x7000F9DC | 0x04 |
FUSE_BURNT_FUSE_COUNT_0 | 0x7000F9E0 | 0x04 |
FUSE_BURNT_FUSE_COUNT_1 | 0x7000F9E4 | 0x04 |
FUSE_MASTER_KEY_VER | 0x7000FB94 | 0x04 |
FUSE_CTRL
Bits | Description |
---|---|
0-1 | Fuse command (1 = FUSE_READ; 2 = FUSE_WRITE; 3 = FUSE_SENSE) |
26 | Fuse power down mode flag (FUSE_CTRL_PD) |
Before fuse reading/writing the power down mode must be disabled.
FUSE_REG_ADDR
This register takes the address of the fuse to be read/written/sensed.
FUSE_REG_READ
This register receives the value read from the fuse.
FUSE_REG_WRITE
This register takes the value to be written to the fuse.
FUSE_TIME_PGM2
This register takes the fuse programming pulse (0xC0 == 19200 kHz).
FUSE_DIS_PGM
If set to 0x01, this register disables fuse programming.
FUSE_WRITE_ACCESS
If set to 0x01, this register disables software writes to the fuse registers.
FUSE_SKU_INFO
Stores the SKU ID (must be 0x83).
FUSE_SPEEDO_1_CALIB_0
Seems to store the bootrom patch version.
FUSE_GCPLEX_CONFIG_FUSE_4
Bits | Description |
---|---|
0-1 | Unit type (3 = debug; 0 = retail) |
2 | Unknown config (must be 1 on retail) |
8 | Unknown config mask (must be 0 on retail) |
9 | Unit type mask (0 = debug; 1 = retail) |
This stores some device configuration parameters.
FUSE_MASTER_KEY_VER
Must be non-zero on retail units, otherwise the first bootloader panics. On debug units it can be zero, which tells the bootloader to choose from two debug master key seeds. If set to non-zero on a debug unit, it tells the bootloader to choose from two retail master key seeds (only the last one matches the retail master key seed).
FUSE_BURNT_FUSE_COUNT_0
This register returns the value programmed into offset 0x3A of the fuse array.
FUSE_BURNT_FUSE_COUNT_1
This register returns the value programmed into offset 0x3C of the fuse array.
eFuses
The actual hardware fuses can be programmed through the fuse driver after enabling fuse programming.
Below is a list of common fuse offsets used by Tegra devices (and applicable to the Switch). Note that offsets are relative to the start of the fuse array and a single fuse write operation always writes the same word at both (fuse_offset + 0) and (fuse_offset + 1).
Name | Offset | Bits |
---|---|---|
jtag_disable | 0x00 | 1 |
odm_production_mode | 0x00 | 1 |
odm_lock | 0x00 | 4 |
public_key | 0x0C | 256 |
secure_boot_key | 0x22 | 128 |
device_key | 0x2A | 32 |
sec_boot_dev_cfg | 0x2C | 16 |
sec_boot_dev_sel | 0x2C | 3 |
sw_reserved | 0x2E | 12 |
ignore_dev_sel_straps | 0x2E | 1 |
odm_reserved | 0x2E | 256 |
pkc_disable | 0x52 | 1 |
odm_reserved
The first bootloader only burns fuses in this region. Both fuse offsets 0x3A (odm_reserved + 0x0C) and 0x3C (odm_reserved + 0x0E) are used for anti-downgrade control.
Anti-downgrade
The first bootloader verifies FUSE_BURNT_FUSE_COUNT_1 to prevent downgrading. How many fuses are expected to be burnt depends the device's unit type as below.
System version | Expected number of burnt fuses (retail) | Expected number of burnt fuses (non-retail) |
---|---|---|
1.0.0 | 1 | 0 |
2.0.0-2.3.0 | 2 | 0 |
3.0.0 | 3 | 1 |
3.0.1 | 4 | 1 |
If too many fuses are burnt the bootloader will panic immediately.
If too few are burnt, the bootloader will enable fuse programming and write the expected value to fuse offsets 0x3A and 0x3C. Afterwards, fuse programming is disabled and a magic value (0x21 == TEGRA210) is written to an unknown PMC register (0x7000EC40). Finally, the watchdog timer is initialized and programmed to force a reset.
On a subsequent boot, after the anti-downgrade fuses are checked again, PMC_RST_STATUS (0x7000E5B4) is checked and if set to 0x01 (watchdog reset) the unknown PMC register (0x7000EC40) will be checked for the magic value 0x21. PMC_RST_STATUS will only be set back to 0 (power on reset) if the fuse count matches the new expected value, otherwise the system will panic.