Fuses

From Nintendo Switch Brew
Revision as of 06:20, 2 August 2017 by Shinyquagsire23 (talk | contribs) (imdoingmypart.gif)
Jump to navigation Jump to search

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.