diff --git a/fusee/fusee-secondary/Makefile b/fusee/fusee-secondary/Makefile index ed51bffb8..930abf2b0 100644 --- a/fusee/fusee-secondary/Makefile +++ b/fusee/fusee-secondary/Makefile @@ -87,7 +87,8 @@ export KIPDIRS := $(AMS)/stratosphere/loader $(AMS)/stratosphere/pm $(AMS)/strat export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ $(foreach dir,$(DATA),$(CURDIR)/$(dir)) \ $(AMS)/exosphere $(AMS)/exosphere/lp0fw $(AMS)/exosphere/rebootstub \ - $(AMS)/thermosphere $(AMS)/fusee/fusee-primary $(KIPDIRS) + $(AMS)/thermosphere $(AMS)/fusee/fusee-primary $(AMS)/sept/sept-primary \ + $(KIPDIRS) export DEPSDIR := $(CURDIR)/$(BUILD) @@ -95,7 +96,10 @@ CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) KIPFILES := loader.kip pm.kip sm.kip ams_mitm.kip boot_100.kip boot_200.kip -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) fusee-primary.bin exosphere.bin lp0fw.bin rebootstub.bin thermosphere.bin splash_screen.bmp $(KIPFILES) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) fusee-primary.bin \ + exosphere.bin lp0fw.bin rebootstub.bin thermosphere.bin splash_screen.bmp \ + sept-primary.bin \ + $(KIPFILES) #--------------------------------------------------------------------------------- # use CXX for linking C++ projects, CC for standard C @@ -123,7 +127,7 @@ export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) .PHONY: $(BUILD) clean all -.PHONY: check_fusee_primary check_exosphere check_thermosphere check_stratosphere +.PHONY: check_fusee_primary check_exosphere check_sept check_thermosphere check_stratosphere #--------------------------------------------------------------------------------- all: $(BUILD) @@ -134,6 +138,9 @@ check_fusee_primary: check_exosphere: @$(MAKE) -C $(AMS)/exosphere all +check_sept: + @$(MAKE) -C $(AMS)/sept all + check_thermosphere: @$(MAKE) -C $(AMS)/thermosphere all @@ -141,7 +148,7 @@ check_stratosphere: @$(MAKE) -C $(AMS)/stratosphere all -$(BUILD): check_fusee_primary check_exosphere check_thermosphere check_stratosphere +$(BUILD): check_fusee_primary check_exosphere check_sept check_thermosphere check_stratosphere @[ -d $@ ] || mkdir -p $@ @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile @@ -186,6 +193,11 @@ fusee_primary.bin.o fusee_primary_bin.h: fusee-primary.bin @echo $(notdir $<) @$(_bin2o) +sept_primary.bin.o sept_primary_bin.h: sept-primary.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(_bin2o) + %.bin.o %_bin.h: %.bin #--------------------------------------------------------------------------------- @echo $(notdir $<) diff --git a/fusee/fusee-secondary/src/nxboot.c b/fusee/fusee-secondary/src/nxboot.c index 92eef7440..0ca6e42a6 100644 --- a/fusee/fusee-secondary/src/nxboot.c +++ b/fusee/fusee-secondary/src/nxboot.c @@ -411,6 +411,12 @@ uint32_t nxboot_main(void) { } } + if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_700) { + /* TODO: Detect when we have been loaded by sept-secondary, and thus have keys provided for us. */ + static const uint8_t sept_secondary[0x0] = { /* TODO: link-time magic */ }; + reboot_to_sept(tsec_fw, tsec_fw_size, sept_secondary, sizeof(sept_secondary)); + } + print(SCREEN_LOG_LEVEL_MANDATORY, "[NXBOOT]: Loaded firmware from eMMC...\n"); /* Get the TSEC keys. */ diff --git a/fusee/fusee-secondary/src/utils.c b/fusee/fusee-secondary/src/utils.c index e09fc6e37..a847320a6 100644 --- a/fusee/fusee-secondary/src/utils.c +++ b/fusee/fusee-secondary/src/utils.c @@ -32,6 +32,7 @@ #define u8 uint8_t #define u32 uint32_t #include "fusee_primary_bin.h" +#include "sept_primary_bin.h" #include "rebootstub_bin.h" #undef u8 #undef u32 @@ -65,7 +66,7 @@ __attribute__((noreturn)) void pmc_reboot(uint32_t scratch0) { } } -__attribute__((noreturn)) void reboot_to_fusee_primary(void) { +__attribute__((noreturn)) static void reboot_to_payload(void) { /* Patch SDRAM init to perform an SVC immediately after second write */ APBDEV_PMC_SCRATCH45_0 = 0x2E38DFFF; APBDEV_PMC_SCRATCH46_0 = 0x6001DC28; @@ -73,11 +74,6 @@ __attribute__((noreturn)) void reboot_to_fusee_primary(void) { APBDEV_PMC_SCRATCH33_0 = 0x4003F000; APBDEV_PMC_SCRATCH40_0 = 0x6000F208; - /* Copy fusee-primary into IRAM low. */ - for (size_t i = 0; i < fusee_primary_bin_size; i += sizeof(uint32_t)) { - write32le((void *)0x40010000, i, read32le(fusee_primary_bin, i)); - } - /* Copy reboot stub into IRAM high. */ for (size_t i = 0; i < rebootstub_bin_size; i += sizeof(uint32_t)) { write32le((void *)0x4003F000, i, read32le(rebootstub_bin, i)); @@ -85,6 +81,55 @@ __attribute__((noreturn)) void reboot_to_fusee_primary(void) { /* Trigger warm reboot. */ pmc_reboot(1 << 0); + while (true) { } +} + +__attribute__((noreturn)) void reboot_to_fusee_primary(void) { + /* Copy fusee-primary into IRAM low. */ + for (size_t i = 0; i < fusee_primary_bin_size; i += sizeof(uint32_t)) { + write32le((void *)0x40010000, i, read32le(fusee_primary_bin, i)); + } + + reboot_to_payload(); +} + +__attribute__((noreturn)) void reboot_to_sept(const void *tsec_fw, size_t tsec_fw_length, const void *stage2, size_t stage2_size) { + + /* Copy tsec firmware. */ + for (size_t i = 0; i < tsec_fw_length; i += sizeof(uint32_t)) { + write32le((void *)0x40010F00, i, read32le(tsec_fw, i)); + } + MAKE_REG32(0x40010EFC) = tsec_fw_length; + + /* Copy stage 2. */ + for (size_t i = 0; i < stage2_size; i += sizeof(uint32_t)) { + write32le((void *)0x40016FE0, i, read32le(stage2, i)); + } + + /* Copy sept into IRAM low. */ + for (size_t i = 0; i < sept_primary_bin_size; i += sizeof(uint32_t)) { + write32le((void *)0x4003F000, i, read32le(sept_primary_bin, i)); + } + + /* Patch SDRAM init to perform an SVC immediately after second write */ + APBDEV_PMC_SCRATCH45_0 = 0x2E38DFFF; + APBDEV_PMC_SCRATCH46_0 = 0x6001DC28; + /* Set SVC handler to jump to reboot stub in IRAM. */ + APBDEV_PMC_SCRATCH33_0 = 0x4003F000; + APBDEV_PMC_SCRATCH40_0 = 0x6000F208; + + /* Trigger warm reboot. */ + pmc_reboot(1 << 0); + while (true) { } +} + +__attribute__((noreturn)) void reboot_to_iram_payload(void *payload, size_t payload_size) { + /* Copy sept into IRAM low. */ + for (size_t i = 0; i < payload_size; i += sizeof(uint32_t)) { + write32le((void *)0x40010000, i, read32le(payload, i)); + } + + reboot_to_payload(); } __attribute__((noreturn)) void wait_for_button_and_reboot(void) { diff --git a/fusee/fusee-secondary/src/utils.h b/fusee/fusee-secondary/src/utils.h index 8cc3e6814..605bd6ed3 100644 --- a/fusee/fusee-secondary/src/utils.h +++ b/fusee/fusee-secondary/src/utils.h @@ -123,6 +123,8 @@ void hexdump(const void* data, size_t size, uintptr_t addrbase); __attribute__((noreturn)) void watchdog_reboot(void); __attribute__((noreturn)) void pmc_reboot(uint32_t scratch0); __attribute__((noreturn)) void reboot_to_fusee_primary(void); +__attribute__((noreturn)) void reboot_to_sept(const void *tsec_fw, size_t tsec_fw_length, const void *stage2, size_t stage2_size); +__attribute__((noreturn)) void reboot_to_iram_payload(void *payload, size_t payload_size); __attribute__((noreturn)) void wait_for_button_and_reboot(void); void wait_for_button(void); diff --git a/sept/Makefile b/sept/Makefile new file mode 100644 index 000000000..632a5cd13 --- /dev/null +++ b/sept/Makefile @@ -0,0 +1,10 @@ +SUBFOLDERS := sept-primary + +TOPTARGETS := all clean + +$(TOPTARGETS): $(SUBFOLDERS) + +$(SUBFOLDERS): + $(MAKE) -C $@ $(MAKECMDGOALS) + +.PHONY: $(TOPTARGETS) $(SUBFOLDERS) diff --git a/sept/sept-primary/Makefile b/sept/sept-primary/Makefile new file mode 100644 index 000000000..107b32f55 --- /dev/null +++ b/sept/sept-primary/Makefile @@ -0,0 +1,169 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +TOPDIR ?= $(CURDIR) + +AMS := $(TOPDIR)/../../ +include $(DEVKITARM)/base_rules + +AMSBRANCH := $(shell git symbolic-ref --short HEAD) +AMSREV := $(AMSBRANCH)-$(shell git rev-parse --short HEAD) + +ifneq (, $(strip $(shell git status --porcelain 2>/dev/null))) + AMSREV := $(AMSREV)-dirty +endif + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# DATA is a list of directories containing data files +# INCLUDES is a list of directories containing header files +#--------------------------------------------------------------------------------- +TARGET := $(notdir $(CURDIR)) +BUILD := build +SOURCES := src src/sdmmc src/lib src/lib/fatfs src/display +DATA := data +INCLUDES := include ../../common/include + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork +DEFINES := -D__BPMP__ -DFUSEE_STAGE1_SRC -DATMOSPHERE_GIT_BRANCH=\"$(AMSBRANCH)\" -DATMOSPHERE_GIT_REV=\"$(AMSREV)\" + +CFLAGS := \ + -g \ + -O2 \ + -fomit-frame-pointer \ + -ffunction-sections \ + -fdata-sections \ + -std=gnu11 \ + -Werror \ + -Wall \ + -fstrict-volatile-bitfields \ + $(ARCH) $(DEFINES) + +CFLAGS += $(INCLUDE) + +CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 + +ASFLAGS := -g $(ARCH) +LDFLAGS = -specs=$(TOPDIR)/linker.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) + +LIBS := + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := + + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) \ + $(AMS)/exosphere/rebootstub + +export DEPSDIR := $(CURDIR)/$(BUILD) + +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) rebootstub.bin + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES_BIN := $(addsuffix .o,$(BINFILES)) +export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +export OFILES := $(OFILES_BIN) $(OFILES_SRC) +export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +.PHONY: $(BUILD) clean all check_rebootstub + +#--------------------------------------------------------------------------------- +all: check_rebootstub $(BUILD) + +check_rebootstub: + @$(MAKE) -C $(AMS)/exosphere/rebootstub all + +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @$(MAKE) -C $(AMS)/exosphere/rebootstub clean + @rm -fr $(BUILD) $(TARGET).bin $(TARGET).elf + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(OUTPUT).bin + +$(OUTPUT).bin : $(OUTPUT).elf + $(OBJCOPY) -S -O binary $< $@ + @echo built ... $(notdir $@) + +$(OUTPUT).elf : $(OFILES) + +%.elf: $(OFILES) + @echo linking $(notdir $@) + @$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ + @$(NM) -CSn $@ > $(notdir $*.lst) + +$(OFILES_SRC) : $(HFILES_BIN) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o %_bin.h: %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/sept/sept-primary/linker.ld b/sept/sept-primary/linker.ld new file mode 100644 index 000000000..7d135168c --- /dev/null +++ b/sept/sept-primary/linker.ld @@ -0,0 +1,168 @@ +OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) + +PHDRS +{ + crt0 PT_LOAD; + main PT_LOAD; +} + +/* Mostly copied from https://github.com/devkitPro/buildscripts/blob/master/dkarm-eabi/crtls/3dsx.ld */ +MEMORY +{ + NULL : ORIGIN = 0x00000000, LENGTH = 0x1000 + main : ORIGIN = 0x40010040, LENGTH = 0x1000 + high_iram : ORIGIN = 0x4003F000, LENGTH = 0x1000 + low_iram : ORIGIN = 0x40003000, LENGTH = 0x8000 +} + +SECTIONS +{ + PROVIDE(__crt0_start__ = 0x4003F000); + PROVIDE(__main_start__ = 0x40010040); + PROVIDE(__stack_top__ = 0x40010000); + PROVIDE(__stack_bottom__ = 0x4000C000); + PROVIDE(__heap_start__ = 0); + PROVIDE(__heap_end__ = 0); + + . = __crt0_start__; + + .crt0 : + { + KEEP( *(.text.start) ) + KEEP( *(.text.ipatch_word) ) + KEEP( *(.init) ) + . = ALIGN(32); + } >high_iram AT>high_iram :crt0 + + __main_phys_start__ = ABSOLUTE(.) ; + + .text : + { + /* .text */ + KEEP( *(.text.jump_to_main) ) + *(.text) + *(.text.*) + *(.glue_7) + *(.glue_7t) + *(.stub) + *(.gnu.warning) + *(.gnu.linkonce.t*) + + /* .fini */ + KEEP( *(.fini) ) + . = ALIGN(8); + } >main AT>high_iram :main + + .rodata : + { + *(.rodata) + *(.roda) + *(.rodata.*) + *all.rodata*(*) + *(.gnu.linkonce.r*) + SORT(CONSTRUCTORS) + . = ALIGN(8); + } >main AT>high_iram + + .preinit_array : + { + PROVIDE (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE (__preinit_array_end = .); + } >main AT>high_iram + + .init_array ALIGN(4) : + { + PROVIDE (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE (__init_array_end = .); + } >main AT>high_iram + + .fini_array ALIGN(4) : + { + PROVIDE (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE (__fini_array_end = .); + } >main AT>high_iram + + .ctors ALIGN(4) : + { + KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */ + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } >main AT>high_iram + + .dtors ALIGN(4) : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } >main AT>high_iram + + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) __exidx_start = ABSOLUTE(.);} >main AT>high_iram + ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) __exidx_end = ABSOLUTE(.);} >main AT>high_iram + + .bss (NOLOAD) : + { + . = ALIGN(32); + PROVIDE (__bss_start__ = ABSOLUTE(.)); + *(.dynbss) + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b*) + *(COMMON) + . = ALIGN(32); + PROVIDE (__bss_end__ = ABSOLUTE(.)); + } >main AT>high_iram :NONE + __main_end__ = ABSOLUTE(.) ; + + PROVIDE(__main_size__ = (__main_end__ - __main_start__)); + + /* ================== + ==== Metadata ==== + ================== */ + + /* Discard sections that difficult post-processing */ + /DISCARD/ : { *(.group .comment .note) } + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } +} diff --git a/sept/sept-primary/linker.specs b/sept/sept-primary/linker.specs new file mode 100644 index 000000000..300990418 --- /dev/null +++ b/sept/sept-primary/linker.specs @@ -0,0 +1,7 @@ +%rename link old_link + +*link: +%(old_link) -T %:getenv(TOPDIR /linker.ld) --nmagic --gc-sections + +*startfile: +crti%O%s crtbegin%O%s diff --git a/sept/sept-primary/src/apb_misc.h b/sept/sept-primary/src/apb_misc.h new file mode 100644 index 000000000..b2e8b1dff --- /dev/null +++ b/sept/sept-primary/src/apb_misc.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef FUSEE_APB_MISC_H +#define FUSEE_APB_MISC_H + +#include + +#define APB_MISC_BASE 0x70000000 +#define APB_PADCTL_BASE 0x70000810 +#define MAKE_APB_MISC_REG(n) MAKE_REG32(APB_MISC_BASE + n) +#define MAKE_APB_PADCTL_REG(n) MAKE_REG32(APB_PADCTL_BASE + n) + +#define APB_MISC_PP_PINMUX_GLOBAL_0 MAKE_APB_MISC_REG(0x40) +#define APB_MISC_GP_WIFI_EN_CFGPADCTRL_0 MAKE_APB_MISC_REG(0xB64) +#define APB_MISC_GP_WIFI_RST_CFGPADCTRL_0 MAKE_APB_MISC_REG(0xB68) + +#define SDMMC1_PAD_CAL_DRVUP_SHIFT (20) +#define SDMMC1_PAD_CAL_DRVDN_SHIFT (12) +#define SDMMC1_PAD_CAL_DRVUP_MASK (0x7Fu << SDMMC1_PAD_CAL_DRVUP_SHIFT) +#define SDMMC1_PAD_CAL_DRVDN_MASK (0x7Fu << SDMMC1_PAD_CAL_DRVDN_SHIFT) + +#define CFG2TMC_EMMC4_PAD_DRVUP_COMP_SHIFT (8) +#define CFG2TMC_EMMC4_PAD_DRVDN_COMP_SHIFT (2) +#define CFG2TMC_EMMC4_PAD_DRVUP_COMP_MASK (0x3Fu << CFG2TMC_EMMC4_PAD_DRVUP_COMP_SHIFT) +#define CFG2TMC_EMMC4_PAD_DRVDN_COMP_MASK (0x3Fu << CFG2TMC_EMMC4_PAD_DRVDN_COMP_SHIFT) + +#define PADCTL_SDMMC1_DEEP_LOOPBACK (1 << 0) +#define PADCTL_SDMMC3_DEEP_LOOPBACK (1 << 0) +#define PADCTL_SDMMC2_ENABLE_DATA_IN (0xFF << 8) +#define PADCTL_SDMMC2_ENABLE_CLK_IN (0x3 << 4) +#define PADCTL_SDMMC2_DEEP_LOOPBACK (1 << 0) +#define PADCTL_SDMMC4_ENABLE_DATA_IN (0xFF << 8) +#define PADCTL_SDMMC4_ENABLE_CLK_IN (0x3 << 4) +#define PADCTL_SDMMC4_DEEP_LOOPBACK (1 << 0) +#define PADCTL_SDMMC1_CD_SOURCE (1 << 0) +#define PADCTL_SDMMC1_WP_SOURCE (1 << 1) +#define PADCTL_SDMMC3_CD_SOURCE (1 << 2) +#define PADCTL_SDMMC3_WP_SOURCE (1 << 3) + +typedef struct { + uint32_t asdbgreg; /* 0x810 */ + uint32_t reserved0[0x31]; + uint32_t sdmmc1_clk_lpbk_control; /* 0x8D4 */ + uint32_t sdmmc3_clk_lpbk_control; /* 0x8D8 */ + uint32_t emmc2_pad_cfg_control; /* 0x8DC */ + uint32_t emmc4_pad_cfg_control; /* 0x8E0 */ + uint32_t _todo0[0x6E]; + uint32_t sdmmc1_pad_cfgpadctrl; /* 0xA98 */ + uint32_t emmc2_pad_cfgpadctrl; /* 0xA9C */ + uint32_t emmc2_pad_drv_type_cfgpadctrl; /* 0xAA0 */ + uint32_t emmc2_pad_pupd_cfgpadctrl; /* 0xAA4 */ + uint32_t _todo1[0x03]; + uint32_t sdmmc3_pad_cfgpadctrl; /* 0xAB0 */ + uint32_t emmc4_pad_cfgpadctrl; /* 0xAB4 */ + uint32_t emmc4_pad_drv_type_cfgpadctrl; /* 0xAB8 */ + uint32_t emmc4_pad_pupd_cfgpadctrl; /* 0xABC */ + uint32_t _todo2[0x2E]; + uint32_t vgpio_gpio_mux_sel; /* 0xB74 */ + uint32_t qspi_sck_lpbk_control; /* 0xB78 */ +} tegra_padctl_t; + +static inline volatile tegra_padctl_t *padctl_get_regs(void) +{ + return (volatile tegra_padctl_t *)APB_PADCTL_BASE; +} + +#endif diff --git a/sept/sept-primary/src/btn.c b/sept/sept-primary/src/btn.c new file mode 100644 index 000000000..87a57c7bd --- /dev/null +++ b/sept/sept-primary/src/btn.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 CTCaer + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "btn.h" +#include "i2c.h" +#include "gpio.h" +#include "timers.h" + +uint32_t btn_read() +{ + uint32_t res = 0; + + if (!gpio_read(GPIO_BUTTON_VOL_DOWN)) + res |= BTN_VOL_DOWN; + + if (!gpio_read(GPIO_BUTTON_VOL_UP)) + res |= BTN_VOL_UP; + + uint32_t val = 0; + if (i2c_query(I2C_5, MAX77620_PWR_I2C_ADDR, 0x15, &val, 1)) + { + if (val & 0x4) + res |= BTN_POWER; + } + + return res; +} + +uint32_t btn_wait() +{ + uint32_t res = 0, btn = btn_read(); + int pwr = 0; + + if (btn & BTN_POWER) + { + pwr = 1; + btn &= ~BTN_POWER; + } + + do + { + res = btn_read(); + + if (!(res & BTN_POWER) && pwr) + pwr = 0; + else if (pwr) + res &= ~BTN_POWER; + } while (btn == res); + + return res; +} + +uint32_t btn_wait_timeout(uint32_t time_ms, uint32_t mask) +{ + uint32_t timeout = get_time_us() + time_ms * 1000; + uint32_t res = btn_read() & mask; + + do + { + if (!(res & mask)) + res = btn_read() & mask; + } while (get_time_us() < timeout); + + return res; +} \ No newline at end of file diff --git a/sept/sept-primary/src/btn.h b/sept/sept-primary/src/btn.h new file mode 100644 index 000000000..04f569b94 --- /dev/null +++ b/sept/sept-primary/src/btn.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 CTCaer + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef FUSEE_BTN_H_ +#define FUSEE_BTN_H_ + +#define BTN_POWER 0x1 +#define BTN_VOL_DOWN 0x2 +#define BTN_VOL_UP 0x4 + +uint32_t btn_read(); +uint32_t btn_wait(); +uint32_t btn_wait_timeout(uint32_t time_ms, uint32_t mask); + +#endif \ No newline at end of file diff --git a/sept/sept-primary/src/car.c b/sept/sept-primary/src/car.c new file mode 100644 index 000000000..75c1f6854 --- /dev/null +++ b/sept/sept-primary/src/car.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "car.h" +#include "utils.h" +#include "timers.h" + +static inline uint32_t get_clk_source_reg(CarDevice dev) { + switch (dev) { + case CARDEVICE_UARTA: return 0x178; + case CARDEVICE_UARTB: return 0x17C; + case CARDEVICE_UARTC: return 0x1A0; + case CARDEVICE_I2C1: return 0x124; + case CARDEVICE_I2C5: return 0x128; + case CARDEVICE_UNK: return 0; + case CARDEVICE_SE: return 0x42C; + case CARDEVICE_HOST1X: return 0x180; + case CARDEVICE_TSEC: return 0x1F4; + case CARDEVICE_SOR_SAFE: return 0; + case CARDEVICE_SOR0: return 0; + case CARDEVICE_SOR1: return 0x410; + case CARDEVICE_KFUSE: return 0; + case CARDEVICE_CL_DVFS: return 0; + case CARDEVICE_CORESIGHT: return 0x1D4; + case CARDEVICE_ACTMON: return 0x3E8; + case CARDEVICE_BPMP: return 0; + default: generic_panic(); + } +} + +static inline uint32_t get_clk_source_val(CarDevice dev) { + switch (dev) { + case CARDEVICE_UARTA: return 0; + case CARDEVICE_UARTB: return 0; + case CARDEVICE_UARTC: return 0; + case CARDEVICE_I2C1: return 6; + case CARDEVICE_I2C5: return 6; + case CARDEVICE_UNK: return 0; + case CARDEVICE_SE: return 0; + case CARDEVICE_HOST1X: return 4; + case CARDEVICE_TSEC: return 0; + case CARDEVICE_SOR_SAFE: return 0; + case CARDEVICE_SOR0: return 0; + case CARDEVICE_SOR1: return 0; + case CARDEVICE_KFUSE: return 0; + case CARDEVICE_CL_DVFS: return 0; + case CARDEVICE_CORESIGHT: return 0; + case CARDEVICE_ACTMON: return 6; + case CARDEVICE_BPMP: return 0; + default: generic_panic(); + } +} + +static inline uint32_t get_clk_source_div(CarDevice dev) { + switch (dev) { + case CARDEVICE_UARTA: return 0; + case CARDEVICE_UARTB: return 0; + case CARDEVICE_UARTC: return 0; + case CARDEVICE_I2C1: return 0; + case CARDEVICE_I2C5: return 0; + case CARDEVICE_UNK: return 0; + case CARDEVICE_SE: return 0; + case CARDEVICE_HOST1X: return 3; + case CARDEVICE_TSEC: return 2; + case CARDEVICE_SOR_SAFE: return 0; + case CARDEVICE_SOR0: return 0; + case CARDEVICE_SOR1: return 2; + case CARDEVICE_KFUSE: return 0; + case CARDEVICE_CL_DVFS: return 0; + case CARDEVICE_CORESIGHT: return 4; + case CARDEVICE_ACTMON: return 0; + case CARDEVICE_BPMP: return 0; + default: generic_panic(); + } +} + +static uint32_t g_clk_reg_offsets[NUM_CAR_BANKS] = {0x010, 0x014, 0x018, 0x360, 0x364, 0x280, 0x298}; +static uint32_t g_rst_reg_offsets[NUM_CAR_BANKS] = {0x004, 0x008, 0x00C, 0x358, 0x35C, 0x28C, 0x2A4}; + +void clk_enable(CarDevice dev) { + uint32_t clk_source_reg; + if ((clk_source_reg = get_clk_source_reg(dev))) { + MAKE_CAR_REG(clk_source_reg) = (get_clk_source_val(dev) << 29) | get_clk_source_div(dev); + } + MAKE_CAR_REG(g_clk_reg_offsets[dev >> 5]) |= BIT(dev & 0x1F); +} + +void clk_disable(CarDevice dev) { + MAKE_CAR_REG(g_clk_reg_offsets[dev >> 5]) &= ~(BIT(dev & 0x1F)); +} + +void rst_enable(CarDevice dev) { + MAKE_CAR_REG(g_rst_reg_offsets[dev >> 5]) |= BIT(dev & 0x1F); +} + +void rst_disable(CarDevice dev) { + MAKE_CAR_REG(g_rst_reg_offsets[dev >> 5]) &= ~(BIT(dev & 0x1F)); +} + +void clkrst_enable(CarDevice dev) { + clk_enable(dev); + rst_disable(dev); +} + +void clkrst_disable(CarDevice dev) { + rst_enable(dev); + clk_disable(dev); +} + +void clkrst_reboot(CarDevice dev) { + clkrst_disable(dev); + if (dev == CARDEVICE_KFUSE) { + /* Workaround for KFUSE clock. */ + clk_enable(dev); + udelay(100); + rst_disable(dev); + udelay(200); + } else { + clkrst_enable(dev); + } +} + +void clkrst_enable_fuse_regs(bool enable) { + volatile tegra_car_t *car = car_get_regs(); + car->misc_clk_enb = ((car->misc_clk_enb & 0xEFFFFFFF) | ((enable & 1) << 28)); +} diff --git a/sept/sept-primary/src/car.h b/sept/sept-primary/src/car.h new file mode 100644 index 000000000..4135a54ef --- /dev/null +++ b/sept/sept-primary/src/car.h @@ -0,0 +1,505 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef FUSEE_CAR_H +#define FUSEE_CAR_H + +#include +#include + +#define CAR_BASE 0x60006000 +#define MAKE_CAR_REG(n) MAKE_REG32(CAR_BASE + n) + +#define CLK_L_SDMMC1 (1 << 14) +#define CLK_L_SDMMC2 (1 << 9) +#define CLK_U_SDMMC3 (1 << 5) +#define CLK_L_SDMMC4 (1 << 15) + +#define CLK_SOURCE_MASK (0b111 << 29) +#define CLK_SOURCE_FIRST (0b000 << 29) +#define CLK_DIVIDER_MASK (0xff << 0) +#define CLK_DIVIDER_UNITY (0x00 << 0) + +#define NUM_CAR_BANKS 7 + +/* Clock and reset devices. */ +typedef enum { + CARDEVICE_UARTA = ((0 << 5) | 0x6), + CARDEVICE_UARTB = ((0 << 5) | 0x7), + CARDEVICE_UARTC = ((1 << 5) | 0x17), + CARDEVICE_I2C1 = ((0 << 5) | 0xC), + CARDEVICE_I2C5 = ((1 << 5) | 0xF), + CARDEVICE_UNK = ((3 << 5) | 0x1E), + CARDEVICE_SE = ((3 << 5) | 0x1F), + CARDEVICE_HOST1X = ((0 << 5) | 0x1C), + CARDEVICE_TSEC = ((2 << 5) | 0x13), + CARDEVICE_SOR_SAFE = ((6 << 5) | 0x1E), + CARDEVICE_SOR0 = ((5 << 5) | 0x16), + CARDEVICE_SOR1 = ((5 << 5) | 0x17), + CARDEVICE_KFUSE = ((1 << 5) | 0x8), + CARDEVICE_CL_DVFS = ((4 << 5) | 0x1B), + CARDEVICE_CORESIGHT = ((2 << 5) | 0x9), + CARDEVICE_ACTMON = ((3 << 5) | 0x17), + CARDEVICE_BPMP = ((0 << 5) | 0x1) +} CarDevice; + +/* Clock/Reset Controller (CLK_RST_CONTROLLER_) regs */ +typedef struct { + uint32_t rst_src; /* _RST_SOURCE_0, 0x00 */ + + /* _RST_DEVICES_L/H/U_0 0x4-0xc */ + uint32_t rst_dev_l; + uint32_t rst_dev_h; + uint32_t rst_dev_u; + + /* _CLK_OUT_ENB_L/H/U_0 0x10-0x18 */ + uint32_t clk_out_enb_l; + uint32_t clk_out_enb_h; + uint32_t clk_out_enb_u; + + uint32_t _0x1C; + uint32_t cclk_brst_pol; /* _CCLK_BURST_POLICY_0, 0x20 */ + uint32_t super_cclk_div; /* _SUPER_CCLK_DIVIDER_0, 0x24 */ + uint32_t sclk_brst_pol; /* _SCLK_BURST_POLICY_0, 0x28 */ + uint32_t super_sclk_div; /* _SUPER_SCLK_DIVIDER_0, 0x2c */ + uint32_t clk_sys_rate; /* _CLK_SYSTEM_RATE_0, 0x30 */ + uint32_t prog_dly_clk; /* _PROG_DLY_CLK_0, 0x34 */ + uint32_t aud_sync_clk_rate; /* _AUDIO_SYNC_CLK_RATE_0, 0x38 */ + uint32_t _0x3C; + uint32_t cop_clk_skip_plcy; /* _COP_CLK_SKIP_POLICY_0, 0x40 */ + uint32_t clk_mask_arm; /* _CLK_MASK_ARM_0, 0x44 */ + uint32_t misc_clk_enb; /* _MISC_CLK_ENB_0, 0x48 */ + uint32_t clk_cpu_cmplx; /* _CLK_CPU_CMPLX_0, 0x4c */ + uint32_t osc_ctrl; /* _OSC_CTRL_0, 0x50 */ + uint32_t pll_lfsr; /* _PLL_LFSR_0, 0x54 */ + uint32_t osc_freq_det; /* _OSC_FREQ_DET_0, 0x58 */ + uint32_t osc_freq_det_stat; /* _OSC_FREQ_DET_STATUS_0, 0x5c */ + uint32_t _0x60[2]; + uint32_t plle_ss_cntl; /* _PLLE_SS_CNTL_0, 0x68 */ + uint32_t plle_misc1; /* _PLLE_MISC1_0, 0x6c */ + uint32_t _0x70[4]; + + /* PLLC 0x80-0x8c */ + uint32_t pllc_base; + uint32_t pllc_out; + uint32_t pllc_misc0; + uint32_t pllc_misc1; + + /* PLLM 0x90-0x9c */ + uint32_t pllm_base; + uint32_t pllm_out; + uint32_t pllm_misc1; + uint32_t pllm_misc2; + + /* PLLP 0xa0-0xac */ + uint32_t pllp_base; + uint32_t pllp_outa; + uint32_t pllp_outb; + uint32_t pllp_misc; + + /* PLLA 0xb0-0xbc */ + uint32_t plla_base; + uint32_t plla_out; + uint32_t plla_misc0; + uint32_t plla_misc1; + + /* PLLU 0xc0-0xcc */ + uint32_t pllu_base; + uint32_t pllu_out; + uint32_t pllu_misc1; + uint32_t pllu_misc2; + + /* PLLD 0xd0-0xdc */ + uint32_t plld_base; + uint32_t plld_out; + uint32_t plld_misc1; + uint32_t plld_misc2; + + /* PLLX 0xe0-0xe4 */ + uint32_t pllx_base; + uint32_t pllx_misc; + + /* PLLE 0xe8-0xf4 */ + uint32_t plle_base; + uint32_t plle_misc; + uint32_t plle_ss_cntl1; + uint32_t plle_ss_cntl2; + + uint32_t lvl2_clk_gate_ovra; /* _LVL2_CLK_GATE_OVRA_0, 0xf8 */ + uint32_t lvl2_clk_gate_ovrb; /* _LVL2_CLK_GATE_OVRB_0, 0xfc */ + + uint32_t clk_source_i2s2; /* _CLK_SOURCE_I2S2_0, 0x100 */ + uint32_t clk_source_i2s3; /* _CLK_SOURCE_I2S3_0, 0x104 */ + uint32_t clk_source_spdif_out; /* _CLK_SOURCE_SPDIF_OUT_0, 0x108 */ + uint32_t clk_source_spdif_in; /* _CLK_SOURCE_SPDIF_IN_0, 0x10c */ + uint32_t clk_source_pwm; /* _CLK_SOURCE_PWM_0, 0x110 */ + uint32_t _0x114; + uint32_t clk_source_spi2; /* _CLK_SOURCE_SPI2_0, 0x118 */ + uint32_t clk_source_spi3; /* _CLK_SOURCE_SPI3_0, 0x11c */ + uint32_t _0x120; + uint32_t clk_source_i2c1; /* _CLK_SOURCE_I2C1_0, 0x124 */ + uint32_t clk_source_i2c5; /* _CLK_SOURCE_I2C5_0, 0x128 */ + uint32_t _0x12c[2]; + uint32_t clk_source_spi1; /* _CLK_SOURCE_SPI1_0, 0x134 */ + uint32_t clk_source_disp1; /* _CLK_SOURCE_DISP1_0, 0x138 */ + uint32_t clk_source_disp2; /* _CLK_SOURCE_DISP2_0, 0x13c */ + uint32_t _0x140; + uint32_t clk_source_isp; /* _CLK_SOURCE_ISP_0, 0x144 */ + uint32_t clk_source_vi; /* _CLK_SOURCE_VI_0, 0x148 */ + uint32_t _0x14c; + uint32_t clk_source_sdmmc1; /* _CLK_SOURCE_SDMMC1_0, 0x150 */ + uint32_t clk_source_sdmmc2; /* _CLK_SOURCE_SDMMC2_0, 0x154 */ + uint32_t _0x158[3]; + uint32_t clk_source_sdmmc4; /* _CLK_SOURCE_SDMMC4_0, 0x164 */ + uint32_t _0x168[4]; + uint32_t clk_source_uarta; /* _CLK_SOURCE_UARTA_0, 0x178 */ + uint32_t clk_source_uartb; /* _CLK_SOURCE_UARTB_0, 0x17c */ + uint32_t clk_source_host1x; /* _CLK_SOURCE_HOST1X_0, 0x180 */ + uint32_t _0x184[5]; + uint32_t clk_source_i2c2; /* _CLK_SOURCE_I2C2_0, 0x198 */ + uint32_t clk_source_emc; /* _CLK_SOURCE_EMC_0, 0x19c */ + uint32_t clk_source_uartc; /* _CLK_SOURCE_UARTC_0, 0x1a0 */ + uint32_t _0x1a4; + uint32_t clk_source_vi_sensor; /* _CLK_SOURCE_VI_SENSOR_0, 0x1a8 */ + uint32_t _0x1ac[2]; + uint32_t clk_source_spi4; /* _CLK_SOURCE_SPI4_0, 0x1b4 */ + uint32_t clk_source_i2c3; /* _CLK_SOURCE_I2C3_0, 0x1b8 */ + uint32_t clk_source_sdmmc3; /* _CLK_SOURCE_SDMMC3_0, 0x1bc */ + uint32_t clk_source_uartd; /* _CLK_SOURCE_UARTD_0, 0x1c0 */ + uint32_t _0x1c4[2]; + uint32_t clk_source_owr; /* _CLK_SOURCE_OWR_0, 0x1cc */ + uint32_t _0x1d0; + uint32_t clk_source_csite; /* _CLK_SOURCE_CSITE_0, 0x1d4 */ + uint32_t clk_source_i2s1; /* _CLK_SOURCE_I2S1_0, 0x1d8 */ + uint32_t clk_source_dtv; /* _CLK_SOURCE_DTV_0, 0x1dc */ + uint32_t _0x1e0[5]; + uint32_t clk_source_tsec; /* _CLK_SOURCE_TSEC_0, 0x1f4 */ + uint32_t _0x1f8; + + uint32_t clk_spare2; /* _CLK_SPARE2_0, 0x1fc */ + uint32_t _0x200[32]; + + uint32_t clk_out_enb_x; /* _CLK_OUT_ENB_X_0, 0x280 */ + uint32_t clk_enb_x_set; /* _CLK_ENB_X_SET_0, 0x284 */ + uint32_t clk_enb_x_clr; /* _CLK_ENB_X_CLR_0, 0x288 */ + + uint32_t rst_devices_x; /* _RST_DEVICES_X_0, 0x28c */ + uint32_t rst_dev_x_set; /* _RST_DEV_X_SET_0, 0x290 */ + uint32_t rst_dev_x_clr; /* _RST_DEV_X_CLR_0, 0x294 */ + + uint32_t clk_out_enb_y; /* _CLK_OUT_ENB_Y_0, 0x298 */ + uint32_t clk_enb_y_set; /* _CLK_ENB_Y_SET_0, 0x29c */ + uint32_t clk_enb_y_clr; /* _CLK_ENB_Y_CLR_0, 0x2a0 */ + + uint32_t rst_devices_y; /* _RST_DEVICES_Y_0, 0x2a4 */ + uint32_t rst_dev_y_set; /* _RST_DEV_Y_SET_0, 0x2a8 */ + uint32_t rst_dev_y_clr; /* _RST_DEV_Y_CLR_0, 0x2ac */ + + uint32_t _0x2b0[17]; + uint32_t dfll_base; /* _DFLL_BASE_0, 0x2f4 */ + uint32_t _0x2f8[2]; + + /* _RST_DEV_L/H/U_SET_0 0x300-0x314 */ + uint32_t rst_dev_l_set; + uint32_t rst_dev_l_clr; + uint32_t rst_dev_h_set; + uint32_t rst_dev_h_clr; + uint32_t rst_dev_u_set; + uint32_t rst_dev_u_clr; + + uint32_t _0x318[2]; + + /* _CLK_ENB_L/H/U_CLR_0 0x320-0x334 */ + uint32_t clk_enb_l_set; + uint32_t clk_enb_l_clr; + uint32_t clk_enb_h_set; + uint32_t clk_enb_h_clr; + uint32_t clk_enb_u_set; + uint32_t clk_enb_u_clr; + + uint32_t _0x338; + uint32_t ccplex_pg_sm_ovrd; /* _CCPLEX_PG_SM_OVRD_0, 0x33c */ + uint32_t rst_cpu_cmplx_set; /* _RST_CPU_CMPLX_SET_0, 0x340 */ + uint32_t rst_cpu_cmplx_clr; /* _RST_CPU_CMPLX_CLR_0, 0x344 */ + + /* Additional (T30) registers */ + uint32_t clk_cpu_cmplx_set; /* _CLK_CPU_CMPLX_SET_0, 0x348 */ + uint32_t clk_cpu_cmplx_clr; /* _CLK_CPU_CMPLX_SET_0, 0x34c */ + + uint32_t _0x350[2]; + uint32_t rst_dev_v; /* _RST_DEVICES_V_0, 0x358 */ + uint32_t rst_dev_w; /* _RST_DEVICES_W_0, 0x35c */ + uint32_t clk_out_enb_v; /* _CLK_OUT_ENB_V_0, 0x360 */ + uint32_t clk_out_enb_w; /* _CLK_OUT_ENB_W_0, 0x364 */ + uint32_t cclkg_brst_pol; /* _CCLKG_BURST_POLICY_0, 0x368 */ + uint32_t super_cclkg_div; /* _SUPER_CCLKG_DIVIDER_0, 0x36c */ + uint32_t cclklp_brst_pol; /* _CCLKLP_BURST_POLICY_0, 0x370 */ + uint32_t super_cclkp_div; /* _SUPER_CCLKLP_DIVIDER_0, 0x374 */ + uint32_t clk_cpug_cmplx; /* _CLK_CPUG_CMPLX_0, 0x378 */ + uint32_t clk_cpulp_cmplx; /* _CLK_CPULP_CMPLX_0, 0x37c */ + uint32_t cpu_softrst_ctrl; /* _CPU_SOFTRST_CTRL_0, 0x380 */ + uint32_t cpu_softrst_ctrl1; /* _CPU_SOFTRST_CTRL1_0, 0x384 */ + uint32_t cpu_softrst_ctrl2; /* _CPU_SOFTRST_CTRL2_0, 0x388 */ + uint32_t _0x38c[5]; + uint32_t lvl2_clk_gate_ovrc; /* _LVL2_CLK_GATE_OVRC, 0x3a0 */ + uint32_t lvl2_clk_gate_ovrd; /* _LVL2_CLK_GATE_OVRD, 0x3a4 */ + uint32_t _0x3a8[2]; + + uint32_t _0x3b0; + uint32_t clk_source_mselect; /* _CLK_SOURCE_MSELECT_0, 0x3b4 */ + uint32_t clk_source_tsensor; /* _CLK_SOURCE_TSENSOR_0, 0x3b8 */ + uint32_t clk_source_i2s4; /* _CLK_SOURCE_I2S4_0, 0x3bc */ + uint32_t clk_source_i2s5; /* _CLK_SOURCE_I2S5_0, 0x3c0 */ + uint32_t clk_source_i2c4; /* _CLK_SOURCE_I2C4_0, 0x3c4 */ + uint32_t _0x3c8[2]; + uint32_t clk_source_ahub; /* _CLK_SOURCE_AHUB_0, 0x3d0 */ + uint32_t _0x3d4[4]; + uint32_t clk_source_hda2codec_2x; /* _CLK_SOURCE_HDA2CODEC_2X_0, 0x3e4 */ + uint32_t clk_source_actmon; /* _CLK_SOURCE_ACTMON_0, 0x3e8 */ + uint32_t clk_source_extperiph1; /* _CLK_SOURCE_EXTPERIPH1_0, 0x3ec */ + uint32_t clk_source_extperiph2; /* _CLK_SOURCE_EXTPERIPH2_0, 0x3f0 */ + uint32_t clk_source_extperiph3; /* _CLK_SOURCE_EXTPERIPH3_0, 0x3f4 */ + uint32_t _0x3f8; + uint32_t clk_source_i2c_slow; /* _CLK_SOURCE_I2C_SLOW_0, 0x3fc */ + uint32_t clk_source_sys; /* _CLK_SOURCE_SYS_0, 0x400 */ + uint32_t clk_source_ispb; /* _CLK_SOURCE_ISPB_0, 0x404 */ + uint32_t _0x408[2]; + uint32_t clk_source_sor1; /* _CLK_SOURCE_SOR1_0, 0x410 */ + uint32_t clk_source_sor0; /* _CLK_SOURCE_SOR0_0, 0x414 */ + uint32_t _0x418[2]; + uint32_t clk_source_sata_oob; /* _CLK_SOURCE_SATA_OOB_0, 0x420 */ + uint32_t clk_source_sata; /* _CLK_SOURCE_SATA_0, 0x424 */ + uint32_t clk_source_hda; /* _CLK_SOURCE_HDA_0, 0x428 */ + uint32_t _0x42c; + + /* _RST_DEV_V/W_SET_0 0x430-0x43c */ + uint32_t rst_dev_v_set; + uint32_t rst_dev_v_clr; + uint32_t rst_dev_w_set; + uint32_t rst_dev_w_clr; + + /* _CLK_ENB_V/W_CLR_0 0x440-0x44c */ + uint32_t clk_enb_v_set; + uint32_t clk_enb_v_clr; + uint32_t clk_enb_w_set; + uint32_t clk_enb_w_clr; + + /* Additional (T114+) registers */ + uint32_t rst_cpug_cmplx_set; /* _RST_CPUG_CMPLX_SET_0, 0x450 */ + uint32_t rst_cpug_cmplx_clr; /* _RST_CPUG_CMPLX_CLR_0, 0x454 */ + uint32_t rst_cpulp_cmplx_set; /* _RST_CPULP_CMPLX_SET_0, 0x458 */ + uint32_t rst_cpulp_cmplx_clr; /* _RST_CPULP_CMPLX_CLR_0, 0x45c */ + uint32_t clk_cpug_cmplx_set; /* _CLK_CPUG_CMPLX_SET_0, 0x460 */ + uint32_t clk_cpug_cmplx_clr; /* _CLK_CPUG_CMPLX_CLR_0, 0x464 */ + uint32_t clk_cpulp_cmplx_set; /* _CLK_CPULP_CMPLX_SET_0, 0x468 */ + uint32_t clk_cpulp_cmplx_clr; /* _CLK_CPULP_CMPLX_CLR_0, 0x46c */ + uint32_t cpu_cmplx_status; /* _CPU_CMPLX_STATUS_0, 0x470 */ + uint32_t _0x474; + uint32_t intstatus; /* _INTSTATUS_0, 0x478 */ + uint32_t intmask; /* _INTMASK_0, 0x47c */ + uint32_t utmip_pll_cfg0; /* _UTMIP_PLL_CFG0_0, 0x480 */ + uint32_t utmip_pll_cfg1; /* _UTMIP_PLL_CFG1_0, 0x484 */ + uint32_t utmip_pll_cfg2; /* _UTMIP_PLL_CFG2_0, 0x488 */ + + uint32_t plle_aux; /* _PLLE_AUX_0, 0x48c */ + uint32_t sata_pll_cfg0; /* _SATA_PLL_CFG0_0, 0x490 */ + uint32_t sata_pll_cfg1; /* _SATA_PLL_CFG1_0, 0x494 */ + uint32_t pcie_pll_cfg0; /* _PCIE_PLL_CFG0_0, 0x498 */ + + uint32_t prog_audio_dly_clk; /* _PROG_AUDIO_DLY_CLK_0, 0x49c */ + uint32_t audio_sync_clk_i2s0; /* _AUDIO_SYNC_CLK_I2S0_0, 0x4a0 */ + uint32_t audio_sync_clk_i2s1; /* _AUDIO_SYNC_CLK_I2S1_0, 0x4a4 */ + uint32_t audio_sync_clk_i2s2; /* _AUDIO_SYNC_CLK_I2S2_0, 0x4a8 */ + uint32_t audio_sync_clk_i2s3; /* _AUDIO_SYNC_CLK_I2S3_0, 0x4ac */ + uint32_t audio_sync_clk_i2s4; /* _AUDIO_SYNC_CLK_I2S4_0, 0x4b0 */ + uint32_t audio_sync_clk_spdif; /* _AUDIO_SYNC_CLK_SPDIF_0, 0x4b4 */ + + uint32_t plld2_base; /* _PLLD2_BASE_0, 0x4b8 */ + uint32_t plld2_misc; /* _PLLD2_MISC_0, 0x4bc */ + uint32_t utmip_pll_cfg3; /* _UTMIP_PLL_CFG3_0, 0x4c0 */ + uint32_t pllrefe_base; /* _PLLREFE_BASE_0, 0x4c4 */ + uint32_t pllrefe_misc; /* _PLLREFE_MISC_0, 0x4c8 */ + uint32_t pllrefe_out; /* _PLLREFE_OUT_0, 0x4cc */ + uint32_t cpu_finetrim_byp; /* _CPU_FINETRIM_BYP_0, 0x4d0 */ + uint32_t cpu_finetrim_select; /* _CPU_FINETRIM_SELECT_0, 0x4d4 */ + uint32_t cpu_finetrim_dr; /* _CPU_FINETRIM_DR_0, 0x4d8 */ + uint32_t cpu_finetrim_df; /* _CPU_FINETRIM_DF_0, 0x4dc */ + uint32_t cpu_finetrim_f; /* _CPU_FINETRIM_F_0, 0x4e0 */ + uint32_t cpu_finetrim_r; /* _CPU_FINETRIM_R_0, 0x4e4 */ + uint32_t pllc2_base; /* _PLLC2_BASE_0, 0x4e8 */ + uint32_t pllc2_misc0; /* _PLLC2_MISC_0_0, 0x4ec */ + uint32_t pllc2_misc1; /* _PLLC2_MISC_1_0, 0x4f0 */ + uint32_t pllc2_misc2; /* _PLLC2_MISC_2_0, 0x4f4 */ + uint32_t pllc2_misc3; /* _PLLC2_MISC_3_0, 0x4f8 */ + uint32_t pllc3_base; /* _PLLC3_BASE_0, 0x4fc */ + uint32_t pllc3_misc0; /* _PLLC3_MISC_0_0, 0x500 */ + uint32_t pllc3_misc1; /* _PLLC3_MISC_1_0, 0x504 */ + uint32_t pllc3_misc2; /* _PLLC3_MISC_2_0, 0x508 */ + uint32_t pllc3_misc3; /* _PLLC3_MISC_3_0, 0x50c */ + uint32_t pllx_misc1; /* _PLLX_MISC_1_0, 0x510 */ + uint32_t pllx_misc2; /* _PLLX_MISC_2_0, 0x514 */ + uint32_t pllx_misc3; /* _PLLX_MISC_3_0, 0x518 */ + uint32_t xusbio_pll_cfg0; /* _XUSBIO_PLL_CFG0_0, 0x51c */ + uint32_t xusbio_pll_cfg1; /* _XUSBIO_PLL_CFG0_1, 0x520 */ + uint32_t plle_aux1; /* _PLLE_AUX1_0, 0x524 */ + uint32_t pllp_reshift; /* _PLLP_RESHIFT_0, 0x528 */ + uint32_t utmipll_hw_pwrdn_cfg0; /* _UTMIPLL_HW_PWRDN_CFG0_0, 0x52c */ + uint32_t pllu_hw_pwrdn_cfg0; /* _PLLU_HW_PWRDN_CFG0_0, 0x530 */ + uint32_t xusb_pll_cfg0; /* _XUSB_PLL_CFG0_0, 0x534 */ + uint32_t _0x538; + uint32_t clk_cpu_misc; /* _CLK_CPU_MISC_0, 0x53c */ + uint32_t clk_cpug_misc; /* _CLK_CPUG_MISC_0, 0x540 */ + uint32_t clk_cpulp_misc; /* _CLK_CPULP_MISC_0, 0x544 */ + uint32_t pllx_hw_ctrl_cfg; /* _PLLX_HW_CTRL_CFG_0, 0x548 */ + uint32_t pllx_sw_ramp_cfg; /* _PLLX_SW_RAMP_CFG_0, 0x54c */ + uint32_t pllx_hw_ctrl_status; /* _PLLX_HW_CTRL_STATUS_0, 0x550 */ + uint32_t lvl2_clk_gate_ovre; /* _LVL2_CLK_GATE_OVRE, 0x554 */ + uint32_t super_gr3d_clk_div; /* _SUPER_GR3D_CLK_DIVIDER_0, 0x558 */ + uint32_t spare_reg0; /* _SPARE_REG0_0, 0x55c */ + uint32_t audio_sync_clk_dmic1; /* _AUDIO_SYNC_CLK_DMIC1_0, 0x560 */ + uint32_t audio_sync_clk_dmic2; /* _AUDIO_SYNC_CLK_DMIC2_0, 0x564 */ + + uint32_t _0x568[2]; + uint32_t plld2_ss_cfg; /* _PLLD2_SS_CFG, 0x570 */ + uint32_t plld2_ss_ctrl1; /* _PLLD2_SS_CTRL1_0, 0x574 */ + uint32_t plld2_ss_ctrl2; /* _PLLD2_SS_CTRL2_0, 0x578 */ + uint32_t _0x57c[5]; + + uint32_t plldp_base; /* _PLLDP_BASE, 0x590*/ + uint32_t plldp_misc; /* _PLLDP_MISC, 0x594 */ + uint32_t plldp_ss_cfg; /* _PLLDP_SS_CFG, 0x598 */ + uint32_t plldp_ss_ctrl1; /* _PLLDP_SS_CTRL1_0, 0x59c */ + uint32_t plldp_ss_ctrl2; /* _PLLDP_SS_CTRL2_0, 0x5a0 */ + uint32_t pllc4_base; /* _PLLC4_BASE_0, 0x5a4 */ + uint32_t pllc4_misc; /* _PLLC4_MISC_0, 0x5a8 */ + uint32_t _0x5ac[6]; + uint32_t clk_spare0; /* _CLK_SPARE0_0, 0x5c4 */ + uint32_t clk_spare1; /* _CLK_SPARE1_0, 0x5c8 */ + uint32_t gpu_isob_ctrl; /* _GPU_ISOB_CTRL_0, 0x5cc */ + uint32_t pllc_misc2; /* _PLLC_MISC_2_0, 0x5d0 */ + uint32_t pllc_misc3; /* _PLLC_MISC_3_0, 0x5d4 */ + uint32_t plla_misc2; /* _PLLA_MISC2_0, 0x5d8 */ + uint32_t _0x5dc[2]; + uint32_t pllc4_out; /* _PLLC4_OUT_0, 0x5e4 */ + uint32_t pllmb_base; /* _PLLMB_BASE_0, 0x5e8 */ + uint32_t pllmb_misc1; /* _PLLMB_MISC1_0, 0x5ec */ + uint32_t pllx_misc4; /* _PLLX_MISC_4_0, 0x5f0 */ + uint32_t pllx_misc5; /* _PLLX_MISC_5_0, 0x5f4 */ + uint32_t _0x5f8[2]; + + uint32_t clk_source_xusb_core_host; /* _CLK_SOURCE_XUSB_CORE_HOST_0, 0x600 */ + uint32_t clk_source_xusb_falcon; /* _CLK_SOURCE_XUSB_FALCON_0, 0x604 */ + uint32_t clk_source_xusb_fs; /* _CLK_SOURCE_XUSB_FS_0, 0x608 */ + uint32_t clk_source_xusb_core_dev; /* _CLK_SOURCE_XUSB_CORE_DEV_0, 0x60c */ + uint32_t clk_source_xusb_ss; /* _CLK_SOURCE_XUSB_SS_0, 0x610 */ + uint32_t clk_source_cilab; /* _CLK_SOURCE_CILAB_0, 0x614 */ + uint32_t clk_source_cilcd; /* _CLK_SOURCE_CILCD_0, 0x618 */ + uint32_t clk_source_cilef; /* _CLK_SOURCE_CILEF_0, 0x61c */ + uint32_t clk_source_dsia_lp; /* _CLK_SOURCE_DSIA_LP_0, 0x620 */ + uint32_t clk_source_dsib_lp; /* _CLK_SOURCE_DSIB_LP_0, 0x624 */ + uint32_t clk_source_entropy; /* _CLK_SOURCE_ENTROPY_0, 0x628 */ + uint32_t clk_source_dvfs_ref; /* _CLK_SOURCE_DVFS_REF_0, 0x62c */ + uint32_t clk_source_dvfs_soc; /* _CLK_SOURCE_DVFS_SOC_0, 0x630 */ + uint32_t _0x634[3]; + uint32_t clk_source_emc_latency; /* _CLK_SOURCE_EMC_LATENCY_0, 0x640 */ + uint32_t clk_source_soc_therm; /* _CLK_SOURCE_SOC_THERM_0, 0x644 */ + uint32_t _0x648; + uint32_t clk_source_dmic1; /* _CLK_SOURCE_DMIC1_0, 0x64c */ + uint32_t clk_source_dmic2; /* _CLK_SOURCE_DMIC2_0, 0x650 */ + uint32_t _0x654; + uint32_t clk_source_vi_sensor2; /* _CLK_SOURCE_VI_SENSOR2_0, 0x658 */ + uint32_t clk_source_i2c6; /* _CLK_SOURCE_I2C6_0, 0x65c */ + uint32_t clk_source_mipibif; /* _CLK_SOURCE_MIPIBIF_0, 0x660 */ + uint32_t clk_source_emc_dll; /* _CLK_SOURCE_EMC_DLL_0, 0x664 */ + uint32_t _0x668; + uint32_t clk_source_uart_fst_mipi_cal; /* _CLK_SOURCE_UART_FST_MIPI_CAL_0, 0x66c */ + uint32_t _0x670[2]; + uint32_t clk_source_vic; /* _CLK_SOURCE_VIC_0, 0x678 */ + + uint32_t pllp_outc; /* _PLLP_OUTC_0, 0x67c */ + uint32_t pllp_misc1; /* _PLLP_MISC1_0, 0x680 */ + uint32_t _0x684[2]; + uint32_t emc_div_clk_shaper_ctrl; /* _EMC_DIV_CLK_SHAPER_CTRL_0, 0x68c */ + uint32_t emc_pllc_shaper_ctrl; /* _EMC_PLLC_SHAPER_CTRL_0, 0x690 */ + + uint32_t clk_source_sdmmc_legacy_tm; /* _CLK_SOURCE_SDMMC_LEGACY_TM_0, 0x694 */ + uint32_t clk_source_nvdec; /* _CLK_SOURCE_NVDEC_0, 0x698 */ + uint32_t clk_source_nvjpg; /* _CLK_SOURCE_NVJPG_0, 0x69c */ + uint32_t clk_source_nvenc; /* _CLK_SOURCE_NVENC_0, 0x6a0 */ + + uint32_t plla1_base; /* _PLLA1_BASE_0, 0x6a4 */ + uint32_t plla1_misc0; /* _PLLA1_MISC_0_0, 0x6a8 */ + uint32_t plla1_misc1; /* _PLLA1_MISC_1_0, 0x6ac */ + uint32_t plla1_misc2; /* _PLLA1_MISC_2_0, 0x6b0 */ + uint32_t plla1_misc3; /* _PLLA1_MISC_3_0, 0x6b4 */ + uint32_t audio_sync_clk_dmic3; /* _AUDIO_SYNC_CLK_DMIC3_0, 0x6b8 */ + + uint32_t clk_source_dmic3; /* _CLK_SOURCE_DMIC3_0, 0x6bc */ + uint32_t clk_source_ape; /* _CLK_SOURCE_APE_0, 0x6c0 */ + uint32_t clk_source_qspi; /* _CLK_SOURCE_QSPI_0, 0x6c4 */ + uint32_t clk_source_vi_i2c; /* _CLK_SOURCE_VI_I2C_0, 0x6c8 */ + uint32_t clk_source_usb2_hsic_trk; /* _CLK_SOURCE_USB2_HSIC_TRK_0, 0x6cc */ + uint32_t clk_source_pex_sata_usb_rx_byp; /* _CLK_SOURCE_PEX_SATA_USB_RX_BYP_0, 0x6d0 */ + uint32_t clk_source_maud; /* _CLK_SOURCE_MAUD_0, 0x6d4 */ + uint32_t clk_source_tsecb; /* _CLK_SOURCE_TSECB_0, 0x6d8 */ + + uint32_t clk_cpug_misc1; /* _CLK_CPUG_MISC1_0, 0x6dc */ + uint32_t aclk_burst_policy; /* _ACLK_BURST_POLICY_0, 0x6e0 */ + uint32_t super_aclk_divider; /* _SUPER_ACLK_DIVIDER_0, 0x6e4 */ + + uint32_t nvenc_super_clk_divider; /* _NVENC_SUPER_CLK_DIVIDER_0, 0x6e8 */ + uint32_t vi_super_clk_divider; /* _VI_SUPER_CLK_DIVIDER_0, 0x6ec */ + uint32_t vic_super_clk_divider; /* _VIC_SUPER_CLK_DIVIDER_0, 0x6f0 */ + uint32_t nvdec_super_clk_divider; /* _NVDEC_SUPER_CLK_DIVIDER_0, 0x6f4 */ + uint32_t isp_super_clk_divider; /* _ISP_SUPER_CLK_DIVIDER_0, 0x6f8 */ + uint32_t ispb_super_clk_divider; /* _ISPB_SUPER_CLK_DIVIDER_0, 0x6fc */ + uint32_t nvjpg_super_clk_divider; /* _NVJPG_SUPER_CLK_DIVIDER_0, 0x700 */ + uint32_t se_super_clk_divider; /* _SE_SUPER_CLK_DIVIDER_0, 0x704 */ + uint32_t tsec_super_clk_divider; /* _TSEC_SUPER_CLK_DIVIDER_0, 0x708 */ + uint32_t tsecb_super_clk_divider; /* _TSECB_SUPER_CLK_DIVIDER_0, 0x70c */ + + uint32_t clk_source_uartape; /* _CLK_SOURCE_UARTAPE_0, 0x710 */ + uint32_t clk_cpug_misc2; /* _CLK_CPUG_MISC2_0, 0x714 */ + uint32_t clk_source_dbgapb; /* _CLK_SOURCE_DBGAPB_0, 0x718 */ + uint32_t clk_ccplex_cc4_ret_clk_enb; /* _CLK_CCPLEX_CC4_RET_CLK_ENB_0, 0x71c */ + uint32_t actmon_cpu_clk; /* _ACTMON_CPU_CLK_0, 0x720 */ + uint32_t clk_source_emc_safe; /* _CLK_SOURCE_EMC_SAFE_0, 0x724 */ + uint32_t sdmmc2_pllc4_out0_shaper_ctrl; /* _SDMMC2_PLLC4_OUT0_SHAPER_CTRL_0, 0x728 */ + uint32_t sdmmc2_pllc4_out1_shaper_ctrl; /* _SDMMC2_PLLC4_OUT1_SHAPER_CTRL_0, 0x72c */ + uint32_t sdmmc2_pllc4_out2_shaper_ctrl; /* _SDMMC2_PLLC4_OUT2_SHAPER_CTRL_0, 0x730 */ + uint32_t sdmmc2_div_clk_shaper_ctrl; /* _SDMMC2_DIV_CLK_SHAPER_CTRL_0, 0x734 */ + uint32_t sdmmc4_pllc4_out0_shaper_ctrl; /* _SDMMC4_PLLC4_OUT0_SHAPER_CTRL_0, 0x738 */ + uint32_t sdmmc4_pllc4_out1_shaper_ctrl; /* _SDMMC4_PLLC4_OUT1_SHAPER_CTRL_0, 0x73c */ + uint32_t sdmmc4_pllc4_out2_shaper_ctrl; /* _SDMMC4_PLLC4_OUT2_SHAPER_CTRL_0, 0x740 */ + uint32_t sdmmc4_div_clk_shaper_ctrl; /* _SDMMC4_DIV_CLK_SHAPER_CTRL_0, 0x744 */ +} tegra_car_t; + +static inline volatile tegra_car_t *car_get_regs(void) { + return (volatile tegra_car_t *)CAR_BASE; +} + +void clk_enable(CarDevice dev); +void clk_disable(CarDevice dev); +void rst_enable(CarDevice dev); +void rst_disable(CarDevice dev); + +void clkrst_enable(CarDevice dev); +void clkrst_disable(CarDevice dev); +void clkrst_reboot(CarDevice dev); + +void clkrst_enable_fuse_regs(bool enable); + +#endif diff --git a/sept/sept-primary/src/di.h b/sept/sept-primary/src/di.h new file mode 100644 index 000000000..cf48dcc66 --- /dev/null +++ b/sept/sept-primary/src/di.h @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 CTCaer + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef FUSEE_DI_H_ +#define FUSEE_DI_H_ + +#include +#include + +#define HOST1X_BASE 0x50000000 +#define DI_BASE 0x54200000 +#define DSI_BASE 0x54300000 +#define VIC_BASE 0x54340000 +#define MIPI_CAL_BASE 0x700E3000 +#define MAKE_HOST1X_REG(n) MAKE_REG32(HOST1X_BASE + n) +#define MAKE_DI_REG(n) MAKE_REG32(DI_BASE + n * 4) +#define MAKE_DSI_REG(n) MAKE_REG32(DSI_BASE + n * 4) +#define MAKE_MIPI_CAL_REG(n) MAKE_REG32(MIPI_CAL_BASE + n) +#define MAKE_VIC_REG(n) MAKE_REG32(VIC_BASE + n) + +/* Display registers. */ +#define DC_CMD_GENERAL_INCR_SYNCPT 0x00 + +#define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x01 +#define SYNCPT_CNTRL_NO_STALL (1 << 8) +#define SYNCPT_CNTRL_SOFT_RESET (1 << 0) + +#define DC_CMD_CONT_SYNCPT_VSYNC 0x28 +#define SYNCPT_VSYNC_ENABLE (1 << 8) + +#define DC_CMD_DISPLAY_COMMAND_OPTION0 0x031 + +#define DC_CMD_DISPLAY_COMMAND 0x32 +#define DISP_CTRL_MODE_STOP (0 << 5) +#define DISP_CTRL_MODE_C_DISPLAY (1 << 5) +#define DISP_CTRL_MODE_NC_DISPLAY (2 << 5) +#define DISP_CTRL_MODE_MASK (3 << 5) + +#define DC_CMD_DISPLAY_POWER_CONTROL 0x36 +#define PW0_ENABLE (1 << 0) +#define PW1_ENABLE (1 << 2) +#define PW2_ENABLE (1 << 4) +#define PW3_ENABLE (1 << 6) +#define PW4_ENABLE (1 << 8) +#define PM0_ENABLE (1 << 16) +#define PM1_ENABLE (1 << 18) + +#define DC_CMD_INT_MASK 0x38 +#define DC_CMD_INT_ENABLE 0x39 + +#define DC_CMD_STATE_ACCESS 0x40 +#define READ_MUX (1 << 0) +#define WRITE_MUX (1 << 2) + +#define DC_CMD_STATE_CONTROL 0x41 +#define GENERAL_ACT_REQ (1 << 0) +#define WIN_A_ACT_REQ (1 << 1) +#define WIN_B_ACT_REQ (1 << 2) +#define WIN_C_ACT_REQ (1 << 3) +#define CURSOR_ACT_REQ (1 << 7) +#define GENERAL_UPDATE (1 << 8) +#define WIN_A_UPDATE (1 << 9) +#define WIN_B_UPDATE (1 << 10) +#define WIN_C_UPDATE (1 << 11) +#define CURSOR_UPDATE (1 << 15) +#define NC_HOST_TRIG (1 << 24) + +#define DC_CMD_DISPLAY_WINDOW_HEADER 0x42 +#define WINDOW_A_SELECT (1 << 4) +#define WINDOW_B_SELECT (1 << 5) +#define WINDOW_C_SELECT (1 << 6) + +#define DC_CMD_REG_ACT_CONTROL 0x043 + +#define DC_COM_CRC_CONTROL 0x300 +#define DC_COM_PIN_OUTPUT_ENABLE(x) (0x302 + (x)) +#define DC_COM_PIN_OUTPUT_POLARITY(x) (0x306 + (x)) + +#define DC_COM_DSC_TOP_CTL 0x33E + +#define DC_DISP_DISP_WIN_OPTIONS 0x402 +#define HDMI_ENABLE (1 << 30) +#define DSI_ENABLE (1 << 29) +#define SOR1_TIMING_CYA (1 << 27) +#define SOR1_ENABLE (1 << 26) +#define SOR_ENABLE (1 << 25) +#define CURSOR_ENABLE (1 << 16) + +#define DC_DISP_DISP_MEM_HIGH_PRIORITY 0x403 +#define DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER 0x404 +#define DC_DISP_DISP_TIMING_OPTIONS 0x405 +#define DC_DISP_REF_TO_SYNC 0x406 +#define DC_DISP_SYNC_WIDTH 0x407 +#define DC_DISP_BACK_PORCH 0x408 +#define DC_DISP_ACTIVE 0x409 +#define DC_DISP_FRONT_PORCH 0x40A + +#define DC_DISP_DISP_CLOCK_CONTROL 0x42E +#define PIXEL_CLK_DIVIDER_PCD1 (0 << 8) +#define PIXEL_CLK_DIVIDER_PCD1H (1 << 8) +#define PIXEL_CLK_DIVIDER_PCD2 (2 << 8) +#define PIXEL_CLK_DIVIDER_PCD3 (3 << 8) +#define PIXEL_CLK_DIVIDER_PCD4 (4 << 8) +#define PIXEL_CLK_DIVIDER_PCD6 (5 << 8) +#define PIXEL_CLK_DIVIDER_PCD8 (6 << 8) +#define PIXEL_CLK_DIVIDER_PCD9 (7 << 8) +#define PIXEL_CLK_DIVIDER_PCD12 (8 << 8) +#define PIXEL_CLK_DIVIDER_PCD16 (9 << 8) +#define PIXEL_CLK_DIVIDER_PCD18 (10 << 8) +#define PIXEL_CLK_DIVIDER_PCD24 (11 << 8) +#define PIXEL_CLK_DIVIDER_PCD13 (12 << 8) +#define SHIFT_CLK_DIVIDER(x) ((x) & 0xff) + +#define DC_DISP_DISP_INTERFACE_CONTROL 0x42F +#define DISP_DATA_FORMAT_DF1P1C (0 << 0) +#define DISP_DATA_FORMAT_DF1P2C24B (1 << 0) +#define DISP_DATA_FORMAT_DF1P2C18B (2 << 0) +#define DISP_DATA_FORMAT_DF1P2C16B (3 << 0) +#define DISP_DATA_FORMAT_DF2S (4 << 0) +#define DISP_DATA_FORMAT_DF3S (5 << 0) +#define DISP_DATA_FORMAT_DFSPI (6 << 0) +#define DISP_DATA_FORMAT_DF1P3C24B (7 << 0) +#define DISP_DATA_FORMAT_DF1P3C18B (8 << 0) +#define DISP_ALIGNMENT_MSB (0 << 8) +#define DISP_ALIGNMENT_LSB (1 << 8) +#define DISP_ORDER_RED_BLUE (0 << 9) +#define DISP_ORDER_BLUE_RED (1 << 9) + +#define DC_DISP_DISP_COLOR_CONTROL 0x430 +#define DITHER_CONTROL_MASK (3 << 8) +#define DITHER_CONTROL_DISABLE (0 << 8) +#define DITHER_CONTROL_ORDERED (2 << 8) +#define DITHER_CONTROL_ERRDIFF (3 << 8) +#define BASE_COLOR_SIZE_MASK (0xf << 0) +#define BASE_COLOR_SIZE_666 (0 << 0) +#define BASE_COLOR_SIZE_111 (1 << 0) +#define BASE_COLOR_SIZE_222 (2 << 0) +#define BASE_COLOR_SIZE_333 (3 << 0) +#define BASE_COLOR_SIZE_444 (4 << 0) +#define BASE_COLOR_SIZE_555 (5 << 0) +#define BASE_COLOR_SIZE_565 (6 << 0) +#define BASE_COLOR_SIZE_332 (7 << 0) +#define BASE_COLOR_SIZE_888 (8 << 0) + +#define DC_DISP_SHIFT_CLOCK_OPTIONS 0x431 +#define SC1_H_QUALIFIER_NONE (1 << 16) +#define SC0_H_QUALIFIER_NONE (1 << 0) + +#define DC_DISP_DATA_ENABLE_OPTIONS 0x432 +#define DE_SELECT_ACTIVE_BLANK (0 << 0) +#define DE_SELECT_ACTIVE (1 << 0) +#define DE_SELECT_ACTIVE_IS (2 << 0) +#define DE_CONTROL_ONECLK (0 << 2) +#define DE_CONTROL_NORMAL (1 << 2) +#define DE_CONTROL_EARLY_EXT (2 << 2) +#define DE_CONTROL_EARLY (3 << 2) +#define DE_CONTROL_ACTIVE_BLANK (4 << 2) + +#define DC_DISP_DC_MCCIF_FIFOCTRL 0x480 +#define DC_DISP_BLEND_BACKGROUND_COLOR 0x4E4 + +#define DC_WIN_CSC_YOF 0x611 +#define DC_WIN_CSC_KYRGB 0x612 +#define DC_WIN_CSC_KUR 0x613 +#define DC_WIN_CSC_KVR 0x614 +#define DC_WIN_CSC_KUG 0x615 +#define DC_WIN_CSC_KVG 0x616 +#define DC_WIN_CSC_KUB 0x617 +#define DC_WIN_CSC_KVB 0x618 +#define DC_WIN_AD_WIN_OPTIONS 0xB80 +#define DC_WIN_BD_WIN_OPTIONS 0xD80 +#define DC_WIN_CD_WIN_OPTIONS 0xF80 + +/* The following registers are A/B/C shadows of the 0xB80/0xD80/0xF80 registers (see DISPLAY_WINDOW_HEADER). */ +#define DC_WIN_WIN_OPTIONS 0x700 +#define H_DIRECTION (1 << 0) +#define V_DIRECTION (1 << 2) +#define COLOR_EXPAND (1 << 6) +#define CSC_ENABLE (1 << 18) +#define WIN_ENABLE (1 << 30) + +#define DC_WIN_COLOR_DEPTH 0x703 +#define WIN_COLOR_DEPTH_P1 0x0 +#define WIN_COLOR_DEPTH_P2 0x1 +#define WIN_COLOR_DEPTH_P4 0x2 +#define WIN_COLOR_DEPTH_P8 0x3 +#define WIN_COLOR_DEPTH_B4G4R4A4 0x4 +#define WIN_COLOR_DEPTH_B5G5R5A 0x5 +#define WIN_COLOR_DEPTH_B5G6R5 0x6 +#define WIN_COLOR_DEPTH_AB5G5R5 0x7 +#define WIN_COLOR_DEPTH_B8G8R8A8 0xC +#define WIN_COLOR_DEPTH_R8G8B8A8 0xD +#define WIN_COLOR_DEPTH_B6x2G6x2R6x2A8 0xE +#define WIN_COLOR_DEPTH_R6x2G6x2B6x2A8 0xF +#define WIN_COLOR_DEPTH_YCbCr422 0x10 +#define WIN_COLOR_DEPTH_YUV422 0x11 +#define WIN_COLOR_DEPTH_YCbCr420P 0x12 +#define WIN_COLOR_DEPTH_YUV420P 0x13 +#define WIN_COLOR_DEPTH_YCbCr422P 0x14 +#define WIN_COLOR_DEPTH_YUV422P 0x15 +#define WIN_COLOR_DEPTH_YCbCr422R 0x16 +#define WIN_COLOR_DEPTH_YUV422R 0x17 +#define WIN_COLOR_DEPTH_YCbCr422RA 0x18 +#define WIN_COLOR_DEPTH_YUV422RA 0x19 + +#define DC_WIN_BUFFER_CONTROL 0x702 +#define DC_WIN_POSITION 0x704 + +#define DC_WIN_SIZE 0x705 +#define H_SIZE(x) (((x) & 0x1fff) << 0) +#define V_SIZE(x) (((x) & 0x1fff) << 16) + +#define DC_WIN_PRESCALED_SIZE 0x706 +#define H_PRESCALED_SIZE(x) (((x) & 0x7fff) << 0) +#define V_PRESCALED_SIZE(x) (((x) & 0x1fff) << 16) + +#define DC_WIN_H_INITIAL_DDA 0x707 +#define DC_WIN_V_INITIAL_DDA 0x708 + +#define DC_WIN_DDA_INC 0x709 +#define H_DDA_INC(x) (((x) & 0xffff) << 0) +#define V_DDA_INC(x) (((x) & 0xffff) << 16) + +#define DC_WIN_LINE_STRIDE 0x70A +#define DC_WIN_DV_CONTROL 0x70E + +/* The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER). */ +#define DC_WINBUF_START_ADDR 0x800 +#define DC_WINBUF_ADDR_H_OFFSET 0x806 +#define DC_WINBUF_ADDR_V_OFFSET 0x808 +#define DC_WINBUF_SURFACE_KIND 0x80B + +/* Display serial interface registers. */ +#define DSI_RD_DATA 0x9 +#define DSI_WR_DATA 0xA + +#define DSI_POWER_CONTROL 0xB +#define DSI_POWER_CONTROL_ENABLE 1 + +#define DSI_INT_ENABLE 0xC +#define DSI_INT_STATUS 0xD +#define DSI_INT_MASK 0xE + +#define DSI_HOST_CONTROL 0xF +#define DSI_HOST_CONTROL_FIFO_RESET (1 << 21) +#define DSI_HOST_CONTROL_CRC_RESET (1 << 20) +#define DSI_HOST_CONTROL_TX_TRIG_SOL (0 << 12) +#define DSI_HOST_CONTROL_TX_TRIG_FIFO (1 << 12) +#define DSI_HOST_CONTROL_TX_TRIG_HOST (2 << 12) +#define DSI_HOST_CONTROL_RAW (1 << 6) +#define DSI_HOST_CONTROL_HS (1 << 5) +#define DSI_HOST_CONTROL_FIFO_SEL (1 << 4) +#define DSI_HOST_CONTROL_IMM_BTA (1 << 3) +#define DSI_HOST_CONTROL_PKT_BTA (1 << 2) +#define DSI_HOST_CONTROL_CS (1 << 1) +#define DSI_HOST_CONTROL_ECC (1 << 0) + +#define DSI_CONTROL 0x10 +#define DSI_CONTROL_HS_CLK_CTRL (1 << 20) +#define DSI_CONTROL_CHANNEL(c) (((c) & 0x3) << 16) +#define DSI_CONTROL_FORMAT(f) (((f) & 0x3) << 12) +#define DSI_CONTROL_TX_TRIG(x) (((x) & 0x3) << 8) +#define DSI_CONTROL_LANES(n) (((n) & 0x3) << 4) +#define DSI_CONTROL_DCS_ENABLE (1 << 3) +#define DSI_CONTROL_SOURCE(s) (((s) & 0x1) << 2) +#define DSI_CONTROL_VIDEO_ENABLE (1 << 1) +#define DSI_CONTROL_HOST_ENABLE (1 << 0) + +#define DSI_SOL_DELAY 0x11 +#define DSI_MAX_THRESHOLD 0x12 + +#define DSI_TRIGGER 0x13 +#define DSI_TRIGGER_HOST (1 << 1) +#define DSI_TRIGGER_VIDEO (1 << 0) + +#define DSI_TX_CRC 0x14 +#define DSI_STATUS 0x15 +#define DSI_INIT_SEQ_CONTROL 0x1A +#define DSI_INIT_SEQ_DATA_0 0x1B +#define DSI_INIT_SEQ_DATA_1 0x1C +#define DSI_INIT_SEQ_DATA_2 0x1D +#define DSI_INIT_SEQ_DATA_3 0x1E +#define DSI_PKT_SEQ_0_LO 0x23 +#define DSI_PKT_SEQ_0_HI 0x24 +#define DSI_PKT_SEQ_1_LO 0x25 +#define DSI_PKT_SEQ_1_HI 0x26 +#define DSI_PKT_SEQ_2_LO 0x27 +#define DSI_PKT_SEQ_2_HI 0x28 +#define DSI_PKT_SEQ_3_LO 0x29 +#define DSI_PKT_SEQ_3_HI 0x2A +#define DSI_PKT_SEQ_4_LO 0x2B +#define DSI_PKT_SEQ_4_HI 0x2C +#define DSI_PKT_SEQ_5_LO 0x2D +#define DSI_PKT_SEQ_5_HI 0x2E +#define DSI_DCS_CMDS 0x33 +#define DSI_PKT_LEN_0_1 0x34 +#define DSI_PKT_LEN_2_3 0x35 +#define DSI_PKT_LEN_4_5 0x36 +#define DSI_PKT_LEN_6_7 0x37 +#define DSI_PHY_TIMING_0 0x3C +#define DSI_PHY_TIMING_1 0x3D +#define DSI_PHY_TIMING_2 0x3E +#define DSI_BTA_TIMING 0x3F + +#define DSI_TIMEOUT_0 0x44 +#define DSI_TIMEOUT_LRX(x) (((x) & 0xffff) << 16) +#define DSI_TIMEOUT_HTX(x) (((x) & 0xffff) << 0) + +#define DSI_TIMEOUT_1 0x45 +#define DSI_TIMEOUT_PR(x) (((x) & 0xffff) << 16) +#define DSI_TIMEOUT_TA(x) (((x) & 0xffff) << 0) + +#define DSI_TO_TALLY 0x46 + +#define DSI_PAD_CONTROL_0 0x4B +#define DSI_PAD_CONTROL_VS1_PULLDN_CLK (1 << 24) +#define DSI_PAD_CONTROL_VS1_PULLDN(x) (((x) & 0xf) << 16) +#define DSI_PAD_CONTROL_VS1_PDIO_CLK (1 << 8) +#define DSI_PAD_CONTROL_VS1_PDIO(x) (((x) & 0xf) << 0) + +#define DSI_PAD_CONTROL_CD 0x4c +#define DSI_VIDEO_MODE_CONTROL 0x4E + +#define DSI_PAD_CONTROL_1 0x4F +#define DSI_PAD_CONTROL_2 0x50 + +#define DSI_PAD_CONTROL_3 0x51 +#define DSI_PAD_PREEMP_PD_CLK(x) (((x) & 0x3) << 12) +#define DSI_PAD_PREEMP_PU_CLK(x) (((x) & 0x3) << 8) +#define DSI_PAD_PREEMP_PD(x) (((x) & 0x3) << 4) +#define DSI_PAD_PREEMP_PU(x) (((x) & 0x3) << 0) + +#define DSI_PAD_CONTROL_4 0x52 + +#endif diff --git a/sept/sept-primary/src/fuse.c b/sept/sept-primary/src/fuse.c new file mode 100644 index 000000000..8e80fd402 --- /dev/null +++ b/sept/sept-primary/src/fuse.c @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include "car.h" +#include "fuse.h" +#include "timers.h" + +/* Prototypes for internal commands. */ +void fuse_make_regs_visible(void); + +void fuse_enable_power(void); +void fuse_disable_power(void); +void fuse_wait_idle(void); + +/* Initialize the fuse driver */ +void fuse_init(void) { + fuse_make_regs_visible(); +} + +/* Make all fuse registers visible */ +void fuse_make_regs_visible(void) { + clkrst_enable_fuse_regs(true); +} + +/* Enable power to the fuse hardware array */ +void fuse_enable_power(void) { + volatile tegra_fuse_t *fuse = fuse_get_regs(); + fuse->FUSE_PWR_GOOD_SW = 1; + udelay(1); +} + +/* Disable power to the fuse hardware array */ +void fuse_disable_power(void) { + volatile tegra_fuse_t *fuse = fuse_get_regs(); + fuse->FUSE_PWR_GOOD_SW = 0; + udelay(1); +} + +/* Wait for the fuse driver to go idle */ +void fuse_wait_idle(void) { + volatile tegra_fuse_t *fuse = fuse_get_regs(); + uint32_t ctrl_val = 0; + + /* Wait for STATE_IDLE */ + while ((ctrl_val & (0xF0000)) != 0x40000) + { + udelay(1); + ctrl_val = fuse->FUSE_CTRL; + } +} + +/* Read a fuse from the hardware array */ +uint32_t fuse_hw_read(uint32_t addr) { + volatile tegra_fuse_t *fuse = fuse_get_regs(); + fuse_wait_idle(); + + /* Program the target address */ + fuse->FUSE_REG_ADDR = addr; + + /* Enable read operation in control register */ + uint32_t ctrl_val = fuse->FUSE_CTRL; + ctrl_val &= ~0x3; + ctrl_val |= 0x1; /* Set FUSE_READ command */ + fuse->FUSE_CTRL = ctrl_val; + + fuse_wait_idle(); + + return fuse->FUSE_REG_READ; +} + +/* Write a fuse in the hardware array */ +void fuse_hw_write(uint32_t value, uint32_t addr) { + volatile tegra_fuse_t *fuse = fuse_get_regs(); + fuse_wait_idle(); + + /* Program the target address and value */ + fuse->FUSE_REG_ADDR = addr; + fuse->FUSE_REG_WRITE = value; + + /* Enable write operation in control register */ + uint32_t ctrl_val = fuse->FUSE_CTRL; + ctrl_val &= ~0x3; + ctrl_val |= 0x2; /* Set FUSE_WRITE command */ + fuse->FUSE_CTRL = ctrl_val; + + fuse_wait_idle(); +} + +/* Sense the fuse hardware array into the shadow cache */ +void fuse_hw_sense(void) { + volatile tegra_fuse_t *fuse = fuse_get_regs(); + fuse_wait_idle(); + + /* Enable sense operation in control register */ + uint32_t ctrl_val = fuse->FUSE_CTRL; + ctrl_val &= ~0x3; + ctrl_val |= 0x3; /* Set FUSE_SENSE command */ + fuse->FUSE_CTRL = ctrl_val; + + fuse_wait_idle(); +} + +/* Disables all fuse programming. */ +void fuse_disable_programming(void) { + volatile tegra_fuse_t *fuse = fuse_get_regs(); + fuse->FUSE_DIS_PGM = 1; +} + +/* Unknown exactly what this does, but it alters the contents read from the fuse cache. */ +void fuse_secondary_private_key_disable(void) { + volatile tegra_fuse_t *fuse = fuse_get_regs(); + fuse->FUSE_PRIVATEKEYDISABLE = 0x10; +} + + +/* Read the SKU info register from the shadow cache */ +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 */ +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; +} + +/* Read a spare bit register from the shadow cache */ +uint32_t fuse_get_spare_bit(uint32_t idx) { + volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); + + if (idx >= 32) { + return 0; + } + + return fuse_chip->FUSE_SPARE_BIT[idx]; +} + +/* Read a reserved ODM register from the shadow cache */ +uint32_t fuse_get_reserved_odm(uint32_t idx) { + volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); + + if (idx >= 8) { + return 0; + } + + return fuse_chip->FUSE_RESERVED_ODM[idx]; +} + +/* Derive the Device ID using values in the shadow cache */ +uint64_t fuse_get_device_id(void) { + volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); + + uint64_t device_id = 0; + uint64_t y_coord = fuse_chip->FUSE_Y_COORDINATE & 0x1FF; + uint64_t x_coord = fuse_chip->FUSE_X_COORDINATE & 0x1FF; + uint64_t wafer_id = fuse_chip->FUSE_WAFER_ID & 0x3F; + uint32_t lot_code = fuse_chip->FUSE_LOT_CODE_0; + uint64_t fab_code = fuse_chip->FUSE_FAB_CODE & 0x3F; + uint64_t derived_lot_code = 0; + for (unsigned int i = 0; i < 5; i++) { + derived_lot_code = (derived_lot_code * 0x24) + ((lot_code >> (24 - 6*i)) & 0x3F); + } + derived_lot_code &= 0x03FFFFFF; + + device_id |= y_coord << 0; + device_id |= x_coord << 9; + device_id |= wafer_id << 18; + device_id |= derived_lot_code << 24; + device_id |= fab_code << 50; + return device_id; +} + +/* Get the DRAM ID using values in the shadow cache */ +uint32_t fuse_get_dram_id(void) { + volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); + return (fuse_chip->FUSE_RESERVED_ODM[4] >> 3) & 0x7; +} + +/* Derive the Hardware Type using values in the shadow cache */ +uint32_t fuse_get_hardware_type(void) { + volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); + + /* This function is very different between 4.x and < 4.x */ + uint32_t hardware_type = ((fuse_chip->FUSE_RESERVED_ODM[4] >> 7) & 2) | ((fuse_chip->FUSE_RESERVED_ODM[4] >> 2) & 1); + + /* TODO: choose; if (mkey_get_revision() >= MASTERKEY_REVISION_400_CURRENT) { + static const uint32_t types[] = {0,1,4,3}; + + hardware_type |= (fuse_chip->FUSE_RESERVED_ODM[4] >> 14) & 0x3C; + hardware_type--; + return hardware_type > 3 ? 4 : types[hardware_type]; + } else {*/ + 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; + } +// } +} + +/* Derive the Retail Type using values in the shadow cache */ +uint32_t fuse_get_retail_type(void) { + volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); + + /* Retail type = IS_RETAIL | UNIT_TYPE */ + uint32_t retail_type = ((fuse_chip->FUSE_RESERVED_ODM[4] >> 7) & 4) | (fuse_chip->FUSE_RESERVED_ODM[4] & 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; + } + return 2; /* IS_RETAIL | DEV_UNIT */ +} + +/* Derive the 16-byte Hardware Info using values in the shadow cache, 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]; + + uint32_t unk_hw_fuse = fuse_chip->_0x120 & 0x3F; + uint32_t y_coord = fuse_chip->FUSE_Y_COORDINATE & 0x1FF; + uint32_t x_coord = fuse_chip->FUSE_X_COORDINATE & 0x1FF; + uint32_t wafer_id = fuse_chip->FUSE_WAFER_ID & 0x3F; + uint32_t lot_code_0 = fuse_chip->FUSE_LOT_CODE_0; + uint32_t lot_code_1 = fuse_chip->FUSE_LOT_CODE_1 & 0x0FFFFFFF; + uint32_t fab_code = fuse_chip->FUSE_FAB_CODE & 0x3F; + uint32_t vendor_code = fuse_chip->FUSE_VENDOR_CODE & 0xF; + + /* Hardware Info = unk_hw_fuse || Y_COORD || X_COORD || WAFER_ID || LOT_CODE || FAB_CODE || VENDOR_ID */ + hw_info[0] = (uint32_t)((lot_code_1 << 30) | (wafer_id << 24) | (x_coord << 15) | (y_coord << 6) | (unk_hw_fuse)); + hw_info[1] = (uint32_t)((lot_code_0 << 26) | (lot_code_1 >> 2)); + hw_info[2] = (uint32_t)((fab_code << 26) | (lot_code_0 >> 6)); + hw_info[3] = (uint32_t)(vendor_code); + + memcpy(dst, hw_info, 0x10); +} diff --git a/sept/sept-primary/src/fuse.h b/sept/sept-primary/src/fuse.h new file mode 100644 index 000000000..528b0aff4 --- /dev/null +++ b/sept/sept-primary/src/fuse.h @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef FUSEE_FUSE_H +#define FUSEE_FUSE_H + +#define FUSE_BASE 0x7000F800 +#define FUSE_CHIP_BASE (FUSE_BASE + 0x100) +#define MAKE_FUSE_REG(n) MAKE_REG32(FUSE_BASE + n) +#define MAKE_FUSE_CHIP_REG(n) MAKE_REG32(FUSE_CHIP_BASE + n) + +typedef struct { + uint32_t FUSE_CTRL; + uint32_t FUSE_REG_ADDR; + uint32_t FUSE_REG_READ; + uint32_t FUSE_REG_WRITE; + uint32_t FUSE_TIME_RD1; + uint32_t FUSE_TIME_RD2; + uint32_t FUSE_TIME_PGM1; + uint32_t FUSE_TIME_PGM2; + uint32_t FUSE_PRIV2INTFC; + uint32_t FUSE_FUSEBYPASS; + uint32_t FUSE_PRIVATEKEYDISABLE; + uint32_t FUSE_DIS_PGM; + uint32_t FUSE_WRITE_ACCESS; + uint32_t FUSE_PWR_GOOD_SW; + uint32_t _0x38[0x32]; +} tegra_fuse_t; + +typedef struct { + uint32_t FUSE_PRODUCTION_MODE; + uint32_t _0x4; + uint32_t _0x8; + uint32_t _0xC; + uint32_t FUSE_SKU_INFO; + uint32_t FUSE_CPU_SPEEDO_0; + uint32_t FUSE_CPU_IDDQ; + uint32_t _0x1C; + uint32_t _0x20; + uint32_t _0x24; + uint32_t FUSE_FT_REV; + uint32_t FUSE_CPU_SPEEDO_1; + uint32_t FUSE_CPU_SPEEDO_2; + uint32_t FUSE_SOC_SPEEDO_0; + uint32_t FUSE_SOC_SPEEDO_1; + uint32_t FUSE_SOC_SPEEDO_2; + uint32_t FUSE_SOC_IDDQ; + uint32_t _0x44; + uint32_t FUSE_FA; + uint32_t _0x4C; + uint32_t _0x50; + uint32_t _0x54; + uint32_t _0x58; + uint32_t _0x5C; + uint32_t _0x60; + uint32_t FUSE_PUBLIC_KEY[0x8]; + uint32_t FUSE_TSENSOR_1; + uint32_t FUSE_TSENSOR_2; + uint32_t _0x8C; + uint32_t FUSE_CP_REV; + uint32_t _0x94; + uint32_t FUSE_TSENSOR_0; + uint32_t FUSE_FIRST_BOOTROM_PATCH_SIZE_REG; + uint32_t FUSE_SECURITY_MODE; + uint32_t FUSE_PRIVATE_KEY[0x4]; + uint32_t FUSE_DEVICE_KEY; + uint32_t _0xB8; + uint32_t _0xBC; + uint32_t FUSE_RESERVED_SW; + uint32_t FUSE_VP8_ENABLE; + uint32_t FUSE_RESERVED_ODM[0x8]; + uint32_t _0xE8; + uint32_t _0xEC; + uint32_t FUSE_SKU_USB_CALIB; + uint32_t FUSE_SKU_DIRECT_CONFIG; + uint32_t _0xF8; + uint32_t _0xFC; + uint32_t FUSE_VENDOR_CODE; + uint32_t FUSE_FAB_CODE; + uint32_t FUSE_LOT_CODE_0; + uint32_t FUSE_LOT_CODE_1; + uint32_t FUSE_WAFER_ID; + uint32_t FUSE_X_COORDINATE; + uint32_t FUSE_Y_COORDINATE; + uint32_t _0x11C; + uint32_t _0x120; + uint32_t FUSE_SATA_CALIB; + uint32_t FUSE_GPU_IDDQ; + uint32_t FUSE_TSENSOR_3; + uint32_t _0x130; + uint32_t _0x134; + uint32_t _0x138; + uint32_t _0x13C; + uint32_t _0x140; + uint32_t _0x144; + uint32_t FUSE_OPT_SUBREVISION; + uint32_t _0x14C; + uint32_t _0x150; + uint32_t FUSE_TSENSOR_4; + uint32_t FUSE_TSENSOR_5; + uint32_t FUSE_TSENSOR_6; + uint32_t FUSE_TSENSOR_7; + uint32_t FUSE_OPT_PRIV_SEC_DIS; + uint32_t FUSE_PKC_DISABLE; + uint32_t _0x16C; + uint32_t _0x170; + uint32_t _0x174; + uint32_t _0x178; + uint32_t _0x17C; + uint32_t FUSE_TSENSOR_COMMON; + uint32_t _0x184; + uint32_t _0x188; + uint32_t _0x18C; + uint32_t _0x190; + uint32_t _0x194; + uint32_t _0x198; + uint32_t FUSE_DEBUG_AUTH_OVERRIDE; + uint32_t _0x1A0; + uint32_t _0x1A4; + uint32_t _0x1A8; + uint32_t _0x1AC; + uint32_t _0x1B0; + uint32_t _0x1B4; + uint32_t _0x1B8; + uint32_t _0x1BC; + uint32_t _0x1D0; + uint32_t FUSE_TSENSOR_8; + uint32_t _0x1D8; + uint32_t _0x1DC; + uint32_t _0x1E0; + uint32_t _0x1E4; + uint32_t _0x1E8; + uint32_t _0x1EC; + uint32_t _0x1F0; + uint32_t _0x1F4; + uint32_t _0x1F8; + uint32_t _0x1FC; + uint32_t _0x200; + uint32_t FUSE_RESERVED_CALIB; + uint32_t _0x208; + uint32_t _0x20C; + uint32_t _0x210; + uint32_t _0x214; + uint32_t _0x218; + uint32_t FUSE_TSENSOR_9; + uint32_t _0x220; + uint32_t _0x224; + uint32_t _0x228; + uint32_t _0x22C; + uint32_t _0x230; + uint32_t _0x234; + uint32_t _0x238; + uint32_t _0x23C; + uint32_t _0x240; + uint32_t _0x244; + uint32_t _0x248; + uint32_t _0x24C; + uint32_t FUSE_USB_CALIB_EXT; + uint32_t _0x254; + uint32_t _0x258; + uint32_t _0x25C; + uint32_t _0x260; + uint32_t _0x264; + uint32_t _0x268; + uint32_t _0x26C; + uint32_t _0x270; + uint32_t _0x274; + uint32_t _0x278; + uint32_t _0x27C; + uint32_t FUSE_SPARE_BIT[0x20]; +} tegra_fuse_chip_t; + +static inline volatile tegra_fuse_t *fuse_get_regs(void) { + return (volatile tegra_fuse_t *)FUSE_BASE; +} + +static inline volatile tegra_fuse_chip_t *fuse_chip_get_regs(void) { + return (volatile tegra_fuse_chip_t *)FUSE_CHIP_BASE; +} + +void fuse_init(void); + +uint32_t fuse_hw_read(uint32_t addr); +void fuse_hw_write(uint32_t value, uint32_t addr); +void fuse_hw_sense(void); +void fuse_disable_programming(void); +void fuse_secondary_private_key_disable(void); + +uint32_t fuse_get_sku_info(void); +uint32_t fuse_get_spare_bit(uint32_t idx); +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(void); +uint32_t fuse_get_retail_type(void); +void fuse_get_hardware_info(void *dst); + +#endif diff --git a/sept/sept-primary/src/gpio.c b/sept/sept-primary/src/gpio.c new file mode 100644 index 000000000..9cfec5c2f --- /dev/null +++ b/sept/sept-primary/src/gpio.c @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include "gpio.h" +#include "utils.h" + +/** + * Returns a GPIO bank object that corresponds to the given GPIO pin, + * which can be created using the TEGRA_GPIO macro or passed from the name macro. + * + * @param pin The GPIO to get the bank for. + * @return The GPIO bank object to use for working with the given bank. + */ +static volatile tegra_gpio_bank_t *gpio_get_bank(uint32_t pin) +{ + volatile tegra_gpio_t *gpio = gpio_get_regs(); + uint32_t bank_number = pin >> GPIO_BANK_SHIFT; + + return &gpio->bank[bank_number]; +} + +/** + * @return the port number for working with the given GPIO. + */ +static volatile uint32_t gpio_get_port(uint32_t pin) +{ + return (pin >> GPIO_PORT_SHIFT) & GPIO_PORT_MASK; +} + +/** + * @return a mask to be used to work with the given GPIO + */ +static volatile uint32_t gpio_get_mask(uint32_t pin) +{ + uint32_t pin_number = pin & GPIO_PIN_MASK; + return (1 << pin_number); +} + +/** + * Performs a simple GPIO configuration operation. + * + * @param pin The GPIO pin to work with, as created with TEGRA_GPIO, or a named GPIO. + * @param should_be_set True iff the relevant bit should be set; or false if it should be cleared. + * @param offset The offset into a gpio_bank structure + */ +static void gpio_simple_register_set(uint32_t pin, bool should_be_set, uint32_t offset) +{ + // Retrieve the register set that corresponds to the given pin and offset. + uintptr_t cluster_addr = (uintptr_t)gpio_get_bank(pin) + offset; + uint32_t *cluster = (uint32_t *)cluster_addr; + + // Figure out the offset into the cluster, + // and the mask to be used. + uint32_t port = gpio_get_port(pin); + uint32_t mask = gpio_get_mask(pin); + + // Set or clear the bit, as appropriate. + if (should_be_set) + cluster[port] |= mask; + else + cluster[port] &= ~mask; +} + +/** + * Performs a simple GPIO configuration operation. + * + * @param pin The GPIO pin to work with, as created with TEGRA_GPIO, or a named GPIO. + * @param should_be_set True iff the relevant bit should be set; or false if it should be cleared. + * @param offset The offset into a gpio_bank structure + */ +static bool gpio_simple_register_get(uint32_t pin, uint32_t offset) +{ + // Retrieve the register set that corresponds to the given pin and offset. + uintptr_t cluster_addr = (uintptr_t)gpio_get_bank(pin) + offset; + uint32_t *cluster = (uint32_t *)cluster_addr; + + // Figure out the offset into the cluster, + // and the mask to be used. + uint32_t port = gpio_get_port(pin); + uint32_t mask = gpio_get_mask(pin); + + // Convert the given value to a boolean. + return !!(cluster[port] & mask); +} + +/** + * Configures a given pin as either GPIO or SFIO. + * + * @param pin The GPIO pin to work with, as created with TEGRA_GPIO, or a named GPIO. + * @param mode The relevant mode. + */ +void gpio_configure_mode(uint32_t pin, uint32_t mode) +{ + gpio_simple_register_set(pin, mode == GPIO_MODE_GPIO, offsetof(tegra_gpio_bank_t, config)); +} + +/** + * Configures a given pin as either INPUT or OUPUT. + * + * @param pin The GPIO pin to work with, as created with TEGRA_GPIO, or a named GPIO. + * @param direction The relevant direction. + */ +void gpio_configure_direction(uint32_t pin, uint32_t dir) +{ + gpio_simple_register_set(pin, dir == GPIO_DIRECTION_OUTPUT, offsetof(tegra_gpio_bank_t, direction)); +} + +/** + * Drives a relevant GPIO pin as either HIGH or LOW. + * + * @param pin The GPIO pin to work with, as created with TEGRA_GPIO, or a named GPIO. + * @param mode The relevant mode. + */ +void gpio_write(uint32_t pin, uint32_t value) +{ + gpio_simple_register_set(pin, value == GPIO_LEVEL_HIGH, offsetof(tegra_gpio_bank_t, out)); +} + +/** + * Drives a relevant GPIO pin as either HIGH or LOW. + * + * @param pin The GPIO pin to work with, as created with TEGRA_GPIO, or a named GPIO. + * @param mode The relevant mode. + */ +uint32_t gpio_read(uint32_t pin) +{ + return gpio_simple_register_get(pin, offsetof(tegra_gpio_bank_t, in)); +} diff --git a/sept/sept-primary/src/gpio.h b/sept/sept-primary/src/gpio.h new file mode 100644 index 000000000..41781a0ca --- /dev/null +++ b/sept/sept-primary/src/gpio.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef FUSEE_GPIO_H +#define FUSEE_GPIO_H + +#include + +#define GPIO_BASE 0x6000D000 +#define MAKE_GPIO_REG(n) MAKE_REG32(GPIO_BASE + n) + +#define TEGRA_GPIO_PORTS 4 +#define TEGRA_GPIO_BANKS 8 +#define GPIO_BANK_SHIFT 5 +#define GPIO_PORT_SHIFT 3 +#define GPIO_PORT_MASK 0x03 +#define GPIO_PIN_MASK 0x07 + +typedef enum { + TEGRA_GPIO_PORT_A = 0, + TEGRA_GPIO_PORT_B = 1, + TEGRA_GPIO_PORT_C = 2, + TEGRA_GPIO_PORT_D = 3, + TEGRA_GPIO_PORT_E = 4, + TEGRA_GPIO_PORT_F = 5, + TEGRA_GPIO_PORT_G = 6, + TEGRA_GPIO_PORT_H = 7, + TEGRA_GPIO_PORT_I = 8, + TEGRA_GPIO_PORT_J = 9, + TEGRA_GPIO_PORT_K = 10, + TEGRA_GPIO_PORT_L = 11, + TEGRA_GPIO_PORT_M = 12, + TEGRA_GPIO_PORT_N = 13, + TEGRA_GPIO_PORT_O = 14, + TEGRA_GPIO_PORT_P = 15, + TEGRA_GPIO_PORT_Q = 16, + TEGRA_GPIO_PORT_R = 17, + TEGRA_GPIO_PORT_S = 18, + TEGRA_GPIO_PORT_T = 19, + TEGRA_GPIO_PORT_U = 20, + TEGRA_GPIO_PORT_V = 21, + TEGRA_GPIO_PORT_W = 22, + TEGRA_GPIO_PORT_X = 23, + TEGRA_GPIO_PORT_Y = 24, + TEGRA_GPIO_PORT_Z = 25, + TEGRA_GPIO_PORT_AA = 26, + TEGRA_GPIO_PORT_BB = 27, + TEGRA_GPIO_PORT_CC = 28, + TEGRA_GPIO_PORT_DD = 29, + TEGRA_GPIO_PORT_EE = 30, + TEGRA_GPIO_PORT_FF = 31, +} tegra_gpio_port; + +typedef struct { + uint32_t config[TEGRA_GPIO_PORTS]; + uint32_t direction[TEGRA_GPIO_PORTS]; + uint32_t out[TEGRA_GPIO_PORTS]; + uint32_t in[TEGRA_GPIO_PORTS]; + uint32_t int_status[TEGRA_GPIO_PORTS]; + uint32_t int_enable[TEGRA_GPIO_PORTS]; + uint32_t int_level[TEGRA_GPIO_PORTS]; + uint32_t int_clear[TEGRA_GPIO_PORTS]; + uint32_t masked_config[TEGRA_GPIO_PORTS]; + uint32_t masked_dir_out[TEGRA_GPIO_PORTS]; + uint32_t masked_out[TEGRA_GPIO_PORTS]; + uint32_t masked_in[TEGRA_GPIO_PORTS]; + uint32_t masked_int_status[TEGRA_GPIO_PORTS]; + uint32_t masked_int_enable[TEGRA_GPIO_PORTS]; + uint32_t masked_int_level[TEGRA_GPIO_PORTS]; + uint32_t masked_int_clear[TEGRA_GPIO_PORTS]; +} tegra_gpio_bank_t; + +typedef struct { + tegra_gpio_bank_t bank[TEGRA_GPIO_BANKS]; +} tegra_gpio_t; + +static inline volatile tegra_gpio_t *gpio_get_regs(void) +{ + return (volatile tegra_gpio_t *)GPIO_BASE; +} + +#define TEGRA_GPIO(port, offset) \ + ((TEGRA_GPIO_PORT_##port * 8) + offset) + +/* Mode select */ +#define GPIO_MODE_GPIO 0 +#define GPIO_MODE_SFIO 1 + +/* Direction */ +#define GPIO_DIRECTION_INPUT 0 +#define GPIO_DIRECTION_OUTPUT 1 + +/* Level */ +#define GPIO_LEVEL_LOW 0 +#define GPIO_LEVEL_HIGH 1 + +/* Named GPIOs */ +#define GPIO_BUTTON_VOL_DOWN TEGRA_GPIO(X, 7) +#define GPIO_BUTTON_VOL_UP TEGRA_GPIO(X, 6) +#define GPIO_MICROSD_CARD_DETECT TEGRA_GPIO(Z, 1) +#define GPIO_MICROSD_WRITE_PROTECT TEGRA_GPIO(Z, 4) +#define GPIO_MICROSD_SUPPLY_ENABLE TEGRA_GPIO(E, 4) +#define GPIO_LCD_BL_P5V TEGRA_GPIO(I, 0) +#define GPIO_LCD_BL_N5V TEGRA_GPIO(I, 1) +#define GPIO_LCD_BL_PWM TEGRA_GPIO(V, 0) +#define GPIO_LCD_BL_EN TEGRA_GPIO(V, 1) +#define GPIO_LCD_BL_RST TEGRA_GPIO(V, 2) + +void gpio_configure_mode(uint32_t pin, uint32_t mode); +void gpio_configure_direction(uint32_t pin, uint32_t dir); +void gpio_write(uint32_t pin, uint32_t value); +uint32_t gpio_read(uint32_t pin); + +#endif diff --git a/sept/sept-primary/src/i2c.c b/sept/sept-primary/src/i2c.c new file mode 100644 index 000000000..aec946cf2 --- /dev/null +++ b/sept/sept-primary/src/i2c.c @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "i2c.h" +#include "utils.h" +#include "timers.h" + +/* Prototypes for internal commands. */ +volatile tegra_i2c_t *i2c_get_registers_from_id(unsigned int id); +void i2c_load_config(volatile tegra_i2c_t *regs); + +bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst_size); +bool i2c_send(unsigned int id, uint8_t device, uint8_t r, void *src, size_t src_size); + +bool i2c_write(volatile tegra_i2c_t *regs, uint8_t device, void *src, size_t src_size); +bool i2c_read(volatile tegra_i2c_t *regs, uint8_t device, void *dst, size_t dst_size); + +/* Initialize I2C based on registers. */ +void i2c_init(unsigned int id) { + volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id); + + /* Setup divisor, and clear the bus. */ + regs->I2C_I2C_CLK_DIVISOR_REGISTER_0 = 0x50001; + regs->I2C_I2C_BUS_CLEAR_CONFIG_0 = 0x90003; + + /* Load hardware configuration. */ + i2c_load_config(regs); + + /* Wait a while until BUS_CLEAR_DONE is set. */ + for (unsigned int i = 0; i < 10; i++) { + udelay(20000); + if (regs->I2C_INTERRUPT_STATUS_REGISTER_0 & 0x800) { + break; + } + } + + /* Read the BUS_CLEAR_STATUS. Result doesn't matter. */ + regs->I2C_I2C_BUS_CLEAR_STATUS_0; + + /* Read and set the Interrupt Status. */ + uint32_t int_status = regs->I2C_INTERRUPT_STATUS_REGISTER_0; + regs->I2C_INTERRUPT_STATUS_REGISTER_0 = int_status; +} + +/* Sets a bit in a PMIC register over I2C during CPU shutdown. */ +void i2c_send_pmic_cpu_shutdown_cmd(void) { + uint32_t val = 0; + /* PMIC == Device 4:3C. */ + i2c_query(I2C_5, MAX77620_PWR_I2C_ADDR, 0x41, &val, 1); + val |= 4; + i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, 0x41, &val, 1); +} + +/* Queries the value of TI charger bit over I2C. */ +bool i2c_query_ti_charger_bit_7(void) { + uint32_t val = 0; + /* TI Charger = Device 0:6B. */ + i2c_query(I2C_1, BQ24193_I2C_ADDR, 0, &val, 1); + return (val & 0x80) != 0; +} + +/* Clears TI charger bit over I2C. */ +void i2c_clear_ti_charger_bit_7(void) { + uint32_t val = 0; + /* TI Charger = Device 0:6B. */ + i2c_query(I2C_1, BQ24193_I2C_ADDR, 0, &val, 1); + val &= 0x7F; + i2c_send(I2C_1, BQ24193_I2C_ADDR, 0, &val, 1); +} + +/* Sets TI charger bit over I2C. */ +void i2c_set_ti_charger_bit_7(void) { + uint32_t val = 0; + /* TI Charger = Device 0:6B. */ + i2c_query(I2C_1, BQ24193_I2C_ADDR, 0, &val, 1); + val |= 0x80; + i2c_send(I2C_1, BQ24193_I2C_ADDR, 0, &val, 1); +} + +/* Get registers pointer based on I2C ID. */ +volatile tegra_i2c_t *i2c_get_registers_from_id(unsigned int id) { + switch (id) { + case I2C_1: + return I2C1_REGS; + case I2C_2: + return I2C2_REGS; + case I2C_3: + return I2C3_REGS; + case I2C_4: + return I2C4_REGS; + case I2C_5: + return I2C5_REGS; + case I2C_6: + return I2C6_REGS; + default: + generic_panic(); + } + return NULL; +} + +/* Load hardware config for I2C4. */ +void i2c_load_config(volatile tegra_i2c_t *regs) { + /* Set MSTR_CONFIG_LOAD, TIMEOUT_CONFIG_LOAD, undocumented bit. */ + regs->I2C_I2C_CONFIG_LOAD_0 = 0x25; + + /* Wait a bit for master config to be loaded. */ + for (unsigned int i = 0; i < 20; i++) { + udelay(1); + if (!(regs->I2C_I2C_CONFIG_LOAD_0 & 1)) { + break; + } + } +} + +/* Reads a register from a device over I2C, writes result to output. */ +bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst_size) { + volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id); + uint32_t val = r; + + /* Write single byte register ID to device. */ + if (!i2c_write(regs, device, &val, 1)) { + return false; + } + /* Limit output size to 32-bits. */ + if (dst_size > 4) { + return false; + } + + return i2c_read(regs, device, dst, dst_size); +} + +/* Writes a value to a register over I2C. */ +bool i2c_send(unsigned int id, uint8_t device, uint8_t r, void *src, size_t src_size) { + uint32_t val = r; + if (src_size == 0) { + return true; + } else if (src_size <= 3) { + memcpy(((uint8_t *)&val) + 1, src, src_size); + return i2c_write(i2c_get_registers_from_id(id), device, &val, src_size + 1); + } else { + return false; + } +} + +/* Writes bytes to device over I2C. */ +bool i2c_write(volatile tegra_i2c_t *regs, uint8_t device, void *src, size_t src_size) { + if (src_size > 4) { + return false; + } else if (src_size == 0) { + return true; + } + + /* Set device for 7-bit write mode. */ + regs->I2C_I2C_CMD_ADDR0_0 = device << 1; + + /* Load in data to write. */ + regs->I2C_I2C_CMD_DATA1_0 = read32le(src, 0); + + /* Set config with LENGTH = src_size, NEW_MASTER_FSM, DEBOUNCE_CNT = 4T. */ + regs->I2C_I2C_CNFG_0 = ((src_size << 1) - 2) | 0x2800; + + i2c_load_config(regs); + + /* Config |= SEND; */ + regs->I2C_I2C_CNFG_0 = ((regs->I2C_I2C_CNFG_0 & 0xFFFFFDFF) | 0x200); + + while (regs->I2C_I2C_STATUS_0 & 0x100) { + /* Wait until not busy. */ + } + + /* Return CMD1_STAT == SL1_XFER_SUCCESSFUL. */ + return (regs->I2C_I2C_STATUS_0 & 0xF) == 0; +} + +/* Reads bytes from device over I2C. */ +bool i2c_read(volatile tegra_i2c_t *regs, uint8_t device, void *dst, size_t dst_size) { + if (dst_size > 4) { + return false; + } else if (dst_size == 0) { + return true; + } + + /* Set device for 7-bit read mode. */ + regs->I2C_I2C_CMD_ADDR0_0 = (device << 1) | 1; + + /* Set config with LENGTH = dst_size, NEW_MASTER_FSM, DEBOUNCE_CNT = 4T. */ + regs->I2C_I2C_CNFG_0 = ((dst_size << 1) - 2) | 0x2840; + + i2c_load_config(regs); + + /* Config |= SEND; */ + regs->I2C_I2C_CNFG_0 = ((regs->I2C_I2C_CNFG_0 & 0xFFFFFDFF) | 0x200); + + while (regs->I2C_I2C_STATUS_0 & 0x100) { + /* Wait until not busy. */ + } + + /* Ensure success. */ + if ((regs->I2C_I2C_STATUS_0 & 0xF) != 0) { + return false; + } + + uint32_t val = regs->I2C_I2C_CMD_DATA1_0; + memcpy(dst, &val, dst_size); + return true; +} diff --git a/sept/sept-primary/src/i2c.h b/sept/sept-primary/src/i2c.h new file mode 100644 index 000000000..9399b0024 --- /dev/null +++ b/sept/sept-primary/src/i2c.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef FUSEE_I2C_H +#define FUSEE_I2C_H + +#include +#include +#include + +#define I2C1234_BASE 0x7000C000 +#define I2C56_BASE 0x7000D000 + +#define I2C_1 0 +#define I2C_2 1 +#define I2C_3 2 +#define I2C_4 3 +#define I2C_5 4 +#define I2C_6 5 + +#define MAX77621_CPU_I2C_ADDR 0x1B +#define MAX77621_GPU_I2C_ADDR 0x1C +#define MAX17050_I2C_ADDR 0x36 +#define MAX77620_PWR_I2C_ADDR 0x3C +#define MAX77620_RTC_I2C_ADDR 0x68 +#define BQ24193_I2C_ADDR 0x6B + +typedef struct { + uint32_t I2C_I2C_CNFG_0; + uint32_t I2C_I2C_CMD_ADDR0_0; + uint32_t I2C_I2C_CMD_ADDR1_0; + uint32_t I2C_I2C_CMD_DATA1_0; + uint32_t I2C_I2C_CMD_DATA2_0; + uint32_t _0x14; + uint32_t _0x18; + uint32_t I2C_I2C_STATUS_0; + uint32_t I2C_I2C_SL_CNFG_0; + uint32_t I2C_I2C_SL_RCVD_0; + uint32_t I2C_I2C_SL_STATUS_0; + uint32_t I2C_I2C_SL_ADDR1_0; + uint32_t I2C_I2C_SL_ADDR2_0; + uint32_t I2C_I2C_TLOW_SEXT_0; + uint32_t _0x38; + uint32_t I2C_I2C_SL_DELAY_COUNT_0; + uint32_t I2C_I2C_SL_INT_MASK_0; + uint32_t I2C_I2C_SL_INT_SOURCE_0; + uint32_t I2C_I2C_SL_INT_SET_0; + uint32_t _0x4C; + uint32_t I2C_I2C_TX_PACKET_FIFO_0; + uint32_t I2C_I2C_RX_FIFO_0; + uint32_t I2C_PACKET_TRANSFER_STATUS_0; + uint32_t I2C_FIFO_CONTROL_0; + uint32_t I2C_FIFO_STATUS_0; + uint32_t I2C_INTERRUPT_MASK_REGISTER_0; + uint32_t I2C_INTERRUPT_STATUS_REGISTER_0; + uint32_t I2C_I2C_CLK_DIVISOR_REGISTER_0; + uint32_t I2C_I2C_INTERRUPT_SOURCE_REGISTER_0; + uint32_t I2C_I2C_INTERRUPT_SET_REGISTER_0; + uint32_t I2C_I2C_SLV_TX_PACKET_FIFO_0; + uint32_t I2C_I2C_SLV_RX_FIFO_0; + uint32_t I2C_I2C_SLV_PACKET_STATUS_0; + uint32_t I2C_I2C_BUS_CLEAR_CONFIG_0; + uint32_t I2C_I2C_BUS_CLEAR_STATUS_0; + uint32_t I2C_I2C_CONFIG_LOAD_0; + uint32_t _0x90; + uint32_t I2C_I2C_INTERFACE_TIMING_0_0; + uint32_t I2C_I2C_INTERFACE_TIMING_1_0; + uint32_t I2C_I2C_HS_INTERFACE_TIMING_0_0; + uint32_t I2C_I2C_HS_INTERFACE_TIMING_1_0; +} tegra_i2c_t; + +#define I2C1_REGS ((volatile tegra_i2c_t *)(I2C1234_BASE + 0x000)) +#define I2C2_REGS ((volatile tegra_i2c_t *)(I2C1234_BASE + 0x400)) +#define I2C3_REGS ((volatile tegra_i2c_t *)(I2C1234_BASE + 0x500)) +#define I2C4_REGS ((volatile tegra_i2c_t *)(I2C1234_BASE + 0x700)) +#define I2C5_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x000)) +#define I2C6_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x100)) + +void i2c_init(unsigned int id); +bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst_size); +bool i2c_send(unsigned int id, uint8_t device, uint8_t r, void *src, size_t src_size); + +void i2c_send_pmic_cpu_shutdown_cmd(void); +bool i2c_query_ti_charger_bit_7(void); +void i2c_clear_ti_charger_bit_7(void); +void i2c_set_ti_charger_bit_7(void); + +#endif diff --git a/sept/sept-primary/src/main.c b/sept/sept-primary/src/main.c new file mode 100644 index 000000000..6154995f4 --- /dev/null +++ b/sept/sept-primary/src/main.c @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "utils.h" +#include "car.h" +#include "timers.h" +#include "di.h" +#include "se.h" +#include "fuse.h" +#include "pmc.h" +#include "mc.h" +#include "sysreg.h" +#include "tsec.h" + +#define I2S_BASE 0x702D1000 +#define MAKE_I2S_REG(n) MAKE_REG32(I2S_BASE + n) + +static void setup_exception_vectors(void) { + for (unsigned int i = 0; i < 0x20; i += 4) { + MAKE_REG32(0x6000F200u + i) = (uint32_t)generic_panic; + } +} + +static void mbist_workaround(void) +{ + volatile tegra_car_t *car = car_get_regs(); + + car->clk_source_sor1 = ((car->clk_source_sor1 | 0x8000) & 0xFFFFBFFF); + car->plld_base |= 0x40800000u; + car->rst_dev_y_clr = 0x40; + car->rst_dev_x_clr = 0x40000; + car->rst_dev_l_clr = 0x18000000; + udelay(3); + + /* Setup I2S. */ + MAKE_I2S_REG(0x0A0) |= 0x400; + MAKE_I2S_REG(0x088) &= 0xFFFFFFFE; + MAKE_I2S_REG(0x1A0) |= 0x400; + MAKE_I2S_REG(0x188) &= 0xFFFFFFFE; + MAKE_I2S_REG(0x2A0) |= 0x400; + MAKE_I2S_REG(0x288) &= 0xFFFFFFFE; + MAKE_I2S_REG(0x3A0) |= 0x400; + MAKE_I2S_REG(0x388) &= 0xFFFFFFFE; + MAKE_I2S_REG(0x4A0) |= 0x400; + MAKE_I2S_REG(0x488) &= 0xFFFFFFFE; + + MAKE_DI_REG(DC_COM_DSC_TOP_CTL) |= 4; + MAKE_VIC_REG(0x8C) = 0xFFFFFFFF; + udelay(3); + + /* Set devices in reset. */ + car->rst_dev_y_set = 0x40; + car->rst_dev_l_set = 0x18000000; + car->rst_dev_x_set = 0x40000; + + /* Clock out enables. */ + car->clk_out_enb_h = 0xC0; + car->clk_out_enb_l = 0x80000130; + car->clk_out_enb_u = 0x1F00200; + car->clk_out_enb_v = 0x80400808; + car->clk_out_enb_w = 0x402000FC; + car->clk_out_enb_x = 0x23000780; + car->clk_out_enb_y = 0x300; + + /* LVL2 clock gate overrides. */ + car->lvl2_clk_gate_ovra = 0; + car->lvl2_clk_gate_ovrb = 0; + car->lvl2_clk_gate_ovrc = 0; + car->lvl2_clk_gate_ovrd = 0; + car->lvl2_clk_gate_ovre = 0; + + /* Configure clock sources. */ + car->plld_base &= 0x1F7FFFFF; + car->clk_source_sor1 &= 0xFFFF3FFF; + car->clk_source_vi = ((car->clk_source_vi & 0x1FFFFFFF) | 0x80000000); + car->clk_source_host1x = ((car->clk_source_host1x & 0x1FFFFFFF) | 0x80000000); + car->clk_source_nvenc = ((car->clk_source_nvenc & 0x1FFFFFFF) | 0x80000000); +} + +static int tsec_dma_wait_idle() +{ + volatile tegra_tsec_t *tsec = tsec_get_regs(); + uint32_t timeout = (get_time_us() + 10000000); + + while (!(tsec->FALCON_DMATRFCMD & 2)) + if (get_time_us() > timeout) + return 0; + + return 1; +} + +static int tsec_dma_phys_to_flcn(bool is_imem, uint32_t flcn_offset, uint32_t phys_offset) +{ + volatile tegra_tsec_t *tsec = tsec_get_regs(); + uint32_t cmd = 0; + + if (!is_imem) + cmd = 0x600; + else + cmd = 0x10; + + tsec->FALCON_DMATRFMOFFS = flcn_offset; + tsec->FALCON_DMATRFFBOFFS = phys_offset; + tsec->FALCON_DMATRFCMD = cmd; + + return tsec_dma_wait_idle(); +} + +int load_tsec_fw(void) { + volatile uint32_t* tsec_fw = (volatile uint32_t*)0x40010F00; + const uint32_t tsec_fw_length = MAKE_REG32(0x40010EFC); + + volatile tegra_tsec_t *tsec = tsec_get_regs(); + + /* Enable clocks. */ + clkrst_reboot(CARDEVICE_HOST1X); + clkrst_reboot(CARDEVICE_TSEC); + clkrst_reboot(CARDEVICE_SOR_SAFE); + clkrst_reboot(CARDEVICE_SOR0); + clkrst_reboot(CARDEVICE_SOR1); + clkrst_reboot(CARDEVICE_KFUSE); + + /* Configure Falcon. */ + tsec->FALCON_DMACTL = 0; + tsec->FALCON_IRQMSET = 0xFFF2; + tsec->FALCON_IRQDEST = 0xFFF0; + tsec->FALCON_ITFEN = 3; + + if (!tsec_dma_wait_idle()) + { + /* Disable clocks. */ + clkrst_disable(CARDEVICE_KFUSE); + clkrst_disable(CARDEVICE_SOR1); + clkrst_disable(CARDEVICE_SOR0); + clkrst_disable(CARDEVICE_SOR_SAFE); + clkrst_disable(CARDEVICE_TSEC); + clkrst_disable(CARDEVICE_HOST1X); + + return -1; + } + + /* Load firmware. */ + tsec->FALCON_DMATRFBASE = (uint32_t)tsec_fw >> 8; + for (uint32_t addr = 0; addr < tsec_fw_length; addr += 0x100) + { + if (!tsec_dma_phys_to_flcn(true, addr, addr)) + { + /* Disable clocks. */ + clkrst_disable(CARDEVICE_KFUSE); + clkrst_disable(CARDEVICE_SOR1); + clkrst_disable(CARDEVICE_SOR0); + clkrst_disable(CARDEVICE_SOR_SAFE); + clkrst_disable(CARDEVICE_TSEC); + clkrst_disable(CARDEVICE_HOST1X); + + return -2; + } + } + + /* Unknown host1x write. */ + MAKE_HOST1X_REG(0x3300) = 0x34C2E1DA; + + + /* Execute firmware. */ + tsec->FALCON_SCRATCH1 = 0; + tsec->FALCON_SCRATCH0 = 1; + tsec->FALCON_BOOTVEC = 0; + tsec->FALCON_CPUCTL = 2; + + while (true) { + /* Yield to Nintendo's TSEC firmware. */ + } +} + + +int main(void) { + /* Setup vectors */ + setup_exception_vectors(); + + volatile tegra_pmc_t *pmc = pmc_get_regs(); + volatile tegra_car_t *car = car_get_regs(); + + /* Clear the boot reason to avoid problems later */ + pmc->scratch200 = 0; + pmc->reset_status = 0; + + //AHB_AHB_SPARE_REG_0 &= 0xFFFFFF9F; + //pmc->scratch49 = (((pmc->scratch49 >> 1) << 1) & 0xFFFFFFFD); + + /* Apply the memory built-in self test workaround. */ + mbist_workaround(); + + /* Reboot SE. */ + clkrst_reboot(CARDEVICE_SE); + + /* Initialize the fuse driver. */ + fuse_init(); + + /* Don't bother checking SKU, fuses, or bootloader version. */ + mc_enable_for_tsec(); + + /* 7.0.0 package1ldr holds I2C5 in reset, clears SYS clock. */ + car->clk_source_sys = 0; + rst_enable(CARDEVICE_I2C5); + + load_tsec_fw(); + + while (true) { } + return 0; +} diff --git a/sept/sept-primary/src/mc.c b/sept/sept-primary/src/mc.c new file mode 100644 index 000000000..6ee9f5b74 --- /dev/null +++ b/sept/sept-primary/src/mc.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "mc.h" +#include "car.h" +#include "timers.h" + +void mc_enable_for_tsec() +{ + volatile tegra_car_t *car = car_get_regs(); + + /* Set EMC clock source. */ + car->clk_source_emc = ((car->clk_source_emc & 0x1FFFFFFF) | 0x40000000); + + /* Enable MIPI CAL clock. */ + car->clk_enb_h_set = ((car->clk_enb_h_set & 0xFDFFFFFF) | 0x2000000); + + /* Enable MC clock. */ + car->clk_enb_h_set = ((car->clk_enb_h_set & 0xFFFFFFFE) | 1); + + /* Enable EMC DLL clock. */ + car->clk_enb_x_set = ((car->clk_enb_x_set & 0xFFFFBFFF) | 0x4000); + + /* Clear EMC and MC reset. */ + /* NOTE: [4.0.0+] This was changed to use the right register. */ + /* car->rst_dev_h_set = 0x2000001; */ + car->rst_dev_h_clr = 0x2000001; + udelay(5); + + /* Enable AHB redirect, weird boundaries for new TSEC firmware. */ + car->lvl2_clk_gate_ovrd = ((car->lvl2_clk_gate_ovrd & 0xFFF7FFFF) | 0x80000); + + MAKE_MC_REG(MC_IRAM_REG_CTRL) &= 0xFFFFFFFE; + MAKE_MC_REG(MC_IRAM_BOM) = 0x40000000; + MAKE_MC_REG(MC_IRAM_TOM) = 0x80000000; +} \ No newline at end of file diff --git a/sept/sept-primary/src/mc.h b/sept/sept-primary/src/mc.h new file mode 100644 index 000000000..bbdafa15c --- /dev/null +++ b/sept/sept-primary/src/mc.h @@ -0,0 +1,593 @@ +/* + * Copyright (c) 2014, NVIDIA Corporation. All rights reserved. + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef FUSEE_MC_H_ +#define FUSEE_MC_H_ + +#include +#include + +#define MC_BASE 0x70019000 +#define MAKE_MC_REG(n) MAKE_REG32(MC_BASE + n) + +#define MC_INTSTATUS 0x0 +#define MC_INTMASK 0x4 +#define MC_ERR_STATUS 0x8 +#define MC_ERR_ADR 0xc +#define MC_SMMU_CONFIG 0x10 +#define MC_SMMU_TLB_CONFIG 0x14 +#define MC_SMMU_PTC_CONFIG 0x18 +#define MC_SMMU_PTB_ASID 0x1c +#define MC_SMMU_PTB_DATA 0x20 +#define MC_SMMU_TLB_FLUSH 0x30 +#define MC_SMMU_PTC_FLUSH 0x34 +#define MC_SMMU_ASID_SECURITY 0x38 +#define MC_SMMU_AFI_ASID 0x238 +#define MC_SMMU_AVPC_ASID 0x23c +#define MC_SMMU_TSEC_ASID 0x294 +#define MC_SMMU_PPCS1_ASID 0x298 +#define MC_SMMU_TRANSLATION_ENABLE_0 0x228 +#define MC_SMMU_TRANSLATION_ENABLE_1 0x22c +#define MC_SMMU_TRANSLATION_ENABLE_2 0x230 +#define MC_SMMU_TRANSLATION_ENABLE_3 0x234 +#define MC_SMMU_TRANSLATION_ENABLE_4 0xb98 +#define MC_PCFIFO_CLIENT_CONFIG0 0xdd0 +#define MC_PCFIFO_CLIENT_CONFIG1 0xdd4 +#define MC_PCFIFO_CLIENT_CONFIG2 0xdd8 +#define MC_PCFIFO_CLIENT_CONFIG3 0xddc +#define MC_PCFIFO_CLIENT_CONFIG4 0xde0 +#define MC_EMEM_CFG 0x50 +#define MC_EMEM_ADR_CFG 0x54 +#define MC_EMEM_ADR_CFG_DEV0 0x58 +#define MC_EMEM_ADR_CFG_DEV1 0x5c +#define MC_EMEM_ADR_CFG_CHANNEL_MASK 0x60 +#define MC_EMEM_ADR_CFG_BANK_MASK_0 0x64 +#define MC_EMEM_ADR_CFG_BANK_MASK_1 0x68 +#define MC_EMEM_ADR_CFG_BANK_MASK_2 0x6c +#define MC_SECURITY_CFG0 0x70 +#define MC_SECURITY_CFG1 0x74 +#define MC_SECURITY_CFG3 0x9bc +#define MC_SECURITY_RSV 0x7c +#define MC_EMEM_ARB_CFG 0x90 +#define MC_EMEM_ARB_OUTSTANDING_REQ 0x94 +#define MC_EMEM_ARB_TIMING_RCD 0x98 +#define MC_EMEM_ARB_TIMING_RP 0x9c +#define MC_EMEM_ARB_TIMING_RC 0xa0 +#define MC_EMEM_ARB_TIMING_RAS 0xa4 +#define MC_EMEM_ARB_TIMING_FAW 0xa8 +#define MC_EMEM_ARB_TIMING_RRD 0xac +#define MC_EMEM_ARB_TIMING_RAP2PRE 0xb0 +#define MC_EMEM_ARB_TIMING_WAP2PRE 0xb4 +#define MC_EMEM_ARB_TIMING_R2R 0xb8 +#define MC_EMEM_ARB_TIMING_W2W 0xbc +#define MC_EMEM_ARB_TIMING_R2W 0xc0 +#define MC_EMEM_ARB_TIMING_W2R 0xc4 +#define MC_EMEM_ARB_TIMING_RFCPB 0x6c0 +#define MC_EMEM_ARB_TIMING_CCDMW 0x6c4 +#define MC_EMEM_ARB_REFPB_HP_CTRL 0x6f0 +#define MC_EMEM_ARB_REFPB_BANK_CTRL 0x6f4 +#define MC_EMEM_ARB_DA_TURNS 0xd0 +#define MC_EMEM_ARB_DA_COVERS 0xd4 +#define MC_EMEM_ARB_MISC0 0xd8 +#define MC_EMEM_ARB_MISC1 0xdc +#define MC_EMEM_ARB_MISC2 0xc8 +#define MC_EMEM_ARB_RING1_THROTTLE 0xe0 +#define MC_EMEM_ARB_RING3_THROTTLE 0xe4 +#define MC_EMEM_ARB_NISO_THROTTLE 0x6b0 +#define MC_EMEM_ARB_OVERRIDE 0xe8 +#define MC_EMEM_ARB_RSV 0xec +#define MC_CLKEN_OVERRIDE 0xf4 +#define MC_TIMING_CONTROL_DBG 0xf8 +#define MC_TIMING_CONTROL 0xfc +#define MC_STAT_CONTROL 0x100 +#define MC_STAT_STATUS 0x104 +#define MC_STAT_EMC_CLOCK_LIMIT 0x108 +#define MC_STAT_EMC_CLOCK_LIMIT_MSBS 0x10c +#define MC_STAT_EMC_CLOCKS 0x110 +#define MC_STAT_EMC_CLOCKS_MSBS 0x114 +#define MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_LO 0x118 +#define MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_LO 0x158 +#define MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_HI 0x11c +#define MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_HI 0x15c +#define MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_UPPER 0xa20 +#define MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_UPPER 0xa24 +#define MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_LO 0x198 +#define MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_LO 0x1a8 +#define MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_HI 0x19c +#define MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_HI 0x1ac +#define MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_UPPER 0xa28 +#define MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_UPPER 0xa2c +#define MC_STAT_EMC_FILTER_SET0_ASID 0x1a0 +#define MC_STAT_EMC_FILTER_SET1_ASID 0x1b0 +#define MC_STAT_EMC_FILTER_SET0_SLACK_LIMIT 0x120 +#define MC_STAT_EMC_FILTER_SET1_SLACK_LIMIT 0x160 +#define MC_STAT_EMC_FILTER_SET0_CLIENT_0 0x128 +#define MC_STAT_EMC_FILTER_SET1_CLIENT_0 0x168 +#define MC_STAT_EMC_FILTER_SET0_CLIENT_1 0x12c +#define MC_STAT_EMC_FILTER_SET1_CLIENT_1 0x16c +#define MC_STAT_EMC_FILTER_SET0_CLIENT_2 0x130 +#define MC_STAT_EMC_FILTER_SET1_CLIENT_2 0x170 +#define MC_STAT_EMC_FILTER_SET0_CLIENT_3 0x134 +#define MC_STAT_EMC_FILTER_SET0_CLIENT_4 0xb88 +#define MC_STAT_EMC_FILTER_SET1_CLIENT_3 0x174 +#define MC_STAT_EMC_FILTER_SET1_CLIENT_4 0xb8c +#define MC_STAT_EMC_SET0_COUNT 0x138 +#define MC_STAT_EMC_SET0_COUNT_MSBS 0x13c +#define MC_STAT_EMC_SET1_COUNT 0x178 +#define MC_STAT_EMC_SET1_COUNT_MSBS 0x17c +#define MC_STAT_EMC_SET0_SLACK_ACCUM 0x140 +#define MC_STAT_EMC_SET0_SLACK_ACCUM_MSBS 0x144 +#define MC_STAT_EMC_SET1_SLACK_ACCUM 0x180 +#define MC_STAT_EMC_SET1_SLACK_ACCUM_MSBS 0x184 +#define MC_STAT_EMC_SET0_HISTO_COUNT 0x148 +#define MC_STAT_EMC_SET0_HISTO_COUNT_MSBS 0x14c +#define MC_STAT_EMC_SET1_HISTO_COUNT 0x188 +#define MC_STAT_EMC_SET1_HISTO_COUNT_MSBS 0x18c +#define MC_STAT_EMC_SET0_MINIMUM_SLACK_OBSERVED 0x150 +#define MC_STAT_EMC_SET1_MINIMUM_SLACK_OBSERVED 0x190 +#define MC_STAT_EMC_SET0_IDLE_CYCLE_COUNT 0x1b8 +#define MC_STAT_EMC_SET0_IDLE_CYCL_COUNT_MSBS 0x1bc +#define MC_STAT_EMC_SET1_IDLE_CYCLE_COUNT 0x1c8 +#define MC_STAT_EMC_SET1_IDLE_CYCL_COUNT_MSBS 0x1cc +#define MC_STAT_EMC_SET0_IDLE_CYCLE_PARTITION_SELECT 0x1c0 +#define MC_STAT_EMC_SET1_IDLE_CYCLE_PARTITION_SELECT 0x1d0 +#define MC_CLIENT_HOTRESET_CTRL 0x200 +#define MC_CLIENT_HOTRESET_CTRL_1 0x970 +#define MC_CLIENT_HOTRESET_STATUS 0x204 +#define MC_CLIENT_HOTRESET_STATUS_1 0x974 +#define MC_EMEM_ARB_ISOCHRONOUS_0 0x208 +#define MC_EMEM_ARB_ISOCHRONOUS_1 0x20c +#define MC_EMEM_ARB_ISOCHRONOUS_2 0x210 +#define MC_EMEM_ARB_ISOCHRONOUS_3 0x214 +#define MC_EMEM_ARB_ISOCHRONOUS_4 0xb94 +#define MC_EMEM_ARB_HYSTERESIS_0 0x218 +#define MC_EMEM_ARB_HYSTERESIS_1 0x21c +#define MC_EMEM_ARB_HYSTERESIS_2 0x220 +#define MC_EMEM_ARB_HYSTERESIS_3 0x224 +#define MC_EMEM_ARB_HYSTERESIS_4 0xb84 +#define MC_EMEM_ARB_DHYSTERESIS_0 0xbb0 +#define MC_EMEM_ARB_DHYSTERESIS_1 0xbb4 +#define MC_EMEM_ARB_DHYSTERESIS_2 0xbb8 +#define MC_EMEM_ARB_DHYSTERESIS_3 0xbbc +#define MC_EMEM_ARB_DHYSTERESIS_4 0xbc0 +#define MC_EMEM_ARB_DHYST_CTRL 0xbcc +#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_0 0xbd0 +#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_1 0xbd4 +#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_2 0xbd8 +#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_3 0xbdc +#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_4 0xbe0 +#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_5 0xbe4 +#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_6 0xbe8 +#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_7 0xbec +#define MC_RESERVED_RSV 0x3fc +#define MC_DISB_EXTRA_SNAP_LEVELS 0x408 +#define MC_APB_EXTRA_SNAP_LEVELS 0x2a4 +#define MC_AHB_EXTRA_SNAP_LEVELS 0x2a0 +#define MC_USBD_EXTRA_SNAP_LEVELS 0xa18 +#define MC_ISP_EXTRA_SNAP_LEVELS 0xa08 +#define MC_AUD_EXTRA_SNAP_LEVELS 0xa10 +#define MC_MSE_EXTRA_SNAP_LEVELS 0x40c +#define MC_GK2_EXTRA_SNAP_LEVELS 0xa40 +#define MC_A9AVPPC_EXTRA_SNAP_LEVELS 0x414 +#define MC_FTOP_EXTRA_SNAP_LEVELS 0x2bc +#define MC_JPG_EXTRA_SNAP_LEVELS 0xa3c +#define MC_HOST_EXTRA_SNAP_LEVELS 0xa14 +#define MC_SAX_EXTRA_SNAP_LEVELS 0x2c0 +#define MC_DIS_EXTRA_SNAP_LEVELS 0x2ac +#define MC_VICPC_EXTRA_SNAP_LEVELS 0xa1c +#define MC_HDAPC_EXTRA_SNAP_LEVELS 0xa48 +#define MC_AVP_EXTRA_SNAP_LEVELS 0x2a8 +#define MC_USBX_EXTRA_SNAP_LEVELS 0x404 +#define MC_PCX_EXTRA_SNAP_LEVELS 0x2b8 +#define MC_SD_EXTRA_SNAP_LEVELS 0xa04 +#define MC_DFD_EXTRA_SNAP_LEVELS 0xa4c +#define MC_VE_EXTRA_SNAP_LEVELS 0x2d8 +#define MC_GK_EXTRA_SNAP_LEVELS 0xa00 +#define MC_VE2_EXTRA_SNAP_LEVELS 0x410 +#define MC_SDM_EXTRA_SNAP_LEVELS 0xa44 +#define MC_VIDEO_PROTECT_BOM 0x648 +#define MC_VIDEO_PROTECT_SIZE_MB 0x64c +#define MC_VIDEO_PROTECT_BOM_ADR_HI 0x978 +#define MC_VIDEO_PROTECT_REG_CTRL 0x650 +#define MC_ERR_VPR_STATUS 0x654 +#define MC_ERR_VPR_ADR 0x658 +#define MC_VIDEO_PROTECT_VPR_OVERRIDE 0x418 +#define MC_VIDEO_PROTECT_VPR_OVERRIDE1 0x590 +#define MC_IRAM_BOM 0x65c +#define MC_IRAM_TOM 0x660 +#define MC_IRAM_ADR_HI 0x980 +#define MC_IRAM_REG_CTRL 0x964 +#define MC_EMEM_CFG_ACCESS_CTRL 0x664 +#define MC_TZ_SECURITY_CTRL 0x668 +#define MC_EMEM_ARB_OUTSTANDING_REQ_RING3 0x66c +#define MC_EMEM_ARB_OUTSTANDING_REQ_NISO 0x6b4 +#define MC_EMEM_ARB_RING0_THROTTLE_MASK 0x6bc +#define MC_EMEM_ARB_NISO_THROTTLE_MASK 0x6b8 +#define MC_EMEM_ARB_NISO_THROTTLE_MASK_1 0xb80 +#define MC_SEC_CARVEOUT_BOM 0x670 +#define MC_SEC_CARVEOUT_SIZE_MB 0x674 +#define MC_SEC_CARVEOUT_ADR_HI 0x9d4 +#define MC_SEC_CARVEOUT_REG_CTRL 0x678 +#define MC_ERR_SEC_STATUS 0x67c +#define MC_ERR_SEC_ADR 0x680 +#define MC_PC_IDLE_CLOCK_GATE_CONFIG 0x684 +#define MC_STUTTER_CONTROL 0x688 +#define MC_RESERVED_RSV_1 0x958 +#define MC_DVFS_PIPE_SELECT 0x95c +#define MC_AHB_PTSA_MIN 0x4e0 +#define MC_AUD_PTSA_MIN 0x54c +#define MC_MLL_MPCORER_PTSA_RATE 0x44c +#define MC_RING2_PTSA_RATE 0x440 +#define MC_USBD_PTSA_RATE 0x530 +#define MC_USBX_PTSA_MIN 0x528 +#define MC_USBD_PTSA_MIN 0x534 +#define MC_APB_PTSA_MAX 0x4f0 +#define MC_JPG_PTSA_RATE 0x584 +#define MC_DIS_PTSA_MIN 0x420 +#define MC_AVP_PTSA_MAX 0x4fc +#define MC_AVP_PTSA_RATE 0x4f4 +#define MC_RING1_PTSA_MIN 0x480 +#define MC_DIS_PTSA_MAX 0x424 +#define MC_SD_PTSA_MAX 0x4d8 +#define MC_MSE_PTSA_RATE 0x4c4 +#define MC_VICPC_PTSA_MIN 0x558 +#define MC_PCX_PTSA_MAX 0x4b4 +#define MC_ISP_PTSA_RATE 0x4a0 +#define MC_A9AVPPC_PTSA_MIN 0x48c +#define MC_RING2_PTSA_MAX 0x448 +#define MC_AUD_PTSA_RATE 0x548 +#define MC_HOST_PTSA_MIN 0x51c +#define MC_MLL_MPCORER_PTSA_MAX 0x454 +#define MC_SD_PTSA_MIN 0x4d4 +#define MC_RING1_PTSA_RATE 0x47c +#define MC_JPG_PTSA_MIN 0x588 +#define MC_HDAPC_PTSA_MIN 0x62c +#define MC_AVP_PTSA_MIN 0x4f8 +#define MC_JPG_PTSA_MAX 0x58c +#define MC_VE_PTSA_MAX 0x43c +#define MC_DFD_PTSA_MAX 0x63c +#define MC_VICPC_PTSA_RATE 0x554 +#define MC_GK_PTSA_MAX 0x544 +#define MC_VICPC_PTSA_MAX 0x55c +#define MC_SDM_PTSA_MAX 0x624 +#define MC_SAX_PTSA_RATE 0x4b8 +#define MC_PCX_PTSA_MIN 0x4b0 +#define MC_APB_PTSA_MIN 0x4ec +#define MC_GK2_PTSA_MIN 0x614 +#define MC_PCX_PTSA_RATE 0x4ac +#define MC_RING1_PTSA_MAX 0x484 +#define MC_HDAPC_PTSA_RATE 0x628 +#define MC_MLL_MPCORER_PTSA_MIN 0x450 +#define MC_GK2_PTSA_MAX 0x618 +#define MC_AUD_PTSA_MAX 0x550 +#define MC_GK2_PTSA_RATE 0x610 +#define MC_ISP_PTSA_MAX 0x4a8 +#define MC_DISB_PTSA_RATE 0x428 +#define MC_VE2_PTSA_MAX 0x49c +#define MC_DFD_PTSA_MIN 0x638 +#define MC_FTOP_PTSA_RATE 0x50c +#define MC_A9AVPPC_PTSA_RATE 0x488 +#define MC_VE2_PTSA_MIN 0x498 +#define MC_USBX_PTSA_MAX 0x52c +#define MC_DIS_PTSA_RATE 0x41c +#define MC_USBD_PTSA_MAX 0x538 +#define MC_A9AVPPC_PTSA_MAX 0x490 +#define MC_USBX_PTSA_RATE 0x524 +#define MC_FTOP_PTSA_MAX 0x514 +#define MC_HDAPC_PTSA_MAX 0x630 +#define MC_SD_PTSA_RATE 0x4d0 +#define MC_DFD_PTSA_RATE 0x634 +#define MC_FTOP_PTSA_MIN 0x510 +#define MC_SDM_PTSA_RATE 0x61c +#define MC_AHB_PTSA_RATE 0x4dc +#define MC_SMMU_SMMU_PTSA_MAX 0x460 +#define MC_RING2_PTSA_MIN 0x444 +#define MC_SDM_PTSA_MIN 0x620 +#define MC_APB_PTSA_RATE 0x4e8 +#define MC_MSE_PTSA_MIN 0x4c8 +#define MC_HOST_PTSA_RATE 0x518 +#define MC_VE_PTSA_RATE 0x434 +#define MC_AHB_PTSA_MAX 0x4e4 +#define MC_SAX_PTSA_MIN 0x4bc +#define MC_SMMU_SMMU_PTSA_MIN 0x45c +#define MC_ISP_PTSA_MIN 0x4a4 +#define MC_HOST_PTSA_MAX 0x520 +#define MC_SAX_PTSA_MAX 0x4c0 +#define MC_VE_PTSA_MIN 0x438 +#define MC_GK_PTSA_MIN 0x540 +#define MC_MSE_PTSA_MAX 0x4cc +#define MC_DISB_PTSA_MAX 0x430 +#define MC_DISB_PTSA_MIN 0x42c +#define MC_SMMU_SMMU_PTSA_RATE 0x458 +#define MC_VE2_PTSA_RATE 0x494 +#define MC_GK_PTSA_RATE 0x53c +#define MC_PTSA_GRANT_DECREMENT 0x960 +#define MC_LATENCY_ALLOWANCE_AVPC_0 0x2e4 +#define MC_LATENCY_ALLOWANCE_AXIAP_0 0x3a0 +#define MC_LATENCY_ALLOWANCE_XUSB_1 0x380 +#define MC_LATENCY_ALLOWANCE_ISP2B_0 0x384 +#define MC_LATENCY_ALLOWANCE_SDMMCAA_0 0x3bc +#define MC_LATENCY_ALLOWANCE_SDMMCA_0 0x3b8 +#define MC_LATENCY_ALLOWANCE_ISP2_0 0x370 +#define MC_LATENCY_ALLOWANCE_SE_0 0x3e0 +#define MC_LATENCY_ALLOWANCE_ISP2_1 0x374 +#define MC_LATENCY_ALLOWANCE_DC_0 0x2e8 +#define MC_LATENCY_ALLOWANCE_VIC_0 0x394 +#define MC_LATENCY_ALLOWANCE_DCB_1 0x2f8 +#define MC_LATENCY_ALLOWANCE_NVDEC_0 0x3d8 +#define MC_LATENCY_ALLOWANCE_DCB_2 0x2fc +#define MC_LATENCY_ALLOWANCE_TSEC_0 0x390 +#define MC_LATENCY_ALLOWANCE_DC_2 0x2f0 +#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0AB 0x694 +#define MC_LATENCY_ALLOWANCE_PPCS_1 0x348 +#define MC_LATENCY_ALLOWANCE_XUSB_0 0x37c +#define MC_LATENCY_ALLOWANCE_PPCS_0 0x344 +#define MC_LATENCY_ALLOWANCE_TSECB_0 0x3f0 +#define MC_LATENCY_ALLOWANCE_AFI_0 0x2e0 +#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0B 0x698 +#define MC_LATENCY_ALLOWANCE_DC_1 0x2ec +#define MC_LATENCY_ALLOWANCE_APE_0 0x3dc +#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0C 0x6a0 +#define MC_LATENCY_ALLOWANCE_A9AVP_0 0x3a4 +#define MC_LATENCY_ALLOWANCE_GPU2_0 0x3e8 +#define MC_LATENCY_ALLOWANCE_DCB_0 0x2f4 +#define MC_LATENCY_ALLOWANCE_HC_1 0x314 +#define MC_LATENCY_ALLOWANCE_SDMMC_0 0x3c0 +#define MC_LATENCY_ALLOWANCE_NVJPG_0 0x3e4 +#define MC_LATENCY_ALLOWANCE_PTC_0 0x34c +#define MC_LATENCY_ALLOWANCE_ETR_0 0x3ec +#define MC_LATENCY_ALLOWANCE_MPCORE_0 0x320 +#define MC_LATENCY_ALLOWANCE_VI2_0 0x398 +#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0BB 0x69c +#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0CB 0x6a4 +#define MC_LATENCY_ALLOWANCE_SATA_0 0x350 +#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0A 0x690 +#define MC_LATENCY_ALLOWANCE_HC_0 0x310 +#define MC_LATENCY_ALLOWANCE_DC_3 0x3c8 +#define MC_LATENCY_ALLOWANCE_GPU_0 0x3ac +#define MC_LATENCY_ALLOWANCE_SDMMCAB_0 0x3c4 +#define MC_LATENCY_ALLOWANCE_ISP2B_1 0x388 +#define MC_LATENCY_ALLOWANCE_NVENC_0 0x328 +#define MC_LATENCY_ALLOWANCE_HDA_0 0x318 +#define MC_MIN_LENGTH_APE_0 0xb34 +#define MC_MIN_LENGTH_DCB_2 0x8a8 +#define MC_MIN_LENGTH_A9AVP_0 0x950 +#define MC_MIN_LENGTH_TSEC_0 0x93c +#define MC_MIN_LENGTH_DC_1 0x898 +#define MC_MIN_LENGTH_AXIAP_0 0x94c +#define MC_MIN_LENGTH_ISP2B_0 0x930 +#define MC_MIN_LENGTH_VI2_0 0x944 +#define MC_MIN_LENGTH_DCB_0 0x8a0 +#define MC_MIN_LENGTH_DCB_1 0x8a4 +#define MC_MIN_LENGTH_PPCS_1 0x8f4 +#define MC_MIN_LENGTH_NVJPG_0 0xb3c +#define MC_MIN_LENGTH_HDA_0 0x8c4 +#define MC_MIN_LENGTH_NVENC_0 0x8d4 +#define MC_MIN_LENGTH_SDMMC_0 0xb18 +#define MC_MIN_LENGTH_ISP2B_1 0x934 +#define MC_MIN_LENGTH_HC_1 0x8c0 +#define MC_MIN_LENGTH_DC_3 0xb20 +#define MC_MIN_LENGTH_AVPC_0 0x890 +#define MC_MIN_LENGTH_VIC_0 0x940 +#define MC_MIN_LENGTH_ISP2_0 0x91c +#define MC_MIN_LENGTH_HC_0 0x8bc +#define MC_MIN_LENGTH_SE_0 0xb38 +#define MC_MIN_LENGTH_NVDEC_0 0xb30 +#define MC_MIN_LENGTH_SATA_0 0x8fc +#define MC_MIN_LENGTH_DC_0 0x894 +#define MC_MIN_LENGTH_XUSB_1 0x92c +#define MC_MIN_LENGTH_DC_2 0x89c +#define MC_MIN_LENGTH_SDMMCAA_0 0xb14 +#define MC_MIN_LENGTH_GPU_0 0xb04 +#define MC_MIN_LENGTH_ETR_0 0xb44 +#define MC_MIN_LENGTH_AFI_0 0x88c +#define MC_MIN_LENGTH_PPCS_0 0x8f0 +#define MC_MIN_LENGTH_ISP2_1 0x920 +#define MC_MIN_LENGTH_XUSB_0 0x928 +#define MC_MIN_LENGTH_MPCORE_0 0x8cc +#define MC_MIN_LENGTH_TSECB_0 0xb48 +#define MC_MIN_LENGTH_SDMMCA_0 0xb10 +#define MC_MIN_LENGTH_GPU2_0 0xb40 +#define MC_MIN_LENGTH_SDMMCAB_0 0xb1c +#define MC_MIN_LENGTH_PTC_0 0x8f8 +#define MC_EMEM_ARB_OVERRIDE_1 0x968 +#define MC_VIDEO_PROTECT_GPU_OVERRIDE_0 0x984 +#define MC_VIDEO_PROTECT_GPU_OVERRIDE_1 0x988 +#define MC_EMEM_ARB_STATS_0 0x990 +#define MC_EMEM_ARB_STATS_1 0x994 +#define MC_MTS_CARVEOUT_BOM 0x9a0 +#define MC_MTS_CARVEOUT_SIZE_MB 0x9a4 +#define MC_MTS_CARVEOUT_ADR_HI 0x9a8 +#define MC_MTS_CARVEOUT_REG_CTRL 0x9ac +#define MC_ERR_MTS_STATUS 0x9b0 +#define MC_ERR_MTS_ADR 0x9b4 +#define MC_ERR_GENERALIZED_CARVEOUT_STATUS 0xc00 +#define MC_ERR_GENERALIZED_CARVEOUT_ADR 0xc04 +#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS2 0xd74 +#define MC_SECURITY_CARVEOUT4_CFG0 0xcf8 +#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS2 0xd10 +#define MC_SECURITY_CARVEOUT4_SIZE_128KB 0xd04 +#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4 0xc28 +#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS1 0xc30 +#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4 0xc8c +#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS0 0xd1c +#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS1 0xd70 +#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS0 0xc2c +#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS4 0xd7c +#define MC_SECURITY_CARVEOUT3_SIZE_128KB 0xcb4 +#define MC_SECURITY_CARVEOUT2_CFG0 0xc58 +#define MC_SECURITY_CARVEOUT1_CFG0 0xc08 +#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2 0xc84 +#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0 0xc68 +#define MC_SECURITY_CARVEOUT3_BOM 0xcac +#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2 0xc70 +#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS3 0xd78 +#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0 0xc7c +#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS4 0xd18 +#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS1 0xcbc +#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS3 0xc38 +#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS2 0xc34 +#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2 0xcc0 +#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS2 0xd60 +#define MC_SECURITY_CARVEOUT3_CFG0 0xca8 +#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS0 0xcb8 +#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3 0xc88 +#define MC_SECURITY_CARVEOUT2_SIZE_128KB 0xc64 +#define MC_SECURITY_CARVEOUT5_BOM_HI 0xd50 +#define MC_SECURITY_CARVEOUT1_SIZE_128KB 0xc14 +#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS3 0xd14 +#define MC_SECURITY_CARVEOUT1_BOM 0xc0c +#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4 0xd2c +#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS4 0xd68 +#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4 0xcc8 +#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS0 0xd58 +#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS2 0xd24 +#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS3 0xcc4 +#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4 0xc78 +#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1 0xc1c +#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0 0xc18 +#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3 0xd28 +#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS1 0xd5c +#define MC_SECURITY_CARVEOUT3_BOM_HI 0xcb0 +#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3 0xcd8 +#define MC_SECURITY_CARVEOUT2_BOM_HI 0xc60 +#define MC_SECURITY_CARVEOUT4_BOM_HI 0xd00 +#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS3 0xd64 +#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4 0xcdc +#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1 0xc80 +#define MC_SECURITY_CARVEOUT5_SIZE_128KB 0xd54 +#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS1 0xd20 +#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS2 0xcd4 +#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS1 0xd0c +#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3 0xc74 +#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS0 0xccc +#define MC_SECURITY_CARVEOUT4_BOM 0xcfc +#define MC_SECURITY_CARVEOUT5_CFG0 0xd48 +#define MC_SECURITY_CARVEOUT2_BOM 0xc5c +#define MC_SECURITY_CARVEOUT5_BOM 0xd4c +#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3 0xc24 +#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS0 0xd6c +#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS1 0xcd0 +#define MC_SECURITY_CARVEOUT1_BOM_HI 0xc10 +#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2 0xc20 +#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4 0xc3c +#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1 0xc6c +#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS0 0xd08 +#define MC_ERR_APB_ASID_UPDATE_STATUS 0x9d0 +#define MC_DA_CONFIG0 0x9dc + +/* Memory Controller clients */ +#define CLIENT_ACCESS_NUM_CLIENTS 32 +typedef enum { + /* _ACCESS0 */ + CSR_PTCR = (0 - (CLIENT_ACCESS_NUM_CLIENTS * 0)), + CSR_DISPLAY0A = (1 - (CLIENT_ACCESS_NUM_CLIENTS * 0)), + CSR_DISPLAY0AB = (2 - (CLIENT_ACCESS_NUM_CLIENTS * 0)), + CSR_DISPLAY0B = (3 - (CLIENT_ACCESS_NUM_CLIENTS * 0)), + CSR_DISPLAY0BB = (4 - (CLIENT_ACCESS_NUM_CLIENTS * 0)), + CSR_DISPLAY0C = (5 - (CLIENT_ACCESS_NUM_CLIENTS * 0)), + CSR_DISPLAY0CB = (6 - (CLIENT_ACCESS_NUM_CLIENTS * 0)), + CSR_AFIR = (14 - (CLIENT_ACCESS_NUM_CLIENTS * 0)), + CSR_AVPCARM7R = (15 - (CLIENT_ACCESS_NUM_CLIENTS * 0)), + CSR_DISPLAYHC = (16 - (CLIENT_ACCESS_NUM_CLIENTS * 0)), + CSR_DISPLAYHCB = (17 - (CLIENT_ACCESS_NUM_CLIENTS * 0)), + CSR_HDAR = (21 - (CLIENT_ACCESS_NUM_CLIENTS * 0)), + CSR_HOST1XDMAR = (22 - (CLIENT_ACCESS_NUM_CLIENTS * 0)), + CSR_HOST1XR = (23 - (CLIENT_ACCESS_NUM_CLIENTS * 0)), + CSR_NVENCSRD = (28 - (CLIENT_ACCESS_NUM_CLIENTS * 0)), + CSR_PPCSAHBDMAR = (29 - (CLIENT_ACCESS_NUM_CLIENTS * 0)), + CSR_PPCSAHBSLVR = (30 - (CLIENT_ACCESS_NUM_CLIENTS * 0)), + CSR_SATAR = (31 - (CLIENT_ACCESS_NUM_CLIENTS * 0)), + + /* _ACCESS1 */ + CSR_VDEBSEVR = (34 - (CLIENT_ACCESS_NUM_CLIENTS * 1)), + CSR_VDEMBER = (35 - (CLIENT_ACCESS_NUM_CLIENTS * 1)), + CSR_VDEMCER = (36 - (CLIENT_ACCESS_NUM_CLIENTS * 1)), + CSR_VDETPER = (37 - (CLIENT_ACCESS_NUM_CLIENTS * 1)), + CSR_MPCORELPR = (38 - (CLIENT_ACCESS_NUM_CLIENTS * 1)), + CSR_MPCORER = (39 - (CLIENT_ACCESS_NUM_CLIENTS * 1)), + CSW_NVENCSWR = (43 - (CLIENT_ACCESS_NUM_CLIENTS * 1)), + CSW_AFIW = (49 - (CLIENT_ACCESS_NUM_CLIENTS * 1)), + CSW_AVPCARM7W = (50 - (CLIENT_ACCESS_NUM_CLIENTS * 1)), + CSW_HDAW = (53 - (CLIENT_ACCESS_NUM_CLIENTS * 1)), + CSW_HOST1XW = (54 - (CLIENT_ACCESS_NUM_CLIENTS * 1)), + CSW_MPCORELPW = (56 - (CLIENT_ACCESS_NUM_CLIENTS * 1)), + CSW_MPCOREW = (57 - (CLIENT_ACCESS_NUM_CLIENTS * 1)), + CSW_PPCSAHBDMAW = (59 - (CLIENT_ACCESS_NUM_CLIENTS * 1)), + CSW_PPCSAHBSLVW = (60 - (CLIENT_ACCESS_NUM_CLIENTS * 1)), + CSW_SATAW = (61 - (CLIENT_ACCESS_NUM_CLIENTS * 1)), + CSW_VDEBSEVW = (62 - (CLIENT_ACCESS_NUM_CLIENTS * 1)), + CSW_VDEDBGW = (63 - (CLIENT_ACCESS_NUM_CLIENTS * 1)), + + /* _ACCESS2 */ + CSW_VDEMBEW = (64 - (CLIENT_ACCESS_NUM_CLIENTS * 2)), + CSW_VDETPMW = (65 - (CLIENT_ACCESS_NUM_CLIENTS * 2)), + CSR_ISPRA = (68 - (CLIENT_ACCESS_NUM_CLIENTS * 2)), + CSW_ISPWA = (70 - (CLIENT_ACCESS_NUM_CLIENTS * 2)), + CSW_ISPWB = (71 - (CLIENT_ACCESS_NUM_CLIENTS * 2)), + CSR_XUSB_HOSTR = (74 - (CLIENT_ACCESS_NUM_CLIENTS * 2)), + CSW_XUSB_HOSTW = (75 - (CLIENT_ACCESS_NUM_CLIENTS * 2)), + CSR_XUSB_DEVR = (76 - (CLIENT_ACCESS_NUM_CLIENTS * 2)), + CSW_XUSB_DEVW = (77 - (CLIENT_ACCESS_NUM_CLIENTS * 2)), + CSR_ISPRAB = (78 - (CLIENT_ACCESS_NUM_CLIENTS * 2)), + CSW_ISPWAB = (80 - (CLIENT_ACCESS_NUM_CLIENTS * 2)), + CSW_ISPWBB = (81 - (CLIENT_ACCESS_NUM_CLIENTS * 2)), + CSR_TSECSRD = (84 - (CLIENT_ACCESS_NUM_CLIENTS * 2)), + CSW_TSECSWR = (85 - (CLIENT_ACCESS_NUM_CLIENTS * 2)), + CSR_A9AVPSCR = (86 - (CLIENT_ACCESS_NUM_CLIENTS * 2)), + CSW_A9AVPSCW = (87 - (CLIENT_ACCESS_NUM_CLIENTS * 2)), + CSR_GPUSRD = (88 - (CLIENT_ACCESS_NUM_CLIENTS * 2)), + CSW_GPUSWR = (89 - (CLIENT_ACCESS_NUM_CLIENTS * 2)), + CSR_DISPLAYT = (90 - (CLIENT_ACCESS_NUM_CLIENTS * 2)), + + /* _ACCESS3 */ + CSR_SDMMCRA = (96 - (CLIENT_ACCESS_NUM_CLIENTS * 3)), + CSR_SDMMCRAA = (97 - (CLIENT_ACCESS_NUM_CLIENTS * 3)), + CSR_SDMMCR = (98 - (CLIENT_ACCESS_NUM_CLIENTS * 3)), + CSR_SDMMCRAB = (99 - (CLIENT_ACCESS_NUM_CLIENTS * 3)), + CSW_SDMMCWA = (100 - (CLIENT_ACCESS_NUM_CLIENTS * 3)), + CSW_SDMMCWAA = (101 - (CLIENT_ACCESS_NUM_CLIENTS * 3)), + CSW_SDMMCW = (102 - (CLIENT_ACCESS_NUM_CLIENTS * 3)), + CSW_SDMMCWAB = (103 - (CLIENT_ACCESS_NUM_CLIENTS * 3)), + CSR_VICSRD = (108 - (CLIENT_ACCESS_NUM_CLIENTS * 3)), + CSW_VICSWR = (109 - (CLIENT_ACCESS_NUM_CLIENTS * 3)), + CSW_VIW = (114 - (CLIENT_ACCESS_NUM_CLIENTS * 3)), + CSR_DISPLAYD = (115 - (CLIENT_ACCESS_NUM_CLIENTS * 3)), + CSR_NVDECSRD = (120 - (CLIENT_ACCESS_NUM_CLIENTS * 3)), + CSW_NVDECSWR = (121 - (CLIENT_ACCESS_NUM_CLIENTS * 3)), + CSR_APER = (122 - (CLIENT_ACCESS_NUM_CLIENTS * 3)), + CSW_APEW = (123 - (CLIENT_ACCESS_NUM_CLIENTS * 3)), + CSR_NVJPGSRD = (126 - (CLIENT_ACCESS_NUM_CLIENTS * 3)), + CSW_NVJPGSWR = (127 - (CLIENT_ACCESS_NUM_CLIENTS * 3)), + + /* _ACCESS4 */ + CSR_SESRD = (128 - (CLIENT_ACCESS_NUM_CLIENTS * 4)), + CSW_SESWR = (129 - (CLIENT_ACCESS_NUM_CLIENTS * 4)), + CSR_AXIAPR = (130 - (CLIENT_ACCESS_NUM_CLIENTS * 4)), + CSW_AXIAPW = (131 - (CLIENT_ACCESS_NUM_CLIENTS * 4)), + CSR_ETRR = (132 - (CLIENT_ACCESS_NUM_CLIENTS * 4)), + CSW_ETRW = (133 - (CLIENT_ACCESS_NUM_CLIENTS * 4)), + CSR_TSECSRDB = (134 - (CLIENT_ACCESS_NUM_CLIENTS * 4)), + CSW_TSECSWRB = (135 - (CLIENT_ACCESS_NUM_CLIENTS * 4)), + CSR_GPUSRD2 = (136 - (CLIENT_ACCESS_NUM_CLIENTS * 4)), + CSW_GPUSWR2 = (137 - (CLIENT_ACCESS_NUM_CLIENTS * 4)) +} McClient; + +void mc_enable_for_tsec(); + +#endif \ No newline at end of file diff --git a/sept/sept-primary/src/panic.c b/sept/sept-primary/src/panic.c new file mode 100644 index 000000000..910e785f5 --- /dev/null +++ b/sept/sept-primary/src/panic.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "panic.h" +#include "di.h" +#include "pmc.h" +#include "fuse.h" +#include "utils.h" + +static uint32_t g_panic_code = 0; + +void check_panic(void) { + /* We also handle our own panics. */ + /* In the case of our own panics, we assume that the display has already been initialized. */ + bool has_panic = APBDEV_PMC_RST_STATUS_0 != 0 || g_panic_code != 0; + uint32_t code = g_panic_code == 0 ? APBDEV_PMC_SCRATCH200_0 : g_panic_code; + + has_panic = has_panic && !(APBDEV_PMC_RST_STATUS_0 != 1 && code == PANIC_CODE_SAFEMODE); + + if (has_panic) { + uint32_t color; + + /* Check for predefined codes: */ + switch (code & MASK(20)) { + case 0x01: /* Package2 signature verification failed. */ + case 0x02: /* Package2 meta verification failed. */ + case 0x03: /* Package2 version check failed. */ + case 0x04: /* Package2 payload verification failed. */ + color = PANIC_COLOR_KERNEL; + break; + case 0x05: /* Unknown SMC. */ + case 0x06: /* Unknown Abort. */ + color = PANIC_COLOR_SECMON_GENERIC; + break; + case 0x07: /* Invalid CPU context. */ + case 0x08: /* Invalid SE state. */ + case 0x09: /* CPU is already awake (2.0.0+). */ + color = PANIC_COLOR_SECMON_DEEPSLEEP; + break; + case 0x10: /* Unknown exception. */ + color = PANIC_COLOR_SECMON_EXCEPTION; + break; + case 0x30: /* General bootloader error. */ + case 0x31: /* Invalid DRAM ID. */ + case 0x32: /* Invalid size. */ + case 0x33: /* Invalid arguement. */ + case 0x34: /* Bad GPT. */ + case 0x35: /* Failed to boot SafeMode. */ + case 0x36: /* Activity monitor fired (4.0.0+). */ + color = PANIC_COLOR_BOOTLOADER_GENERIC; + break; + case 0x40: /* Kernel panic. */ + color = PANIC_COLOR_KERNEL; + break; + default: + color = code >> 20; + color |= color << 4; + break; + } + + wait_for_button_and_reboot(); + } else { + g_panic_code = 0; + APBDEV_PMC_SCRATCH200_0 = 0; + } +} + +__attribute__ ((noreturn)) void panic(uint32_t code) { + /* Set panic code. */ + if (g_panic_code == 0) { + g_panic_code = code; + APBDEV_PMC_SCRATCH200_0 = code; + } + + fuse_disable_programming(); + APBDEV_PMC_CRYPTO_OP_0 = 1; /* Disable all SE operations. */ + + check_panic(); + while(true); +} diff --git a/sept/sept-primary/src/panic.h b/sept/sept-primary/src/panic.h new file mode 100644 index 000000000..78ea67fb6 --- /dev/null +++ b/sept/sept-primary/src/panic.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef FUSEE_PANIC_H +#define FUSEE_PANIC_H + +#include + +#define PANIC_COLOR_KERNEL 0x0000FF +#define PANIC_COLOR_SECMON_EXCEPTION 0xFF7700 +#define PANIC_COLOR_SECMON_GENERIC 0x00FFFF +#define PANIC_COLOR_SECMON_DEEPSLEEP 0xFF77FF /* 4.0+ color */ +#define PANIC_COLOR_BOOTLOADER_GENERIC 0xAA00FF +#define PANIC_COLOR_BOOTLOADER_SAFEMODE 0xFFFFAA /* Removed */ + +#define PANIC_CODE_SAFEMODE 0x00000020 + +void check_and_display_panic(void); +__attribute__ ((noreturn)) void panic(uint32_t code); + +#endif diff --git a/sept/sept-primary/src/pmc.h b/sept/sept-primary/src/pmc.h new file mode 100644 index 000000000..80c36da7f --- /dev/null +++ b/sept/sept-primary/src/pmc.h @@ -0,0 +1,626 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef FUSEE_PMC_H +#define FUSEE_PMC_H + +#include + +#define PMC_BASE 0x7000E400 +#define MAKE_PMC_REG(n) MAKE_REG32(PMC_BASE + n) + +#define PMC_CONTROL_SDMMC1 (1 << 12) +#define PMC_CONTROL_SDMMC3 (1 << 13) +#define PMC_CONTROL_SDMMC4 (1 << 14) + +#define APBDEV_PMC_CONTROL MAKE_PMC_REG(0x00) +#define APBDEV_PM_0 MAKE_PMC_REG(0x14) +#define APBDEV_PMC_DPD_ENABLE_0 MAKE_PMC_REG(0x24) +#define APBDEV_PMC_PWRGATE_TOGGLE_0 MAKE_PMC_REG(0x30) +#define APBDEV_PMC_PWRGATE_STATUS_0 MAKE_PMC_REG(0x38) +#define APBDEV_PMC_NO_IOPOWER_0 MAKE_PMC_REG(0x44) +#define APBDEV_PMC_SCRATCH0_0 MAKE_PMC_REG(0x50) +#define APBDEV_PMC_SCRATCH1_0 MAKE_PMC_REG(0x54) +#define APBDEV_PMC_SCRATCH20_0 MAKE_PMC_REG(0xA0) +#define APBDEV_PMC_PWR_DET_VAL_0 MAKE_PMC_REG(0xE4) +#define APBDEV_PMC_DDR_PWR_0 MAKE_PMC_REG(0xE8) +#define APBDEV_PMC_CRYPTO_OP_0 MAKE_PMC_REG(0xF4) +#define APBDEV_PMC_WAKE2_STATUS_0 MAKE_PMC_REG(0x168) +#define APBDEV_PMC_OSC_EDPD_OVER_0 MAKE_PMC_REG(0x1A4) +#define APBDEV_PMC_RST_STATUS_0 MAKE_PMC_REG(0x1B4) +#define APBDEV_PMC_IO_DPD_REQ_0 MAKE_PMC_REG(0x1B8) +#define APBDEV_PMC_IO_DPD2_REQ_0 MAKE_PMC_REG(0x1C0) +#define APBDEV_PMC_VDDP_SEL_0 MAKE_PMC_REG(0x1CC) +#define APBDEV_PMC_SCRATCH49_0 MAKE_PMC_REG(0x244) +#define APBDEV_PMC_TSC_MULT_0 MAKE_PMC_REG(0x2B4) +#define APBDEV_PMC_REG_SHORT_0 MAKE_PMC_REG(0x2CC) +#define APBDEV_PMC_WEAK_BIAS_0 MAKE_PMC_REG(0x2C8) +#define APBDEV_PMC_SECURE_SCRATCH21_0 MAKE_PMC_REG(0x334) +#define APBDEV_PMC_SECURE_SCRATCH32_0 MAKE_PMC_REG(0x360) +#define APBDEV_PMC_SECURE_SCRATCH49_0 MAKE_PMC_REG(0x3A4) +#define APBDEV_PMC_CNTRL2_0 MAKE_PMC_REG(0x440) +#define APBDEV_PMC_IO_DPD4_REQ_0 MAKE_PMC_REG(0x464) +#define APBDEV_PMC_UTMIP_PAD_CFG1_0 MAKE_PMC_REG(0x4C4) +#define APBDEV_PMC_UTMIP_PAD_CFG3_0 MAKE_PMC_REG(0x4CC) +#define APBDEV_PMC_DDR_CNTRL_0 MAKE_PMC_REG(0x4E4) +#define APBDEV_PMC_SCRATCH43_0 MAKE_PMC_REG(0x22C) +#define APBDEV_PMC_SCRATCH188_0 MAKE_PMC_REG(0x810) +#define APBDEV_PMC_SCRATCH190_0 MAKE_PMC_REG(0x818) +#define APBDEV_PMC_SCRATCH200_0 MAKE_PMC_REG(0x840) + +#define APBDEV_PMC_SCRATCH45_0 MAKE_PMC_REG(0x234) +#define APBDEV_PMC_SCRATCH46_0 MAKE_PMC_REG(0x238) +#define APBDEV_PMC_SCRATCH33_0 MAKE_PMC_REG(0x120) +#define APBDEV_PMC_SCRATCH40_0 MAKE_PMC_REG(0x13C) + +typedef struct { + uint32_t cntrl; + uint32_t sec_disable; + uint32_t pmc_swrst; + uint32_t wake_mask; + uint32_t wake_lvl; + uint32_t wake_status; + uint32_t sw_wake_status; + uint32_t dpd_pads_oride; + uint32_t dpd_sample; + uint32_t dpd_enable; + uint32_t pwrgate_timer_off; + uint32_t clamp_status; + uint32_t pwrgate_toggle; + uint32_t remove_clamping; + uint32_t pwrgate_status; + uint32_t pwrgood_timer; + uint32_t blink_timer; + uint32_t no_iopower; + uint32_t pwr_det; + uint32_t pwr_det_latch; + uint32_t scratch0; + uint32_t scratch1; + uint32_t scratch2; + uint32_t scratch3; + uint32_t scratch4; + uint32_t scratch5; + uint32_t scratch6; + uint32_t scratch7; + uint32_t scratch8; + uint32_t scratch9; + uint32_t scratch10; + uint32_t scratch11; + uint32_t scratch12; + uint32_t scratch13; + uint32_t scratch14; + uint32_t scratch15; + uint32_t scratch16; + uint32_t scratch17; + uint32_t scratch18; + uint32_t scratch19; + uint32_t scratch20; + uint32_t scratch21; + uint32_t scratch22; + uint32_t scratch23; + uint32_t secure_scratch0; + uint32_t secure_scratch1; + uint32_t secure_scratch2; + uint32_t secure_scratch3; + uint32_t secure_scratch4; + uint32_t secure_scratch5; + uint32_t cpupwrgood_timer; + uint32_t cpupwroff_timer; + uint32_t pg_mask; + uint32_t pg_mask_1; + uint32_t auto_wake_lvl; + uint32_t auto_wake_lvl_mask; + uint32_t wake_delay; + uint32_t pwr_det_val; + uint32_t ddr_pwr; + uint32_t usb_debounce_del; + uint32_t usb_ao; + uint32_t crypto_op; + uint32_t pllp_wb0_override; + uint32_t scratch24; + uint32_t scratch25; + uint32_t scratch26; + uint32_t scratch27; + uint32_t scratch28; + uint32_t scratch29; + uint32_t scratch30; + uint32_t scratch31; + uint32_t scratch32; + uint32_t scratch33; + uint32_t scratch34; + uint32_t scratch35; + uint32_t scratch36; + uint32_t scratch37; + uint32_t scratch38; + uint32_t scratch39; + uint32_t scratch40; + uint32_t scratch41; + uint32_t scratch42; + uint32_t bo_mirror0; + uint32_t bo_mirror1; + uint32_t bo_mirror2; + uint32_t sys_33v_en; + uint32_t bo_mirror_access; + uint32_t gate; + uint32_t wake2_mask; + uint32_t wake2_lvl; + uint32_t wake2_stat; + uint32_t sw_wake2_stat; + uint32_t auto_wake2_lvl_mask; + uint32_t pg_mask2; + uint32_t pg_mask_ce1; + uint32_t pg_mask_ce2; + uint32_t pg_mask_ce3; + uint32_t pwrgate_timer_ce0; + uint32_t pwrgate_timer_ce1; + uint32_t pwrgate_timer_ce2; + uint32_t pwrgate_timer_ce3; + uint32_t pwrgate_timer_ce4; + uint32_t pwrgate_timer_ce5; + uint32_t pwrgate_timer_ce6; + uint32_t pcx_edpd_cntrl; + uint32_t osc_edpd_over; + uint32_t clk_out_cntrl; + uint32_t sata_pwrgate; + uint32_t sensor_ctrl; + uint32_t reset_status; + uint32_t io_dpd_req; + uint32_t io_dpd_stat; + uint32_t io_dpd2_req; + uint32_t io_dpd2_stat; + uint32_t sel_dpd_tim; + uint32_t vddp_sel; + uint32_t ddr_cfg; + uint32_t e_no_vttgen; + uint32_t _reserved0; + uint32_t pllm_wb0_ovrride_frq; + uint32_t test_pwrgate; + uint32_t pwrgate_timer_mult; + uint32_t dsi_sel_dpd; + uint32_t utmip_uhsic_triggers; + uint32_t utmip_uhsic_saved_st; + uint32_t utmip_pad_cfg; + uint32_t utmip_term_pad_cfg; + uint32_t utmip_uhsic_sleep_cfg; + uint32_t utmip_uhsic_sleepwalk_cfg; + uint32_t utmip_sleepwalk_p[3]; + uint32_t uhsic_sleepwalk_p0; + uint32_t utmip_uhsic_status; + uint32_t utmip_uhsic_fake; + uint32_t bo_mirror3[2]; + uint32_t secure_scratch6; + uint32_t secure_scratch7; + uint32_t scratch43; + uint32_t scratch44; + uint32_t scratch45; + uint32_t scratch46; + uint32_t scratch47; + uint32_t scratch48; + uint32_t scratch49; + uint32_t scratch50; + uint32_t scratch51; + uint32_t scratch52; + uint32_t scratch53; + uint32_t scratch54; + uint32_t scratch55; + uint32_t scratch0_eco; + uint32_t por_dpd_ctrl; + uint32_t scratch2_eco; + uint32_t utmip_uhsic_line_wakeup; + uint32_t utmip_bias_master_cntrl; + uint32_t utmip_master_config; + uint32_t td_pwrgate_inter_part_timer; + uint32_t utmip_uhsic2_triggers; + uint32_t utmip_uhsic2_saved_state; + uint32_t utmip_uhsic2_sleep_cfg; + uint32_t utmip_uhsic2_sleepwalk_cfg; + uint32_t uhsic2_sleepwalk_p1; + uint32_t utmip_uhsic2_status; + uint32_t utmip_uhsic2_fake; + uint32_t utmip_uhsic2_line_wakeup; + uint32_t utmip_master2_config; + uint32_t utmip_uhsic_rpd_cfg; + uint32_t pg_mask_ce0; + uint32_t pg_mask3[2]; + uint32_t pllm_wb0_override2; + uint32_t tsc_mult; + uint32_t cpu_vsense_override; + uint32_t glb_amap_cfg; + uint32_t sticky_bits; + uint32_t sec_disable2; + uint32_t weak_bias; + uint32_t reg_short; + uint32_t pg_mask_andor; + uint32_t _reserved1[11]; + uint32_t secure_scratch8; + uint32_t secure_scratch9; + uint32_t secure_scratch10; + uint32_t secure_scratch11; + uint32_t secure_scratch12; + uint32_t secure_scratch13; + uint32_t secure_scratch14; + uint32_t secure_scratch15; + uint32_t secure_scratch16; + uint32_t secure_scratch17; + uint32_t secure_scratch18; + uint32_t secure_scratch19; + uint32_t secure_scratch20; + uint32_t secure_scratch21; + uint32_t secure_scratch22; + uint32_t secure_scratch23; + uint32_t secure_scratch24; + uint32_t secure_scratch25; + uint32_t secure_scratch26; + uint32_t secure_scratch27; + uint32_t secure_scratch28; + uint32_t secure_scratch29; + uint32_t secure_scratch30; + uint32_t secure_scratch31; + uint32_t secure_scratch32; + uint32_t secure_scratch33; + uint32_t secure_scratch34; + uint32_t secure_scratch35; + uint32_t secure_scratch36; + uint32_t secure_scratch37; + uint32_t secure_scratch38; + uint32_t secure_scratch39; + uint32_t secure_scratch40; + uint32_t secure_scratch41; + uint32_t secure_scratch42; + uint32_t secure_scratch43; + uint32_t secure_scratch44; + uint32_t secure_scratch45; + uint32_t secure_scratch46; + uint32_t secure_scratch47; + uint32_t secure_scratch48; + uint32_t secure_scratch49; + uint32_t secure_scratch50; + uint32_t secure_scratch51; + uint32_t secure_scratch52; + uint32_t secure_scratch53; + uint32_t secure_scratch54; + uint32_t secure_scratch55; + uint32_t secure_scratch56; + uint32_t secure_scratch57; + uint32_t secure_scratch58; + uint32_t secure_scratch59; + uint32_t secure_scratch60; + uint32_t secure_scratch61; + uint32_t secure_scratch62; + uint32_t secure_scratch63; + uint32_t secure_scratch64; + uint32_t secure_scratch65; + uint32_t secure_scratch66; + uint32_t secure_scratch67; + uint32_t secure_scratch68; + uint32_t secure_scratch69; + uint32_t secure_scratch70; + uint32_t secure_scratch71; + uint32_t secure_scratch72; + uint32_t secure_scratch73; + uint32_t secure_scratch74; + uint32_t secure_scratch75; + uint32_t secure_scratch76; + uint32_t secure_scratch77; + uint32_t secure_scratch78; + uint32_t secure_scratch79; + uint32_t _reserved2[8]; + uint32_t cntrl2; + uint32_t _reserved3[2]; + uint32_t event_counter; + uint32_t fuse_control; + uint32_t scratch1_eco; + uint32_t _reserved4; + uint32_t io_dpd3_req; + uint32_t io_dpd3_status; + uint32_t io_dpd4_req; + uint32_t io_dpd4_status; + uint32_t _reserved5[30]; + uint32_t ddr_cntrl; + uint32_t _reserved6[70]; + uint32_t scratch56; + uint32_t scratch57; + uint32_t scratch58; + uint32_t scratch59; + uint32_t scratch60; + uint32_t scratch61; + uint32_t scratch62; + uint32_t scratch63; + uint32_t scratch64; + uint32_t scratch65; + uint32_t scratch66; + uint32_t scratch67; + uint32_t scratch68; + uint32_t scratch69; + uint32_t scratch70; + uint32_t scratch71; + uint32_t scratch72; + uint32_t scratch73; + uint32_t scratch74; + uint32_t scratch75; + uint32_t scratch76; + uint32_t scratch77; + uint32_t scratch78; + uint32_t scratch79; + uint32_t scratch80; + uint32_t scratch81; + uint32_t scratch82; + uint32_t scratch83; + uint32_t scratch84; + uint32_t scratch85; + uint32_t scratch86; + uint32_t scratch87; + uint32_t scratch88; + uint32_t scratch89; + uint32_t scratch90; + uint32_t scratch91; + uint32_t scratch92; + uint32_t scratch93; + uint32_t scratch94; + uint32_t scratch95; + uint32_t scratch96; + uint32_t scratch97; + uint32_t scratch98; + uint32_t scratch99; + uint32_t scratch100; + uint32_t scratch101; + uint32_t scratch102; + uint32_t scratch103; + uint32_t scratch104; + uint32_t scratch105; + uint32_t scratch106; + uint32_t scratch107; + uint32_t scratch108; + uint32_t scratch109; + uint32_t scratch110; + uint32_t scratch111; + uint32_t scratch112; + uint32_t scratch113; + uint32_t scratch114; + uint32_t scratch115; + uint32_t scratch116; + uint32_t scratch117; + uint32_t scratch118; + uint32_t scratch119; + uint32_t scratch120; + uint32_t scratch121; + uint32_t scratch122; + uint32_t scratch123; + uint32_t scratch124; + uint32_t scratch125; + uint32_t scratch126; + uint32_t scratch127; + uint32_t scratch128; + uint32_t scratch129; + uint32_t scratch130; + uint32_t scratch131; + uint32_t scratch132; + uint32_t scratch133; + uint32_t scratch134; + uint32_t scratch135; + uint32_t scratch136; + uint32_t scratch137; + uint32_t scratch138; + uint32_t scratch139; + uint32_t scratch140; + uint32_t scratch141; + uint32_t scratch142; + uint32_t scratch143; + uint32_t scratch144; + uint32_t scratch145; + uint32_t scratch146; + uint32_t scratch147; + uint32_t scratch148; + uint32_t scratch149; + uint32_t scratch150; + uint32_t scratch151; + uint32_t scratch152; + uint32_t scratch153; + uint32_t scratch154; + uint32_t scratch155; + uint32_t scratch156; + uint32_t scratch157; + uint32_t scratch158; + uint32_t scratch159; + uint32_t scratch160; + uint32_t scratch161; + uint32_t scratch162; + uint32_t scratch163; + uint32_t scratch164; + uint32_t scratch165; + uint32_t scratch166; + uint32_t scratch167; + uint32_t scratch168; + uint32_t scratch169; + uint32_t scratch170; + uint32_t scratch171; + uint32_t scratch172; + uint32_t scratch173; + uint32_t scratch174; + uint32_t scratch175; + uint32_t scratch176; + uint32_t scratch177; + uint32_t scratch178; + uint32_t scratch179; + uint32_t scratch180; + uint32_t scratch181; + uint32_t scratch182; + uint32_t scratch183; + uint32_t scratch184; + uint32_t scratch185; + uint32_t scratch186; + uint32_t scratch187; + uint32_t scratch188; + uint32_t scratch189; + uint32_t scratch190; + uint32_t scratch191; + uint32_t scratch192; + uint32_t scratch193; + uint32_t scratch194; + uint32_t scratch195; + uint32_t scratch196; + uint32_t scratch197; + uint32_t scratch198; + uint32_t scratch199; + uint32_t scratch200; + uint32_t scratch201; + uint32_t scratch202; + uint32_t scratch203; + uint32_t scratch204; + uint32_t scratch205; + uint32_t scratch206; + uint32_t scratch207; + uint32_t scratch208; + uint32_t scratch209; + uint32_t scratch210; + uint32_t scratch211; + uint32_t scratch212; + uint32_t scratch213; + uint32_t scratch214; + uint32_t scratch215; + uint32_t scratch216; + uint32_t scratch217; + uint32_t scratch218; + uint32_t scratch219; + uint32_t scratch220; + uint32_t scratch221; + uint32_t scratch222; + uint32_t scratch223; + uint32_t scratch224; + uint32_t scratch225; + uint32_t scratch226; + uint32_t scratch227; + uint32_t scratch228; + uint32_t scratch229; + uint32_t scratch230; + uint32_t scratch231; + uint32_t scratch232; + uint32_t scratch233; + uint32_t scratch234; + uint32_t scratch235; + uint32_t scratch236; + uint32_t scratch237; + uint32_t scratch238; + uint32_t scratch239; + uint32_t scratch240; + uint32_t scratch241; + uint32_t scratch242; + uint32_t scratch243; + uint32_t scratch244; + uint32_t scratch245; + uint32_t scratch246; + uint32_t scratch247; + uint32_t scratch248; + uint32_t scratch249; + uint32_t scratch250; + uint32_t scratch251; + uint32_t scratch252; + uint32_t scratch253; + uint32_t scratch254; + uint32_t scratch255; + uint32_t scratch256; + uint32_t scratch257; + uint32_t scratch258; + uint32_t scratch259; + uint32_t scratch260; + uint32_t scratch261; + uint32_t scratch262; + uint32_t scratch263; + uint32_t scratch264; + uint32_t scratch265; + uint32_t scratch266; + uint32_t scratch267; + uint32_t scratch268; + uint32_t scratch269; + uint32_t scratch270; + uint32_t scratch271; + uint32_t scratch272; + uint32_t scratch273; + uint32_t scratch274; + uint32_t scratch275; + uint32_t scratch276; + uint32_t scratch277; + uint32_t scratch278; + uint32_t scratch279; + uint32_t scratch280; + uint32_t scratch281; + uint32_t scratch282; + uint32_t scratch283; + uint32_t scratch284; + uint32_t scratch285; + uint32_t scratch286; + uint32_t scratch287; + uint32_t scratch288; + uint32_t scratch289; + uint32_t scratch290; + uint32_t scratch291; + uint32_t scratch292; + uint32_t scratch293; + uint32_t scratch294; + uint32_t scratch295; + uint32_t scratch296; + uint32_t scratch297; + uint32_t scratch298; + uint32_t scratch299; + uint32_t _reserved7[50]; + uint32_t secure_scratch80; + uint32_t secure_scratch81; + uint32_t secure_scratch82; + uint32_t secure_scratch83; + uint32_t secure_scratch84; + uint32_t secure_scratch85; + uint32_t secure_scratch86; + uint32_t secure_scratch87; + uint32_t secure_scratch88; + uint32_t secure_scratch89; + uint32_t secure_scratch90; + uint32_t secure_scratch91; + uint32_t secure_scratch92; + uint32_t secure_scratch93; + uint32_t secure_scratch94; + uint32_t secure_scratch95; + uint32_t secure_scratch96; + uint32_t secure_scratch97; + uint32_t secure_scratch98; + uint32_t secure_scratch99; + uint32_t secure_scratch100; + uint32_t secure_scratch101; + uint32_t secure_scratch102; + uint32_t secure_scratch103; + uint32_t secure_scratch104; + uint32_t secure_scratch105; + uint32_t secure_scratch106; + uint32_t secure_scratch107; + uint32_t secure_scratch108; + uint32_t secure_scratch109; + uint32_t secure_scratch110; + uint32_t secure_scratch111; + uint32_t secure_scratch112; + uint32_t secure_scratch113; + uint32_t secure_scratch114; + uint32_t secure_scratch115; + uint32_t secure_scratch116; + uint32_t secure_scratch117; + uint32_t secure_scratch118; + uint32_t secure_scratch119; +} tegra_pmc_t; + +static inline volatile tegra_pmc_t *pmc_get_regs(void) +{ + return (volatile tegra_pmc_t *)PMC_BASE; +} + +#endif diff --git a/sept/sept-primary/src/se.c b/sept/sept-primary/src/se.c new file mode 100644 index 000000000..d4dbdc498 --- /dev/null +++ b/sept/sept-primary/src/se.c @@ -0,0 +1,649 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "utils.h" +#include "se.h" + +void trigger_se_blocking_op(unsigned int op, void *dst, size_t dst_size, const void *src, size_t src_size); + +/* Globals for driver. */ +static unsigned int g_se_modulus_sizes[KEYSLOT_RSA_MAX]; +static unsigned int g_se_exp_sizes[KEYSLOT_RSA_MAX]; + +/* Initialize a SE linked list. */ +void NOINLINE ll_init(volatile se_ll_t *ll, void *buffer, size_t size) { + ll->num_entries = 0; /* 1 Entry. */ + + if (buffer != NULL) { + ll->addr_info.address = (uint32_t) get_physical_address(buffer); + ll->addr_info.size = (uint32_t) size; + } else { + ll->addr_info.address = 0; + ll->addr_info.size = 0; + } +} + +void se_check_error_status_reg(void) { + if (se_get_regs()->ERR_STATUS_REG) { + generic_panic(); + } +} + +void se_check_for_error(void) { + volatile tegra_se_t *se = se_get_regs(); + if (se->INT_STATUS_REG & 0x10000 || se->FLAGS_REG & 3 || se->ERR_STATUS_REG) { + generic_panic(); + } +} + +void se_verify_flags_cleared(void) { + if (se_get_regs()->FLAGS_REG & 3) { + generic_panic(); + } +} + +/* Set the flags for an AES keyslot. */ +void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_AES_MAX) { + generic_panic(); + } + + /* Misc flags. */ + if (flags & ~0x80) { + se->AES_KEYSLOT_FLAGS[keyslot] = ~flags; + } + + /* Disable keyslot reads. */ + if (flags & 0x80) { + se->AES_KEY_READ_DISABLE_REG &= ~(1 << keyslot); + } +} + +/* Set the flags for an RSA keyslot. */ +void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_RSA_MAX) { + generic_panic(); + } + + /* Misc flags. */ + if (flags & ~0x80) { + /* TODO: Why are flags assigned this way? */ + se->RSA_KEYSLOT_FLAGS[keyslot] = (((flags >> 4) & 4) | (flags & 3)) ^ 7; + } + + /* Disable keyslot reads. */ + if (flags & 0x80) { + se->RSA_KEY_READ_DISABLE_REG &= ~(1 << keyslot); + } +} + +void clear_aes_keyslot(unsigned int keyslot) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_AES_MAX) { + generic_panic(); + } + + /* Zero out the whole keyslot and IV. */ + for (unsigned int i = 0; i < 0x10; i++) { + se->AES_KEYTABLE_ADDR = (keyslot << 4) | i; + se->AES_KEYTABLE_DATA = 0; + } +} + +void clear_rsa_keyslot(unsigned int keyslot) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_RSA_MAX) { + generic_panic(); + } + + /* Zero out the whole keyslot. */ + for (unsigned int i = 0; i < 0x40; i++) { + /* Select Keyslot Modulus[i] */ + se->RSA_KEYTABLE_ADDR = (keyslot << 7) | i | 0x40; + se->RSA_KEYTABLE_DATA = 0; + } + for (unsigned int i = 0; i < 0x40; i++) { + /* Select Keyslot Expontent[i] */ + se->RSA_KEYTABLE_ADDR = (keyslot << 7) | i; + se->RSA_KEYTABLE_DATA = 0; + } +} + +void set_aes_keyslot(unsigned int keyslot, const void *key, size_t key_size) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_AES_MAX || key_size > KEYSIZE_AES_MAX) { + generic_panic(); + } + + for (size_t i = 0; i < (key_size >> 2); i++) { + se->AES_KEYTABLE_ADDR = (keyslot << 4) | i; + se->AES_KEYTABLE_DATA = read32le(key, 4 * i); + } +} + +void set_rsa_keyslot(unsigned int keyslot, const void *modulus, size_t modulus_size, const void *exponent, size_t exp_size) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_RSA_MAX || modulus_size > KEYSIZE_RSA_MAX || exp_size > KEYSIZE_RSA_MAX) { + generic_panic(); + } + + for (size_t i = 0; i < (modulus_size >> 2); i++) { + se->RSA_KEYTABLE_ADDR = (keyslot << 7) | 0x40 | i; + se->RSA_KEYTABLE_DATA = read32be(modulus, (4 * (modulus_size >> 2)) - (4 * i) - 4); + } + + for (size_t i = 0; i < (exp_size >> 2); i++) { + se->RSA_KEYTABLE_ADDR = (keyslot << 7) | i; + se->RSA_KEYTABLE_DATA = read32be(exponent, (4 * (exp_size >> 2)) - (4 * i) - 4); + } + + g_se_modulus_sizes[keyslot] = modulus_size; + g_se_exp_sizes[keyslot] = exp_size; +} + +void set_aes_keyslot_iv(unsigned int keyslot, const void *iv, size_t iv_size) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_AES_MAX || iv_size > 0x10) { + generic_panic(); + } + + for (size_t i = 0; i < (iv_size >> 2); i++) { + se->AES_KEYTABLE_ADDR = (keyslot << 4) | 8 | i; + se->AES_KEYTABLE_DATA = read32le(iv, 4 * i); + } +} + +void clear_aes_keyslot_iv(unsigned int keyslot) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_AES_MAX) { + generic_panic(); + } + + for (size_t i = 0; i < (0x10 >> 2); i++) { + se->AES_KEYTABLE_ADDR = (keyslot << 4) | 8 | i; + se->AES_KEYTABLE_DATA = 0; + } +} + +void set_se_ctr(const void *ctr) { + for (unsigned int i = 0; i < 4; i++) { + se_get_regs()->CRYPTO_CTR_REG[i] = read32le(ctr, i * 4); + } +} + +void decrypt_data_into_keyslot(unsigned int keyslot_dst, unsigned int keyslot_src, const void *wrapped_key, size_t wrapped_key_size) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot_dst >= KEYSLOT_AES_MAX || keyslot_src >= KEYSLOT_AES_MAX || wrapped_key_size > KEYSIZE_AES_MAX) { + generic_panic(); + } + + se->CONFIG_REG = (ALG_AES_DEC | DST_KEYTAB); + se->CRYPTO_REG = keyslot_src << 24; + se->BLOCK_COUNT_REG = 0; + se->CRYPTO_KEYTABLE_DST_REG = keyslot_dst << 8; + + trigger_se_blocking_op(OP_START, NULL, 0, wrapped_key, wrapped_key_size); +} + +void se_synchronous_exp_mod(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) { + volatile tegra_se_t *se = se_get_regs(); + uint8_t ALIGN(16) stack_buf[KEYSIZE_RSA_MAX]; + + if (keyslot >= KEYSLOT_RSA_MAX || src_size > KEYSIZE_RSA_MAX || dst_size > KEYSIZE_RSA_MAX) { + generic_panic(); + } + + /* Endian swap the input. */ + for (size_t i = 0; i < src_size; i++) { + stack_buf[i] = *((uint8_t *)src + src_size - i - 1); + } + + se->CONFIG_REG = (ALG_RSA | DST_RSAREG); + se->RSA_CONFIG = keyslot << 24; + se->RSA_KEY_SIZE_REG = (g_se_modulus_sizes[keyslot] >> 6) - 1; + se->RSA_EXP_SIZE_REG = g_se_exp_sizes[keyslot] >> 2; + + trigger_se_blocking_op(OP_START, NULL, 0, stack_buf, src_size); + se_get_exp_mod_output(dst, dst_size); +} + +void se_get_exp_mod_output(void *buf, size_t size) { + size_t num_dwords = (size >> 2); + + if (num_dwords < 1) { + return; + } + + uint32_t *p_out = ((uint32_t *)buf) + num_dwords - 1; + uint32_t offset = 0; + + /* Copy endian swapped output. */ + while (num_dwords) { + *p_out = read32be(se_get_regs()->RSA_OUTPUT, offset); + offset += 4; + p_out--; + num_dwords--; + } +} + +bool se_rsa2048_pss_verify(const void *signature, size_t signature_size, const void *modulus, size_t modulus_size, const void *data, size_t data_size) { + uint8_t message[RSA_2048_BYTES]; + uint8_t h_buf[0x24]; + + /* Hardcode RSA with keyslot 0. */ + const uint8_t public_exponent[4] = {0x00, 0x01, 0x00, 0x01}; + set_rsa_keyslot(0, modulus, modulus_size, public_exponent, sizeof(public_exponent)); + se_synchronous_exp_mod(0, message, sizeof(message), signature, signature_size); + + /* Validate sanity byte. */ + if (message[RSA_2048_BYTES - 1] != 0xBC) { + return false; + } + + /* Copy Salt into MGF1 Hash Buffer. */ + memset(h_buf, 0, sizeof(h_buf)); + memcpy(h_buf, message + RSA_2048_BYTES - 0x20 - 0x1, 0x20); + + /* Decrypt maskedDB (via inline MGF1). */ + uint8_t seed = 0; + uint8_t mgf1_buf[0x20]; + for (unsigned int ofs = 0; ofs < RSA_2048_BYTES - 0x20 - 1; ofs += 0x20) { + h_buf[sizeof(h_buf) - 1] = seed++; + se_calculate_sha256(mgf1_buf, h_buf, sizeof(h_buf)); + for (unsigned int i = ofs; i < ofs + 0x20 && i < RSA_2048_BYTES - 0x20 - 1; i++) { + message[i] ^= mgf1_buf[i - ofs]; + } + } + + /* Constant lmask for rsa-2048-pss. */ + message[0] &= 0x7F; + + /* Validate DB is of the form 0000...0001. */ + for (unsigned int i = 0; i < RSA_2048_BYTES - 0x20 - 0x20 - 1 - 1; i++) { + if (message[i] != 0) { + return false; + } + } + if (message[RSA_2048_BYTES - 0x20 - 0x20 - 1 - 1] != 1) { + return false; + } + + /* Check hash correctness. */ + uint8_t validate_buf[8 + 0x20 + 0x20]; + uint8_t validate_hash[0x20]; + + memset(validate_buf, 0, sizeof(validate_buf)); + se_calculate_sha256(&validate_buf[8], data, data_size); + memcpy(&validate_buf[0x28], &message[RSA_2048_BYTES - 0x20 - 0x20 - 1], 0x20); + se_calculate_sha256(validate_hash, validate_buf, sizeof(validate_buf)); + return memcmp(h_buf, validate_hash, 0x20) == 0; +} + +void trigger_se_blocking_op(unsigned int op, void *dst, size_t dst_size, const void *src, size_t src_size) { + volatile tegra_se_t *se = se_get_regs(); + se_ll_t in_ll; + se_ll_t out_ll; + + ll_init(&in_ll, (void *)src, src_size); + ll_init(&out_ll, dst, dst_size); + + /* Set the LLs. */ + se->IN_LL_ADDR_REG = (uint32_t) get_physical_address(&in_ll); + se->OUT_LL_ADDR_REG = (uint32_t) get_physical_address(&out_ll); + + /* Set registers for operation. */ + se->ERR_STATUS_REG = se->ERR_STATUS_REG; + se->INT_STATUS_REG = se->INT_STATUS_REG; + se->OPERATION_REG = op; + + while (!(se->INT_STATUS_REG & 0x10)) { /* Wait a while */ } + se_check_for_error(); +} + +/* Secure AES Functionality. */ +void se_perform_aes_block_operation(void *dst, size_t dst_size, const void *src, size_t src_size) { + uint8_t block[0x10] = {0}; + + if (src_size > sizeof(block) || dst_size > sizeof(block)) { + generic_panic(); + } + + /* Load src data into block. */ + if (src_size != 0) { + memcpy(block, src, src_size); + } + + /* Trigger AES operation. */ + se_get_regs()->BLOCK_COUNT_REG = 0; + trigger_se_blocking_op(OP_START, block, sizeof(block), block, sizeof(block)); + + /* Copy output data into dst. */ + if (dst_size != 0) { + memcpy(dst, block, dst_size); + } +} + +void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *ctr, size_t ctr_size) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_AES_MAX || ctr_size != 0x10) { + generic_panic(); + } + unsigned int num_blocks = src_size >> 4; + + /* Unknown what this write does, but official code writes it for CTR mode. */ + se->SPARE_0 = 1; + se->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY); + se->CRYPTO_REG = (keyslot << 24) | 0x91E; + set_se_ctr(ctr); + + /* Handle any aligned blocks. */ + size_t aligned_size = (size_t)num_blocks << 4; + if (aligned_size) { + se->BLOCK_COUNT_REG = num_blocks - 1; + trigger_se_blocking_op(OP_START, dst, dst_size, src, aligned_size); + } + + /* Handle final, unaligned block. */ + if (aligned_size < dst_size && aligned_size < src_size) { + size_t last_block_size = dst_size - aligned_size; + if (src_size < dst_size) { + last_block_size = src_size - aligned_size; + } + se_perform_aes_block_operation(dst + aligned_size, last_block_size, (uint8_t *)src + aligned_size, src_size - aligned_size); + } +} + +void se_aes_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, unsigned int config_high) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) { + generic_panic(); + } + + /* Set configuration high (256-bit vs 128-bit) based on parameter. */ + se->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY) | (config_high << 16); + se->CRYPTO_REG = keyslot << 24 | 0x100; + se_perform_aes_block_operation(dst, 0x10, src, 0x10); +} + +void se_aes_128_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) { + se_aes_ecb_encrypt_block(keyslot, dst, dst_size, src, src_size, 0); +} + +void se_aes_256_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) { + se_aes_ecb_encrypt_block(keyslot, dst, dst_size, src, src_size, 0x202); +} + +void se_aes_ecb_decrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) { + generic_panic(); + } + + se->CONFIG_REG = (ALG_AES_DEC | DST_MEMORY); + se->CRYPTO_REG = keyslot << 24; + se_perform_aes_block_operation(dst, 0x10, src, 0x10); +} + +void shift_left_xor_rb(uint8_t *key) { + uint8_t prev_high_bit = 0; + for (unsigned int i = 0; i < 0x10; i++) { + uint8_t cur_byte = key[0xF - i]; + key[0xF - i] = (cur_byte << 1) | (prev_high_bit); + prev_high_bit = cur_byte >> 7; + } + if (prev_high_bit) { + key[0xF] ^= 0x87; + } +} + +void shift_left_xor_rb_le(uint8_t *key) { + uint8_t prev_high_bit = 0; + for (unsigned int i = 0; i < 0x10; i++) { + uint8_t cur_byte = key[i]; + key[i] = (cur_byte << 1) | (prev_high_bit); + prev_high_bit = cur_byte >> 7; + } + if (prev_high_bit) { + key[0x0] ^= 0x87; + } +} + +void aes_128_xts_nintendo_get_tweak(uint8_t *tweak, size_t sector) { + for (int i = 0xF; i >= 0; i--) { /* Nintendo LE custom tweak... */ + tweak[i] = (unsigned char)(sector & 0xFF); + sector >>= 8; + } +} + +void aes_128_xts_nintendo_xor_with_tweak(unsigned int keyslot, size_t sector, uint8_t *dst, const uint8_t *src, size_t size) { + if ((size & 0xF) || size == 0) { + generic_panic(); + } + uint8_t tweak[0x10]; + aes_128_xts_nintendo_get_tweak(tweak, sector); + se_aes_128_ecb_encrypt_block(keyslot, tweak, sizeof(tweak), tweak, sizeof(tweak)); + + for (unsigned int block = 0; block < (size >> 4); block++) { + for (unsigned int i = 0; i < 0x10; i++) { + dst[(block << 4) | i] = src[(block << 4) | i] ^ tweak[i]; + } + shift_left_xor_rb_le(tweak); + } +} + +void aes_128_xts_nintendo_crypt_sector(unsigned int keyslot_1, unsigned int keyslot_2, size_t sector, bool encrypt, void *dst, const void *src, size_t size) { + volatile tegra_se_t *se = se_get_regs(); + + if ((size & 0xF) || size == 0) { + generic_panic(); + } + + /* XOR. */ + aes_128_xts_nintendo_xor_with_tweak(keyslot_2, sector, dst, src, size); + + /* Encrypt/Decrypt. */ + if (encrypt) { + se->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY); + se->CRYPTO_REG = keyslot_1 << 24 | 0x100; + } else { + se->CONFIG_REG = (ALG_AES_DEC | DST_MEMORY); + se->CRYPTO_REG = keyslot_1 << 24; + } + se->BLOCK_COUNT_REG = (size >> 4) - 1; + trigger_se_blocking_op(OP_START, dst, size, src, size); + + /* XOR. */ + aes_128_xts_nintendo_xor_with_tweak(keyslot_2, sector, dst, dst, size); +} + +/* Encrypt with AES-XTS (Nintendo's custom tweak). */ +void se_aes_128_xts_nintendo_encrypt(unsigned int keyslot_1, unsigned int keyslot_2, size_t base_sector, void *dst, const void *src, size_t size, unsigned int sector_size) { + if ((size & 0xF) || size == 0) { + generic_panic(); + } + size_t sector = base_sector; + for (size_t ofs = 0; ofs < size; ofs += sector_size) { + aes_128_xts_nintendo_crypt_sector(keyslot_1, keyslot_2, sector, true, dst + ofs, src + ofs, sector_size); + sector++; + } +} + +/* Decrypt with AES-XTS (Nintendo's custom tweak). */ +void se_aes_128_xts_nintendo_decrypt(unsigned int keyslot_1, unsigned int keyslot_2, size_t base_sector, void *dst, const void *src, size_t size, unsigned int sector_size) { + if ((size & 0xF) || size == 0) { + generic_panic(); + } + size_t sector = base_sector; + for (size_t ofs = 0; ofs < size; ofs += sector_size) { + aes_128_xts_nintendo_crypt_sector(keyslot_1, keyslot_2, sector, false, dst + ofs, src + ofs, sector_size); + sector++; + } +} + +void se_compute_aes_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size, unsigned int config_high) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_AES_MAX) { + generic_panic(); + } + + /* Generate the derived key, to be XOR'd with final output block. */ + uint8_t ALIGN(16) derived_key[0x10] = {0}; + se_aes_ecb_encrypt_block(keyslot, derived_key, sizeof(derived_key), derived_key, sizeof(derived_key), config_high); + shift_left_xor_rb(derived_key); + if (data_size & 0xF) { + shift_left_xor_rb(derived_key); + } + + se->CONFIG_REG = (ALG_AES_ENC | DST_HASHREG) | (config_high << 16); + se->CRYPTO_REG = (keyslot << 24) | (0x145); + clear_aes_keyslot_iv(keyslot); + + unsigned int num_blocks = (data_size + 0xF) >> 4; + /* Handle aligned blocks. */ + if (num_blocks > 1) { + se->BLOCK_COUNT_REG = num_blocks - 2; + trigger_se_blocking_op(OP_START, NULL, 0, data, data_size); + se->CRYPTO_REG |= 0x80; + } + + /* Create final block. */ + uint8_t ALIGN(16) last_block[0x10] = {0}; + if (data_size & 0xF) { + memcpy(last_block, data + (data_size & ~0xF), data_size & 0xF); + last_block[data_size & 0xF] = 0x80; /* Last block = data || 100...0 */ + } else if (data_size >= 0x10) { + memcpy(last_block, data + data_size - 0x10, 0x10); + } + + for (unsigned int i = 0; i < 0x10; i++) { + last_block[i] ^= derived_key[i]; + } + + /* Perform last operation. */ + se->BLOCK_COUNT_REG = 0; + trigger_se_blocking_op(OP_START, NULL, 0, last_block, sizeof(last_block)); + + /* Copy output CMAC. */ + for (unsigned int i = 0; i < (cmac_size >> 2); i++) { + ((uint32_t *)cmac)[i] = read32le(se->HASH_RESULT_REG, i << 2); + } +} + +void se_compute_aes_128_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size) { + se_compute_aes_cmac(keyslot, cmac, cmac_size, data, data_size, 0); +} +void se_compute_aes_256_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size) { + se_compute_aes_cmac(keyslot, cmac, cmac_size, data, data_size, 0x202); +} + +void se_aes_256_cbc_encrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *iv) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_AES_MAX || src_size < 0x10) { + generic_panic(); + } + + se->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY) | (0x202 << 16); + se->CRYPTO_REG = (keyslot << 24) | 0x144; + set_aes_keyslot_iv(keyslot, iv, 0x10); + se->BLOCK_COUNT_REG = (src_size >> 4) - 1; + trigger_se_blocking_op(OP_START, dst, dst_size, src, src_size); +} + +/* SHA256 Implementation. */ +void se_calculate_sha256(void *dst, const void *src, size_t src_size) { + volatile tegra_se_t *se = se_get_regs(); + + /* Setup config for SHA256, size = BITS(src_size) */ + se->CONFIG_REG = (ENCMODE_SHA256 | ALG_SHA | DST_HASHREG); + se->SHA_CONFIG_REG = 1; + se->SHA_MSG_LENGTH_REG = (uint32_t)(src_size << 3); + se->_0x208 = 0; + se->_0x20C = 0; + se->_0x210 = 0; + se->SHA_MSG_LEFT_REG = (uint32_t)(src_size << 3); + se->_0x218 = 0; + se->_0x21C = 0; + se->_0x220 = 0; + + /* Trigger the operation. */ + trigger_se_blocking_op(OP_START, NULL, 0, src, src_size); + + /* Copy output hash. */ + for (unsigned int i = 0; i < (0x20 >> 2); i++) { + ((uint32_t *)dst)[i] = read32be(se->HASH_RESULT_REG, i << 2); + } +} + +/* RNG API */ +void se_initialize_rng(unsigned int keyslot) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_AES_MAX) { + generic_panic(); + } + + /* To initialize the RNG, we'll perform an RNG operation into an output buffer. */ + /* This will be discarded, when done. */ + uint8_t ALIGN(16) output_buf[0x10]; + + se->RNG_SRC_CONFIG_REG = 3; /* Entropy enable + Entropy lock enable */ + se->RNG_RESEED_INTERVAL_REG = 70001; + se->CONFIG_REG = (ALG_RNG | DST_MEMORY); + se->CRYPTO_REG = (keyslot << 24) | 0x108; + se->RNG_CONFIG_REG = 5; + se->BLOCK_COUNT_REG = 0; + trigger_se_blocking_op(OP_START, output_buf, 0x10, NULL, 0); +} + +void se_generate_random(unsigned int keyslot, void *dst, size_t size) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_AES_MAX) { + generic_panic(); + } + + uint32_t num_blocks = size >> 4; + size_t aligned_size = num_blocks << 4; + se->CONFIG_REG = (ALG_RNG | DST_MEMORY); + se->CRYPTO_REG = (keyslot << 24) | 0x108; + se->RNG_CONFIG_REG = 4; + + if (num_blocks >= 1) { + se->BLOCK_COUNT_REG = num_blocks - 1; + trigger_se_blocking_op(OP_START, dst, aligned_size, NULL, 0); + } + if (size > aligned_size) { + se_perform_aes_block_operation(dst + aligned_size, size - aligned_size, NULL, 0); + } +} diff --git a/sept/sept-primary/src/se.h b/sept/sept-primary/src/se.h new file mode 100644 index 000000000..64998621a --- /dev/null +++ b/sept/sept-primary/src/se.h @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef FUSEE_SE_H +#define FUSEE_SE_H + +#define SE_BASE 0x70012000 +#define MAKE_SE_REG(n) MAKE_REG32(SE_BASE + n) + +#define KEYSLOT_SWITCH_LP0TZRAMKEY 0x2 +#define KEYSLOT_SWITCH_SRKGENKEY 0x8 +#define KEYSLOT_SWITCH_PACKAGE2KEY 0x8 +#define KEYSLOT_SWITCH_TEMPKEY 0x9 +#define KEYSLOT_SWITCH_SESSIONKEY 0xA +#define KEYSLOT_SWITCH_RNGKEY 0xB +#define KEYSLOT_SWITCH_MASTERKEY 0xC +#define KEYSLOT_SWITCH_DEVICEKEY 0xD + +/* This keyslot was added in 4.0.0. */ +#define KEYSLOT_SWITCH_4XNEWDEVICEKEYGENKEY 0xD +#define KEYSLOT_SWITCH_4XNEWCONSOLEKEYGENKEY 0xE +#define KEYSLOT_SWITCH_4XOLDDEVICEKEY 0xF + +/* This keyslot was added in 5.0.0. */ +#define KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY 0xA + +#define KEYSLOT_AES_MAX 0x10 +#define KEYSLOT_RSA_MAX 0x2 + +#define KEYSIZE_AES_MAX 0x20 +#define KEYSIZE_RSA_MAX 0x100 + +#define ALG_SHIFT (12) +#define ALG_DEC_SHIFT (8) +#define ALG_NOP (0 << ALG_SHIFT) +#define ALG_AES_ENC (1 << ALG_SHIFT) +#define ALG_AES_DEC ((1 << ALG_DEC_SHIFT) | ALG_NOP) +#define ALG_RNG (2 << ALG_SHIFT) +#define ALG_SHA (3 << ALG_SHIFT) +#define ALG_RSA (4 << ALG_SHIFT) + +#define DST_SHIFT (2) +#define DST_MEMORY (0 << DST_SHIFT) +#define DST_HASHREG (1 << DST_SHIFT) +#define DST_KEYTAB (2 << DST_SHIFT) +#define DST_SRK (3 << DST_SHIFT) +#define DST_RSAREG (4 << DST_SHIFT) + +#define ENCMODE_SHIFT (24) +#define DECMODE_SHIFT (16) +#define ENCMODE_SHA256 (5 << ENCMODE_SHIFT) + +#define HASH_DISABLE (0x0) +#define HASH_ENABLE (0x1) + +#define OP_ABORT 0 +#define OP_START 1 +#define OP_RESTART 2 +#define OP_CTX_SAVE 3 +#define OP_RESTART_IN 4 + +#define CTX_SAVE_SRC_SHIFT 29 +#define CTX_SAVE_SRC_STICKY_BITS (0 << CTX_SAVE_SRC_SHIFT) +#define CTX_SAVE_SRC_KEYTABLE_AES (2 << CTX_SAVE_SRC_SHIFT) +#define CTX_SAVE_SRC_KEYTABLE_RSA (1 << CTX_SAVE_SRC_SHIFT) +#define CTX_SAVE_SRC_MEM (4 << CTX_SAVE_SRC_SHIFT) +#define CTX_SAVE_SRC_SRK (6 << CTX_SAVE_SRC_SHIFT) + +#define CTX_SAVE_KEY_LOW_BITS 0 +#define CTX_SAVE_KEY_HIGH_BITS 1 +#define CTX_SAVE_KEY_ORIGINAL_IV 2 +#define CTX_SAVE_KEY_UPDATED_IV 3 + +#define CTX_SAVE_STICKY_BIT_INDEX_SHIFT 24 +#define CTX_SAVE_KEY_INDEX_SHIFT 8 +#define CTX_SAVE_RSA_KEY_INDEX_SHIFT 16 +#define CTX_SAVE_RSA_KEY_BLOCK_INDEX_SHIFT 12 + +#define RSA_2048_BYTES 0x100 + +typedef struct { + uint32_t _0x0; + uint32_t _0x4; + uint32_t OPERATION_REG; + uint32_t INT_ENABLE_REG; + uint32_t INT_STATUS_REG; + uint32_t CONFIG_REG; + uint32_t IN_LL_ADDR_REG; + uint32_t _0x1C; + uint32_t _0x20; + uint32_t OUT_LL_ADDR_REG; + uint32_t _0x28; + uint32_t _0x2C; + uint8_t HASH_RESULT_REG[0x20]; + uint8_t _0x50[0x20]; + uint32_t CONTEXT_SAVE_CONFIG_REG; + uint8_t _0x74[0x18C]; + uint32_t SHA_CONFIG_REG; + uint32_t SHA_MSG_LENGTH_REG; + uint32_t _0x208; + uint32_t _0x20C; + uint32_t _0x210; + uint32_t SHA_MSG_LEFT_REG; + uint32_t _0x218; + uint32_t _0x21C; + uint32_t _0x220; + uint32_t _0x224; + uint8_t _0x228[0x58]; + uint32_t AES_KEY_READ_DISABLE_REG; + uint32_t AES_KEYSLOT_FLAGS[0x10]; + uint8_t _0x2C4[0x3C]; + uint32_t _0x300; + uint32_t CRYPTO_REG; + uint32_t CRYPTO_CTR_REG[4]; + uint32_t BLOCK_COUNT_REG; + uint32_t AES_KEYTABLE_ADDR; + uint32_t AES_KEYTABLE_DATA; + uint32_t _0x324; + uint32_t _0x328; + uint32_t _0x32C; + uint32_t CRYPTO_KEYTABLE_DST_REG; + uint8_t _0x334[0xC]; + uint32_t RNG_CONFIG_REG; + uint32_t RNG_SRC_CONFIG_REG; + uint32_t RNG_RESEED_INTERVAL_REG; + uint8_t _0x34C[0xB4]; + uint32_t RSA_CONFIG; + uint32_t RSA_KEY_SIZE_REG; + uint32_t RSA_EXP_SIZE_REG; + uint32_t RSA_KEY_READ_DISABLE_REG; + uint32_t RSA_KEYSLOT_FLAGS[2]; + uint32_t _0x418; + uint32_t _0x41C; + uint32_t RSA_KEYTABLE_ADDR; + uint32_t RSA_KEYTABLE_DATA; + uint8_t RSA_OUTPUT[0x100]; + uint8_t _0x528[0x2D8]; + uint32_t FLAGS_REG; + uint32_t ERR_STATUS_REG; + uint32_t _0x808; + uint32_t SPARE_0; + uint32_t _0x810; + uint32_t _0x814; + uint32_t _0x818; + uint32_t _0x81C; + uint8_t _0x820[0x17E0]; +} tegra_se_t; + +typedef struct { + uint32_t address; + uint32_t size; +} se_addr_info_t; + +typedef struct { + uint32_t num_entries; /* Set to total entries - 1 */ + se_addr_info_t addr_info; /* This should really be an array...but for our use case it works. */ +} se_ll_t; + +static inline volatile tegra_se_t *se_get_regs(void) { + return (volatile tegra_se_t *)SE_BASE; +} + +void se_check_error_status_reg(void); +void se_check_for_error(void); +void se_trigger_interrupt(void); + +void se_validate_stored_vector(void); +void se_generate_stored_vector(void); + +void se_verify_flags_cleared(void); + +void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags); +void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags); +void clear_aes_keyslot(unsigned int keyslot); +void clear_rsa_keyslot(unsigned int keyslot); + +void set_aes_keyslot(unsigned int keyslot, const void *key, size_t key_size); +void decrypt_data_into_keyslot(unsigned int keyslot_dst, unsigned int keyslot_src, const void *wrapped_key, size_t wrapped_key_size); +void set_rsa_keyslot(unsigned int keyslot, const void *modulus, size_t modulus_size, const void *exponent, size_t exp_size); +void set_aes_keyslot_iv(unsigned int keyslot, const void *iv, size_t iv_size); +void set_se_ctr(const void *ctr); + +/* Secure AES API */ +void se_aes_128_xts_nintendo_decrypt(unsigned int keyslot_1, unsigned int keyslot_2, unsigned int base_sector, void *dst, const void *src, size_t size, unsigned int sector_size); +void se_aes_128_xts_nintendo_encrypt(unsigned int keyslot_1, unsigned int keyslot_2, unsigned int base_sector, void *dst, const void *src, size_t size, unsigned int sector_size); +void se_compute_aes_128_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size); +void se_compute_aes_256_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size); +void se_aes_128_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size); +void se_aes_256_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size); +void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *ctr, size_t ctr_size); +void se_aes_ecb_decrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size); +void se_aes_256_cbc_encrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *iv); + +/* Hash API */ +void se_calculate_sha256(void *dst, const void *src, size_t src_size); + +/* RSA API */ +void se_get_exp_mod_output(void *buf, size_t size); +void se_synchronous_exp_mod(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size); +bool se_rsa2048_pss_verify(const void *signature, size_t signature_size, const void *modulus, size_t modulus_size, const void *data, size_t data_size); + +/* RNG API */ +void se_initialize_rng(unsigned int keyslot); +void se_generate_random(unsigned int keyslot, void *dst, size_t size); + +#endif diff --git a/sept/sept-primary/src/start.s b/sept/sept-primary/src/start.s new file mode 100644 index 000000000..50e8faf74 --- /dev/null +++ b/sept/sept-primary/src/start.s @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +.section .text.start, "ax", %progbits +.arm +.align 5 +.global _start +.type _start, %function +_start: + /* Set coldboot */ + mov r0, #0x0 + ldr r1, =0x7000E400 + str r0, [r1, #0x50] + + /* Tell pk1ldr normal reboot, no error */ + str r0, [r1, #0x1B4] + str r0, [r1, #0x840] + + /* Cleanup SVC handler address. */ + ldr r0, =0x40004C30 + ldr r1, =0x6000F208 + str r0, [r1] + + /* Disable RCM forcefully */ + mov r0, #0x4 + ldr r1, =0x15DC + ldr r2, =0xE020 + bl ipatch_word + + /* Patch BCT signature check */ + mov r0, #0x5 + ldr r1, =0x4AEE + ldr r2, =0xE05B + bl ipatch_word + + /* Patch bootloader read */ + mov r0, #0x6 + ldr r1, =0x4E88 + ldr r2, =0xE018 + bl ipatch_word + + ldr r0, =__main_phys_start__ + ldr r1, =__main_start__ + mov r2, #0x0 + ldr r3, =(__main_size__) + copy_panic_payload: + ldr r4, [r0, r2] + str r4, [r1, r2] + add r2, r2, #0x4 + cmp r2, r3 + bne copy_panic_payload + + + + /* Jump back to bootrom start. */ + ldr r0, =0x101010 + bx r0 + + /* Unused, but forces inclusion in binary. */ + b main + + +.section .text.ipatch_word, "ax", %progbits +.arm +.align 5 +.global ipatch_word +.type ipatch_word, %function +ipatch_word: + ldr r3, =0x6001dc00 + lsl r0, r0, #0x2 + lsr r1, r1, #0x1 + lsl r1, r1, #0x10 + orr r1, r1, r2 + str r1, [r3, r0] + bx lr + +.section .text.jump_to_main, "ax", %progbits +.arm +.align 5 +.global jump_to_main +.type jump_to_main, %function +jump_to_main: + /* Just jump to main */ + ldr sp, =__stack_top__ + b main + + diff --git a/sept/sept-primary/src/sysreg.h b/sept/sept-primary/src/sysreg.h new file mode 100644 index 000000000..1bc1a8c43 --- /dev/null +++ b/sept/sept-primary/src/sysreg.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef FUSEE_SYSREG_H +#define FUSEE_SYSREG_H + +#include + +#define SYSREG_BASE 0x6000C000 +#define SB_BASE (SYSREG_BASE + 0x200) +#define EXCP_VEC_BASE 0x6000F000 + +#define MAKE_SYSREG(n) MAKE_REG32(SYSREG_BASE + n) +#define MAKE_SB_REG(n) MAKE_REG32(SB_BASE + n) +#define MAKE_EXCP_VEC_REG(n) MAKE_REG32(EXCP_VEC_BASE + n) + +#define AHB_ARBITRATION_DISABLE_0 MAKE_SYSREG(0x004) +#define AHB_ARBITRATION_XBAR_CTRL_0 MAKE_SYSREG(0x0E0) +#define AHB_AHB_SPARE_REG_0 MAKE_SYSREG(0x110) + +#define SB_CSR_0 MAKE_SB_REG(0x00) +#define SB_PIROM_START_0 MAKE_SB_REG(0x04) +#define SB_PFCFG_0 MAKE_SB_REG(0x08) +#define SB_SECURE_SPAREREG_0_0 MAKE_SB_REG(0x0C) +#define SB_SECURE_SPAREREG_1_0 MAKE_SB_REG(0x10) +#define SB_SECURE_SPAREREG_2_0 MAKE_SB_REG(0x14) +#define SB_SECURE_SPAREREG_3_0 MAKE_SB_REG(0x18) +#define SB_SECURE_SPAREREG_4_0 MAKE_SB_REG(0x1C) +#define SB_SECURE_SPAREREG_5_0 MAKE_SB_REG(0x20) +#define SB_SECURE_SPAREREG_6_0 MAKE_SB_REG(0x24) +#define SB_SECURE_SPAREREG_7_0 MAKE_SB_REG(0x28) +#define SB_AA64_RESET_LOW_0 MAKE_SB_REG(0x30) +#define SB_AA64_RESET_HIGH_0 MAKE_SB_REG(0x34) + +#endif diff --git a/sept/sept-primary/src/timers.h b/sept/sept-primary/src/timers.h new file mode 100644 index 000000000..d1f89d33c --- /dev/null +++ b/sept/sept-primary/src/timers.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef FUSEE_TIMERS_H +#define FUSEE_TIMERS_H + +#include "utils.h" + +#define TIMERS_BASE 0x60005000 +#define MAKE_TIMERS_REG(n) MAKE_REG32(TIMERS_BASE + n) + +#define TIMERUS_CNTR_1US_0 MAKE_TIMERS_REG(0x10) +#define TIMERUS_USEC_CFG_0 MAKE_TIMERS_REG(0x14) +#define SHARED_INTR_STATUS_0 MAKE_TIMERS_REG(0x1A0) +#define SHARED_TIMER_SECURE_CFG_0 MAKE_TIMERS_REG(0x1A4) + +#define RTC_BASE 0x7000E000 +#define MAKE_RTC_REG(n) MAKE_REG32(RTC_BASE + n) + +#define RTC_SECONDS MAKE_RTC_REG(0x08) +#define RTC_SHADOW_SECONDS MAKE_RTC_REG(0x0C) +#define RTC_MILLI_SECONDS MAKE_RTC_REG(0x10) + +typedef struct { + uint32_t CONFIG; + uint32_t STATUS; + uint32_t COMMAND; + uint32_t PATTERN; +} watchdog_timers_t; + +#define GET_WDT(n) ((volatile watchdog_timers_t *)(TIMERS_BASE + 0x100 + 0x20 * n)) +#define WDT_REBOOT_PATTERN 0xC45A +#define GET_WDT_REBOOT_CFG_REG(n) MAKE_REG32(TIMERS_BASE + 0x60 + 0x8 * n) + +void wait(uint32_t microseconds); + +static inline uint32_t get_time_us(void) { + return TIMERUS_CNTR_1US_0; +} + +/** + * Returns the time in microseconds. + */ +static inline uint32_t get_time(void) { + return get_time_us(); +} + +/** + * Returns the number of microseconds that have passed since a given get_time(). + */ +static inline uint32_t get_time_since(uint32_t base) { + return get_time_us() - base; +} + +/** + * Delays for a given number of microseconds. + */ +static inline void udelay(uint32_t usecs) { + uint32_t start = get_time_us(); + while (get_time_us() - start < usecs); +} + +__attribute__ ((noreturn)) void watchdog_reboot(void); + +#endif diff --git a/sept/sept-primary/src/tsec.h b/sept/sept-primary/src/tsec.h new file mode 100644 index 000000000..e90296210 --- /dev/null +++ b/sept/sept-primary/src/tsec.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef FUSEE_TSEC_H_ +#define FUSEE_TSEC_H_ + +#include +#include + +#define TSEC_BASE 0x54500000 +#define SOR1_BASE 0x54580000 + +#define SOR1_DP_HDCP_BKSV_LSB MAKE_REG32(SOR1_BASE + 0x1E8) +#define SOR1_TMDS_HDCP_BKSV_LSB MAKE_REG32(SOR1_BASE + 0x21C) +#define SOR1_TMDS_HDCP_CN_MSB MAKE_REG32(SOR1_BASE + 0x208) +#define SOR1_TMDS_HDCP_CN_LSB MAKE_REG32(SOR1_BASE + 0x20C) + +typedef struct { + uint8_t _0x0[0x1000]; /* Ignore non Falcon registers. */ + uint32_t FALCON_IRQSSET; + uint32_t FALCON_IRQSCLR; + uint32_t FALCON_IRQSTAT; + uint32_t FALCON_IRQMODE; + uint32_t FALCON_IRQMSET; + uint32_t FALCON_IRQMCLR; + uint32_t FALCON_IRQMASK; + uint32_t FALCON_IRQDEST; + uint8_t _0x1020[0x20]; + uint32_t FALCON_SCRATCH0; + uint32_t FALCON_SCRATCH1; + uint32_t FALCON_ITFEN; + uint32_t FALCON_IDLESTATE; + uint32_t FALCON_CURCTX; + uint32_t FALCON_NXTCTX; + uint8_t _0x1058[0x28]; + uint32_t FALCON_SCRATCH2; + uint32_t FALCON_SCRATCH3; + uint32_t FALCON_PM_SIGNAL; + uint32_t FALCON_PM_MODE; + uint32_t FALCON_DEBUG1; + uint32_t FALCON_DEBUGINFO; + uint32_t FALCON_BREAKPOINT0; + uint32_t FALCON_BREAKPOINT1; + uint32_t FALCON_CGCTL; + uint32_t FALCON_ENGCTL; + uint8_t _0x10A8[0x58]; + uint32_t FALCON_CPUCTL; + uint32_t FALCON_BOOTVEC; + uint32_t FALCON_HWCFG; + uint32_t FALCON_DMACTL; + uint32_t FALCON_DMATRFBASE; + uint32_t FALCON_DMATRFMOFFS; + uint32_t FALCON_DMATRFCMD; + uint32_t FALCON_DMATRFFBOFFS; + uint8_t _0x1120[0x10]; + uint32_t FALCON_CPUCTL_ALIAS; + uint8_t _0x1134[0x20]; + uint32_t FALCON_IMFILLRNG1; + uint32_t FALCON_IMFILLCTL; + uint32_t _0x115C; + uint32_t _0x1160; + uint32_t _0x1164; + uint32_t FALCON_EXTERRADDR; + uint32_t FALCON_EXTERRSTAT; + uint32_t _0x1170; + uint32_t _0x1174; + uint32_t _0x1178; + uint32_t FALCON_CG2; + uint32_t FALCON_CODE_INDEX; + uint32_t FALCON_CODE; + uint32_t FALCON_CODE_VIRT_ADDR; + uint8_t _0x118C[0x34]; + uint32_t FALCON_DATA_INDEX0; + uint32_t FALCON_DATA0; + uint32_t FALCON_DATA_INDEX1; + uint32_t FALCON_DATA1; + uint32_t FALCON_DATA_INDEX2; + uint32_t FALCON_DATA2; + uint32_t FALCON_DATA_INDEX3; + uint32_t FALCON_DATA3; + uint32_t FALCON_DATA_INDEX4; + uint32_t FALCON_DATA4; + uint32_t FALCON_DATA_INDEX5; + uint32_t FALCON_DATA5; + uint32_t FALCON_DATA_INDEX6; + uint32_t FALCON_DATA6; + uint32_t FALCON_DATA_INDEX7; + uint32_t FALCON_DATA7; + uint32_t FALCON_ICD_CMD; + uint32_t FALCON_ICD_ADDR; + uint32_t FALCON_ICD_WDATA; + uint32_t FALCON_ICD_RDATA; + uint8_t _0x1210[0x30]; + uint32_t FALCON_SCTL; + uint8_t _0x1244[0x1430-0x1244]; /* Ignore non Falcon registers. */ + uint32_t TSEC_SCP_INSN_STAT; + uint8_t _0x1434[0x1244+0x5F8-0x1434]; /* Ignore non Falcon registers. */ +} tegra_tsec_t; + +static inline volatile tegra_tsec_t *tsec_get_regs(void) +{ + return (volatile tegra_tsec_t *)TSEC_BASE; +} + +#endif \ No newline at end of file diff --git a/sept/sept-primary/src/utils.c b/sept/sept-primary/src/utils.c new file mode 100644 index 000000000..5cf1e0e73 --- /dev/null +++ b/sept/sept-primary/src/utils.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include "utils.h" +#include "se.h" +#include "fuse.h" +#include "pmc.h" +#include "timers.h" +#include "panic.h" +#include "car.h" +#include "btn.h" + +#include + +#define u8 uint8_t +#define u32 uint32_t +#include "rebootstub_bin.h" +#undef u8 +#undef u32 + +void wait(uint32_t microseconds) { + uint32_t old_time = TIMERUS_CNTR_1US_0; + while (TIMERUS_CNTR_1US_0 - old_time <= microseconds) { + /* Spin-lock. */ + } +} + +__attribute__((noreturn)) void watchdog_reboot(void) { + volatile watchdog_timers_t *wdt = GET_WDT(4); + wdt->PATTERN = WDT_REBOOT_PATTERN; + wdt->COMMAND = 2; /* Disable Counter. */ + GET_WDT_REBOOT_CFG_REG(4) = 0xC0000000; + wdt->CONFIG = 0x8019; /* Full System Reset after Fourth Counter expires, using TIMER(9). */ + wdt->COMMAND = 1; /* Enable Counter. */ + while (true) { + /* Wait for reboot. */ + } +} + +__attribute__((noreturn)) void pmc_reboot(uint32_t scratch0) { + APBDEV_PMC_SCRATCH0_0 = scratch0; + + /* Reset the processor. */ + APBDEV_PMC_CONTROL = BIT(4); + + while (true) { + /* Wait for reboot. */ + } +} + +__attribute__((noreturn)) void reboot_to_self(void) { + /* Patch SDRAM init to perform an SVC immediately after second write */ + APBDEV_PMC_SCRATCH45_0 = 0x2E38DFFF; + APBDEV_PMC_SCRATCH46_0 = 0x6001DC28; + /* Set SVC handler to jump to reboot stub in IRAM. */ + APBDEV_PMC_SCRATCH33_0 = 0x4003F000; + APBDEV_PMC_SCRATCH40_0 = 0x6000F208; + + /* Copy reboot stub into IRAM high. */ + for (size_t i = 0; i < rebootstub_bin_size; i += sizeof(uint32_t)) { + write32le((void *)0x4003F000, i, read32le(rebootstub_bin, i)); + } + + /* Trigger warm reboot. */ + pmc_reboot(1 << 0); +} + +__attribute__((noreturn)) void wait_for_button_and_reboot(void) { + uint32_t button; + while (true) { + button = btn_read(); + if (button & BTN_POWER) { + reboot_to_self(); + } + } +} + +__attribute__ ((noreturn)) void generic_panic(void) { + panic(0xFF000006); +} + +__attribute__((noinline)) bool overlaps(uint64_t as, uint64_t ae, uint64_t bs, uint64_t be) +{ + if(as <= bs && bs <= ae) + return true; + if(bs <= as && as <= be) + return true; + return false; +} + diff --git a/sept/sept-primary/src/utils.h b/sept/sept-primary/src/utils.h new file mode 100644 index 000000000..03388c631 --- /dev/null +++ b/sept/sept-primary/src/utils.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef FUSEE_UTILS_H +#define FUSEE_UTILS_H + +#include +#include +#include +#include + +#define BIT(n) (1u << (n)) +#define BITL(n) (1ull << (n)) +#define MASK(n) (BIT(n) - 1) +#define MASKL(n) (BITL(n) - 1) +#define MASK2(a,b) (MASK(a) & ~MASK(b)) +#define MASK2L(a,b) (MASKL(a) & ~MASKL(b)) + +#define MAKE_REG32(a) (*(volatile uint32_t *)(a)) + +#define ALIGN(m) __attribute__((aligned(m))) +#define PACKED __attribute__((packed)) + +#define ALINLINE __attribute__((always_inline)) +#define NOINLINE __attribute__((noinline)) + +#define SET_SYSREG(reg, val) do { temp_reg = (val); __asm__ __volatile__ ("msr " #reg ", %0" :: "r"(temp_reg) : "memory"); } while(false) + +static inline uintptr_t get_physical_address(const void *addr) { + return (uintptr_t)addr; +} + +static inline uint32_t read32le(const volatile void *dword, size_t offset) { + uintptr_t addr = (uintptr_t)dword + offset; + volatile uint32_t *target = (uint32_t *)addr; + return *target; +} + +static inline uint32_t read32be(const volatile void *dword, size_t offset) { + return __builtin_bswap32(read32le(dword, offset)); +} + +static inline uint64_t read64le(const volatile void *qword, size_t offset) { + uintptr_t addr = (uintptr_t)qword + offset; + volatile uint64_t *target = (uint64_t *)addr; + return *target; +} + +static inline uint64_t read64be(const volatile void *qword, size_t offset) { + return __builtin_bswap64(read64le(qword, offset)); +} + +static inline void write32le(volatile void *dword, size_t offset, uint32_t value) { + uintptr_t addr = (uintptr_t)dword + offset; + volatile uint32_t *target = (uint32_t *)addr; + *target = value; +} + +static inline void write32be(volatile void *dword, size_t offset, uint32_t value) { + write32le(dword, offset, __builtin_bswap32(value)); +} + +static inline void write64le(volatile void *qword, size_t offset, uint64_t value) { + uintptr_t addr = (uintptr_t)qword + offset; + volatile uint64_t *target = (uint64_t *)addr; + *target = value; +} + +static inline void write64be(volatile void *qword, size_t offset, uint64_t value) { + write64le(qword, offset, __builtin_bswap64(value)); +} + +static inline bool check_32bit_additive_overflow(uint32_t a, uint32_t b) { + return __builtin_add_overflow_p(a, b, (uint32_t)0); +} + +static inline bool check_32bit_address_loadable(uintptr_t addr) { + /* FWIW the bootROM forbids loading anything between 0x40000000 and 0x40010000, using it for itself... */ + return (addr >= 0x40010000u && addr < 0x40040000u) || addr >= 0x80000000u; +} + +static inline bool check_32bit_address_range_loadable(uintptr_t addr, size_t size) { + return + !__builtin_add_overflow_p(addr, size, (uintptr_t)0) && /* the range doesn't overflow */ + check_32bit_address_loadable(addr) && check_32bit_address_loadable(addr + size) && /* bounds are valid */ + !(addr >= 0x40010000u && addr < 0x40040000u && addr + size >= 0x40040000u) /* the range doesn't cross MMIO */ + ; +} + +bool overlaps(uint64_t as, uint64_t ae, uint64_t bs, uint64_t be); +static inline bool overlaps_a(const void *as, const void *ae, const void *bs, const void *be) { + return overlaps((uint64_t)(uintptr_t)as, (uint64_t)(uintptr_t)ae, (uint64_t)(uintptr_t)bs, (uint64_t)(uintptr_t)be); +} + +static inline bool check_32bit_address_range_in_program(uintptr_t addr, size_t size) { + extern uint8_t __chainloader_start__[], __chainloader_end__[]; + extern uint8_t __stack_bottom__[], __stack_top__[]; + extern uint8_t __start__[], __end__[]; + uint8_t *start = (uint8_t *)addr, *end = start + size; + + return overlaps_a(start, end, __chainloader_start__, __chainloader_end__) || + overlaps_a(start, end, __stack_bottom__, __stack_top__) || + overlaps_a(start, end, (void *)0xC0000000, (void *)0xC03C0000) || /* framebuffer */ + overlaps_a(start, end, __start__, __end__); +} + +void hexdump(const void* data, size_t size, uintptr_t addrbase); + +__attribute__((noreturn)) void watchdog_reboot(void); +__attribute__((noreturn)) void pmc_reboot(uint32_t scratch0); +__attribute__((noreturn)) void reboot_to_self(void); +__attribute__((noreturn)) void wait_for_button_and_reboot(void); + +__attribute__((noreturn)) void generic_panic(void); + +#endif