diff --git a/exosphere/Makefile b/exosphere/Makefile index 11339bb..4eb2d44 100644 --- a/exosphere/Makefile +++ b/exosphere/Makefile @@ -75,14 +75,14 @@ export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ $(foreach dir,$(DATA),$(CURDIR)/$(dir)) \ - $(TOPDIR)/bpmpfw + $(TOPDIR)/sc7fw 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)/*.*))) bpmpfw.bin +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) sc7fw.bin #--------------------------------------------------------------------------------- # use CXX for linking C++ projects, CC for standard C @@ -109,22 +109,22 @@ export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) -.PHONY: $(BUILD) build_bpmpfw clean all +.PHONY: $(BUILD) build_sc7fw clean all #--------------------------------------------------------------------------------- all: $(BUILD) -check_bpmpfw: - @$(MAKE) -C bpmpfw all +check_sc7fw: + @$(MAKE) -C sc7fw all -$(BUILD): check_bpmpfw +$(BUILD): check_sc7fw @[ -d $@ ] || mkdir -p $@ @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile #--------------------------------------------------------------------------------- clean: @echo clean ... - @$(MAKE) -C $(TOPDIR)/bpmpfw clean + @$(MAKE) -C $(TOPDIR)/sc7fw clean @rm -fr $(BUILD) $(TARGET).bin $(TARGET).elf diff --git a/exosphere/bpmpfw/Makefile b/exosphere/bpmpfw/Makefile deleted file mode 100644 index 0eadd13..0000000 --- a/exosphere/bpmpfw/Makefile +++ /dev/null @@ -1,154 +0,0 @@ -#--------------------------------------------------------------------------------- -.SUFFIXES: -#--------------------------------------------------------------------------------- - -ifeq ($(strip $(DEVKITARM)),) -$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") -endif - -TOPDIR ?= $(CURDIR) -include $(DEVKITARM)/base_rules - -#--------------------------------------------------------------------------------- -# 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 -DATA := data -INCLUDES := include - -#--------------------------------------------------------------------------------- -# options for code generation -#--------------------------------------------------------------------------------- -ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork - -CFLAGS := \ - -g \ - -O2 \ - -ffunction-sections \ - -fdata-sections \ - -fomit-frame-pointer \ - -fno-inline \ - -std=gnu11 \ - -Werror \ - -Wall \ - $(ARCH) $(DEFINES) - -CFLAGS += $(INCLUDE) -D__BPMP__ - -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)) - -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)/*.*))) - -#--------------------------------------------------------------------------------- -# 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 - -#--------------------------------------------------------------------------------- -all: $(BUILD) - -$(BUILD): - @[ -d $@ ] || mkdir -p $@ - @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -#--------------------------------------------------------------------------------- -clean: - @echo 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 -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- diff --git a/exosphere/bpmpfw/linker.ld b/exosphere/bpmpfw/linker.ld deleted file mode 100644 index fd42725..0000000 --- a/exosphere/bpmpfw/linker.ld +++ /dev/null @@ -1,21 +0,0 @@ -OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") -OUTPUT_ARCH(arm) - -ENTRY(_start) -SECTIONS -{ - . = 0x40003000; - - __start__ = ABSOLUTE(.); - - .text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); } - .rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); } - .bss : ALIGN(8) { __bss_start__ = .; *(.bss* COMMON); . = ALIGN(8); __bss_end__ = .; } - - . = ALIGN(4); - - __end__ = ABSOLUTE(.); - - __stack_top__ = 0x40005000; - __stack_bottom__ = 0x40004000; -} \ No newline at end of file diff --git a/exosphere/bpmpfw/linker.specs b/exosphere/bpmpfw/linker.specs deleted file mode 100644 index 3009904..0000000 --- a/exosphere/bpmpfw/linker.specs +++ /dev/null @@ -1,7 +0,0 @@ -%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/exosphere/bpmpfw/src/emc.c b/exosphere/bpmpfw/src/emc.c deleted file mode 100644 index e774796..0000000 --- a/exosphere/bpmpfw/src/emc.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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 "utils.h" -#include "lp0.h" -#include "emc.h" -#include "pmc.h" -#include "timer.h" - -static void emc_trigger_timing_update(void) { - EMC_TIMING_CONTROL_0 = 1; - while (EMC_EMC_STATUS_0 & 0x800000) { - /* Wait until TIMING_UPDATE_STALLED is unset. */ - } -} - -/* Puts DRAM into self refresh mode. */ -void emc_put_dram_in_self_refresh_mode(void) { - /* Verify CH1_ENABLE [PMC]. */ - if (!(EMC_FBIO_CFG7_0 & 4)) { - reboot(); - } - - /* Clear config. */ - EMC_CFG_0 = 0; - emc_trigger_timing_update(); - timer_wait(5); - - /* Set calibration intervals. */ - EMC_ZCAL_INTERVAL_0 = 0; - EMC_AUTO_CAL_CONFIG_0 = 0x600; /* AUTO_CAL_MEASURE_STALL | AUTO_CAL_UPDATE_STALL */ - - /* If EMC0 mirror is set, clear digital DLL. */ - if (EMC0_CFG_DIG_DLL_0 & 1) { - EMC_CFG_DIG_DLL_0 &= 0xFFFFFFFE; - emc_trigger_timing_update(); - while (EMC0_CFG_DIG_DLL_0 & 1) { /* Wait for EMC0 to clear. */ } - while (EMC1_CFG_DIG_DLL_0 & 1) { /* Wait for EMC1 to clear. */ } - } else { - emc_trigger_timing_update(); - } - - /* Stall all transactions to DRAM. */ - EMC_REQ_CTRL_0 = 3; /* STALL_ALL_WRITES | STALL_ALL_READS. */ - while (!(EMC0_EMC_STATUS_0 & 4)) { /* Wait for NO_OUTSTANDING_TRANSACTIONS for EMC0. */ } - while (!(EMC1_EMC_STATUS_0 & 4)) { /* Wait for NO_OUTSTANDING_TRANSACTIONS for EMC1. */ } - - /* Enable Self-Refresh Mode. */ - EMC_SELF_REF_0 |= 1; - - - /* Wait until we see the right devices in self refresh mode. */ - uint32_t num_populated_devices = 1; - if (EMC_ADR_CFG_0) { - num_populated_devices = 3; - } - - while (((EMC0_EMC_STATUS_0 >> 8) & 3) != num_populated_devices) { /* Wait for EMC0 DRAM_IN_SELF_REFRESH to be correct. */ } - while (((EMC1_EMC_STATUS_0 >> 8) & 3) != num_populated_devices) { /* Wait for EMC1 DRAM_IN_SELF_REFRESH to be correct. */ } -} diff --git a/exosphere/bpmpfw/src/emc.h b/exosphere/bpmpfw/src/emc.h deleted file mode 100644 index 30ac6e6..0000000 --- a/exosphere/bpmpfw/src/emc.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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 EXOSPHERE_BPMPFW_EMC_H -#define EXOSPHERE_BPMPFW_EMC_H - -#include "utils.h" - -#define EMC_BASE (0x7001B000) - -#define EMC0_BASE (0x7001E000) -#define EMC1_BASE (0x7001F000) - - -#define MAKE_EMC_REG(ofs) (MAKE_REG32(EMC_BASE + ofs)) - -#define MAKE_EMC0_REG(ofs) (MAKE_REG32(EMC0_BASE + ofs)) -#define MAKE_EMC1_REG(ofs) (MAKE_REG32(EMC1_BASE + ofs)) - -#define EMC_CFG_0 MAKE_EMC_REG(0x00C) - -#define EMC_ADR_CFG_0 MAKE_EMC_REG(0x10) - -#define EMC_TIMING_CONTROL_0 MAKE_EMC_REG(0x028) - -#define EMC_SELF_REF_0 MAKE_EMC_REG(0x0E0) - -#define EMC_MRW_0 MAKE_EMC_REG(0x0E8) - -#define EMC_FBIO_CFG5_0 MAKE_EMC_REG(0x104) - -#define EMC_MRW3_0 MAKE_EMC_REG(0x138) - -#define EMC_AUTO_CAL_CONFIG_0 MAKE_EMC_REG(0x2A4) - -#define EMC_REQ_CTRL_0 MAKE_EMC_REG(0x2B0) - -#define EMC_EMC_STATUS_0 MAKE_EMC_REG(0x2B4) -#define EMC0_EMC_STATUS_0 MAKE_EMC0_REG(0x2B4) -#define EMC1_EMC_STATUS_0 MAKE_EMC1_REG(0x2B4) - -#define EMC_CFG_DIG_DLL_0 MAKE_EMC_REG(0x2BC) -#define EMC0_CFG_DIG_DLL_0 MAKE_EMC0_REG(0x2BC) -#define EMC1_CFG_DIG_DLL_0 MAKE_EMC1_REG(0x2BC) - -#define EMC_ZCAL_INTERVAL_0 MAKE_EMC_REG(0x2E0) - -#define EMC_PMC_SCRATCH3_0 MAKE_EMC_REG(0x448) - -#define EMC_FBIO_CFG7_0 MAKE_EMC_REG(0x584) - -void emc_put_dram_in_self_refresh_mode(void); - -#endif diff --git a/exosphere/bpmpfw/src/i2c.c b/exosphere/bpmpfw/src/i2c.c deleted file mode 100644 index 55225c9..0000000 --- a/exosphere/bpmpfw/src/i2c.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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 "timer.h" - -/* Prototypes for internal commands. */ -void i2c_load_config(void); -int i2c_write(unsigned int device, uint32_t val, unsigned int num_bytes); -int i2c_send_byte_command(unsigned int device, unsigned char reg, unsigned char b); - -/* Load hardware config for I2C4. */ -void i2c_load_config(void) { - /* Set MSTR_CONFIG_LOAD, TIMEOUT_CONFIG_LOAD, undocumented bit. */ - I2C_I2C_CONFIG_LOAD_0 = 0x25; - - /* Wait a bit for master config to be loaded. */ - for (unsigned int i = 0; i < 20; i++) { - timer_wait(1); - if (!(I2C_I2C_CONFIG_LOAD_0 & 1)) { - break; - } - } -} - -/* Initialize I2C4. */ -void i2c_init(void) { - /* Setup divisor, and clear the bus. */ - I2C_I2C_CLK_DIVISOR_REGISTER_0 = 0x50001; - I2C_I2C_BUS_CLEAR_CONFIG_0 = 0x90003; - - /* Load hardware configuration. */ - i2c_load_config(); - - /* Wait a while until BUS_CLEAR_DONE is set. */ - for (unsigned int i = 0; i < 10; i++) { - timer_wait(20000); - if (I2C_INTERRUPT_STATUS_REGISTER_0 & 0x800) { - break; - } - } - - /* Read the BUS_CLEAR_STATUS. Result doesn't matter. */ - I2C_I2C_BUS_CLEAR_STATUS_0; - - /* Read and set the Interrupt Status. */ - uint32_t int_status = I2C_INTERRUPT_STATUS_REGISTER_0; - I2C_INTERRUPT_STATUS_REGISTER_0 = int_status; -} - -/* Writes a value to an i2c device. */ -int i2c_write(unsigned int device, uint32_t val, unsigned int num_bytes) { - if (num_bytes > 4) { - return 0; - } - - /* Set device for 7-bit mode. */ - I2C_I2C_CMD_ADDR0_0 = device << 1; - - /* Load in data to write. */ - I2C_I2C_CMD_DATA1_0 = val; - - /* Set config with LENGTH = num_bytes, NEW_MASTER_FSM, DEBOUNCE_CNT = 4T. */ - I2C_I2C_CNFG_0 = ((num_bytes << 1) - 2) | 0x2800; - - i2c_load_config(); - - /* Config |= SEND; */ - I2C_I2C_CNFG_0 |= 0x200; - - - while (I2C_I2C_STATUS_0 & 0x100) { - /* Wait until not busy. */ - } - - /* Return CMD1_STAT == SL1_XFER_SUCCESSFUL. */ - return (I2C_I2C_STATUS_0 & 0xF) == 0; -} - -/* Writes a byte val to reg for given device. */ -int i2c_send_byte_command(unsigned int device, unsigned char reg, unsigned char b) { - uint32_t val = (reg) | (b << 8); - /* Write 1 byte (reg) + 1 byte (value) */ - return i2c_write(device, val, 2); -} - -/* Actually reset device 27. This might turn off the screen? */ -int i2c_send_reset_cmd(void) { - /* Write 00 to Device 27 Reg 00. */ - return i2c_send_byte_command(27, 0, 0); -} diff --git a/exosphere/bpmpfw/src/i2c.h b/exosphere/bpmpfw/src/i2c.h deleted file mode 100644 index b2a755a..0000000 --- a/exosphere/bpmpfw/src/i2c.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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 EXOSPHERE_BPMPFW_I2C_H -#define EXOSPHERE_BPMPFW_I2C_H - -#include "utils.h" - -/* I2C_BASE = I2C4. */ -#define I2C_BASE (0x7000D000) - -#define MAKE_I2C_REG(ofs) (MAKE_REG32(I2C_BASE + ofs)) - -#define I2C_I2C_CNFG_0 MAKE_I2C_REG(0x000) - -#define I2C_I2C_CMD_ADDR0_0 MAKE_I2C_REG(0x004) - -#define I2C_I2C_CMD_DATA1_0 MAKE_I2C_REG(0x00C) - -#define I2C_I2C_STATUS_0 MAKE_I2C_REG(0x01C) - -#define I2C_INTERRUPT_STATUS_REGISTER_0 MAKE_I2C_REG(0x068) - -#define I2C_I2C_CLK_DIVISOR_REGISTER_0 MAKE_I2C_REG(0x06C) - -#define I2C_I2C_BUS_CLEAR_CONFIG_0 MAKE_I2C_REG(0x084) - -#define I2C_I2C_BUS_CLEAR_STATUS_0 MAKE_I2C_REG(0x088) - - -#define I2C_I2C_CONFIG_LOAD_0 MAKE_I2C_REG(0x08C) - -void i2c_init(void); - -int i2c_send_reset_cmd(void); - -#endif diff --git a/exosphere/bpmpfw/src/lp0.c b/exosphere/bpmpfw/src/lp0.c deleted file mode 100644 index 21de19c..0000000 --- a/exosphere/bpmpfw/src/lp0.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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 "utils.h" -#include "lp0.h" -#include "i2c.h" -#include "pmc.h" -#include "emc.h" -#include "timer.h" - -#define CACHE_CTRL MAKE_REG32(0x50040000) - -#define PRI_ICTLR_COP_IER_CLR_0 MAKE_REG32(0x60004038) -#define SEC_ICTLR_COP_IER_CLR_0 MAKE_REG32(0x60004138) -#define TRI_ICTLR_COP_IER_CLR_0 MAKE_REG32(0x60004238) -#define QUAD_ICTLR_COP_IER_CLR_0 MAKE_REG32(0x60004338) -#define PENTA_ICTLR_COP_IER_CLR_0 MAKE_REG32(0x60004438) -#define HEXA_ICTLR_COP_IER_CLR_0 MAKE_REG32(0x60004538) - -void reboot(void) { - /* Write MAIN_RST */ - APBDEV_PMC_CNTRL_0 = 0x10; - while (true) { - /* Wait for reboot. */ - } -} - - -static void set_pmc_dpd_io_pads(void) { - /* Read val from EMC_PMC scratch, configure accordingly. */ - uint32_t emc_pmc_val = EMC_PMC_SCRATCH3_0; - APBDEV_PMC_DDR_CNTRL_0 = emc_pmc_val & 0x7FFFF; - if (emc_pmc_val & 0x40000000) { - APBDEV_PMC_WEAK_BIAS_0 = 0x7FFF0000; - } - /* Request to put pads in Deep Power Down. */ - APBDEV_PMC_IO_DPD3_REQ_0 = 0x8FFFFFFF; - while (APBDEV_PMC_IO_DPD3_STATUS_0 != 0xFFFFFFF) { /* Wait a while. */ } - spinlock_wait(32); - APBDEV_PMC_IO_DPD4_REQ_0 = 0x8FFFFFFF; - while (APBDEV_PMC_IO_DPD4_STATUS_0 != 0xFFF1FFF) { /* Wait a while. */ } - spinlock_wait(32); -} - -void lp0_entry_main(void) { - /* Disable the BPMP Cache. */ - CACHE_CTRL |= 0xC00; - - /* Wait until the CPU Rail is turned off. */ - while (APBDEV_PMC_PWRGATE_STATUS_0 & 1) { /* Wait for TrustZone to finish. */ } - - /* Clamp the CPU Rail. */ - APBDEV_PMC_SET_SW_CLAMP_0 |= 0x1; - while (!(APBDEV_PMC_CLAMP_STATUS_0 & 1)) { /* Wait for CPU Rail to be clamped. */ } - - /* Waste some time. */ - spinlock_wait(10); - - /* Reset device 27 over I2C, then wait a while. */ - i2c_init(); - i2c_send_reset_cmd(); - timer_wait(700); - - /* Clear Interrupt Enable for BPMP in all ICTLRs. */ - PRI_ICTLR_COP_IER_CLR_0 = 0xFFFFFFFF; - SEC_ICTLR_COP_IER_CLR_0 = 0xFFFFFFFF; - TRI_ICTLR_COP_IER_CLR_0 = 0xFFFFFFFF; - QUAD_ICTLR_COP_IER_CLR_0 = 0xFFFFFFFF; - PENTA_ICTLR_COP_IER_CLR_0 = 0xFFFFFFFF; - HEXA_ICTLR_COP_IER_CLR_0 = 0xFFFFFFFF; - - /* Write EMC's DRAM op into PMC scratch. */ - if ((EMC_FBIO_CFG5_0 & 3) != 1) { - /* If DRAM_TYPE != LPDDR4, something's gone wrong. Reboot. */ - reboot(); - } - /* Write MRW3_OP into scratch. */ - APBDEV_PMC_SCRATCH18_0 = (APBDEV_PMC_SCRATCH18_0 & 0xFFFFFF3F) | (EMC_MRW3_0 & 0xC0); - uint32_t mrw3_op = ((EMC_MRW3_0 & 0xC0) << 8) | (EMC_MRW3_0 & 0xC0); - APBDEV_PMC_SCRATCH12_0 = (APBDEV_PMC_SCRATCH12_0 & 0xFFFF3F3F) | mrw3_op; - APBDEV_PMC_SCRATCH13_0 = (APBDEV_PMC_SCRATCH13_0 & 0xFFFF3F3F) | mrw3_op; - - /* Ready DRAM for deep sleep. */ - emc_put_dram_in_self_refresh_mode(); - - /* Setup LPDDR MRW based on device config. */ - EMC_MRW_0 = 0x88110000; - if (EMC_ADR_CFG_0 & 1) { - EMC_MRW_0 = 0x48110000; - } - - /* Put IO pads in Deep Power Down. */ - set_pmc_dpd_io_pads(); - - /* Enable pad sampling during deep sleep. */ - APBDEV_PMC_DPD_SAMPLE_0 |= 1; - - /* Waste some more time. */ - spinlock_wait(0x128); - - /* Enter deep sleep. */ - APBDEV_PMC_DPD_ENABLE_0 |= 1; - - while (true) { /* Wait until we're asleep. */ } -} - - diff --git a/exosphere/bpmpfw/src/lp0.h b/exosphere/bpmpfw/src/lp0.h deleted file mode 100644 index 2505949..0000000 --- a/exosphere/bpmpfw/src/lp0.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 EXOSPHERE_BPMPFW_LP0_H -#define EXOSPHERE_BPMPFW_LP0_H - -#include "utils.h" - -void lp0_entry_main(void); - -void reboot(void); - -#endif diff --git a/exosphere/bpmpfw/src/pmc.h b/exosphere/bpmpfw/src/pmc.h deleted file mode 100644 index 6b8120c..0000000 --- a/exosphere/bpmpfw/src/pmc.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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 EXOSPHERE_BPMPFW_PMC_H -#define EXOSPHERE_BPMPFW_PMC_H - -#include "utils.h" - -#define PMC_BASE (0x7000E400) - -#define MAKE_PMC_REG(ofs) (MAKE_REG32(PMC_BASE + ofs)) - -#define APBDEV_PMC_CNTRL_0 MAKE_PMC_REG(0x000) - -#define APBDEV_PMC_DPD_SAMPLE_0 MAKE_PMC_REG(0x020) - -#define APBDEV_PMC_DPD_ENABLE_0 MAKE_PMC_REG(0x024) - -#define APBDEV_PMC_CLAMP_STATUS_0 MAKE_PMC_REG(0x02C) - -#define APBDEV_PMC_PWRGATE_STATUS_0 MAKE_PMC_REG(0x038) - -#define APBDEV_PMC_SCRATCH12_0 MAKE_PMC_REG(0x080) -#define APBDEV_PMC_SCRATCH13_0 MAKE_PMC_REG(0x084) -#define APBDEV_PMC_SCRATCH18_0 MAKE_PMC_REG(0x098) - - -#define APBDEV_PMC_WEAK_BIAS_0 MAKE_PMC_REG(0x2C8) - -#define APBDEV_PMC_IO_DPD3_REQ_0 MAKE_PMC_REG(0x45C) -#define APBDEV_PMC_IO_DPD3_STATUS_0 MAKE_PMC_REG(0x460) - -#define APBDEV_PMC_IO_DPD4_REQ_0 MAKE_PMC_REG(0x464) -#define APBDEV_PMC_IO_DPD4_STATUS_0 MAKE_PMC_REG(0x468) - -#define APBDEV_PMC_SET_SW_CLAMP_0 MAKE_PMC_REG(0x47C) - -#define APBDEV_PMC_DDR_CNTRL_0 MAKE_PMC_REG(0x4E4) - -#endif diff --git a/exosphere/bpmpfw/src/start.s b/exosphere/bpmpfw/src/start.s deleted file mode 100644 index a439b7d..0000000 --- a/exosphere/bpmpfw/src/start.s +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 -.align 4 -.global _start -_start: - b crt0 -.global _reboot - b reboot - -.global crt0 -.type crt0, %function -crt0: - @ setup to call lp0_entry_main - msr cpsr_cxsf, #0xD3 - ldr sp, =__stack_top__ - ldr lr, =reboot - b lp0_entry_main - - -.global spinlock_wait -.type spinlock_wait, %function -spinlock_wait: - subs r0, r0, #1 - bgt spinlock_wait - bx lr diff --git a/exosphere/bpmpfw/src/timer.h b/exosphere/bpmpfw/src/timer.h deleted file mode 100644 index 62ab23c..0000000 --- a/exosphere/bpmpfw/src/timer.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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 EXOSPHERE_BPMPFW_TIMER_H -#define EXOSPHERE_BPMPFW_TIMER_H - -#include "utils.h" - -#define TIMERUS_CNTR_1US_0 MAKE_REG32(0x60005010) - -static inline void timer_wait(uint32_t microseconds) { - uint32_t old_time = TIMERUS_CNTR_1US_0; - while (TIMERUS_CNTR_1US_0 - old_time <= microseconds) { - /* Spin-lock. */ - } -} - -void spinlock_wait(uint32_t count); - -#endif diff --git a/exosphere/bpmpfw/src/utils.h b/exosphere/bpmpfw/src/utils.h deleted file mode 100644 index e0b908e..0000000 --- a/exosphere/bpmpfw/src/utils.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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 EXOSPHERE_BPMPFW_UTILS_H -#define EXOSPHERE_BPMPFW_UTILS_H - -#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)) - -#endif diff --git a/exosphere/sc7fw/Makefile b/exosphere/sc7fw/Makefile new file mode 100644 index 0000000..0eadd13 --- /dev/null +++ b/exosphere/sc7fw/Makefile @@ -0,0 +1,154 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +TOPDIR ?= $(CURDIR) +include $(DEVKITARM)/base_rules + +#--------------------------------------------------------------------------------- +# 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 +DATA := data +INCLUDES := include + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork + +CFLAGS := \ + -g \ + -O2 \ + -ffunction-sections \ + -fdata-sections \ + -fomit-frame-pointer \ + -fno-inline \ + -std=gnu11 \ + -Werror \ + -Wall \ + $(ARCH) $(DEFINES) + +CFLAGS += $(INCLUDE) -D__BPMP__ + +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)) + +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)/*.*))) + +#--------------------------------------------------------------------------------- +# 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 + +#--------------------------------------------------------------------------------- +all: $(BUILD) + +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo 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 +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/exosphere/sc7fw/linker.ld b/exosphere/sc7fw/linker.ld new file mode 100644 index 0000000..fd42725 --- /dev/null +++ b/exosphere/sc7fw/linker.ld @@ -0,0 +1,21 @@ +OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") +OUTPUT_ARCH(arm) + +ENTRY(_start) +SECTIONS +{ + . = 0x40003000; + + __start__ = ABSOLUTE(.); + + .text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); } + .rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); } + .bss : ALIGN(8) { __bss_start__ = .; *(.bss* COMMON); . = ALIGN(8); __bss_end__ = .; } + + . = ALIGN(4); + + __end__ = ABSOLUTE(.); + + __stack_top__ = 0x40005000; + __stack_bottom__ = 0x40004000; +} \ No newline at end of file diff --git a/exosphere/sc7fw/linker.specs b/exosphere/sc7fw/linker.specs new file mode 100644 index 0000000..3009904 --- /dev/null +++ b/exosphere/sc7fw/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/exosphere/sc7fw/src/emc.c b/exosphere/sc7fw/src/emc.c new file mode 100644 index 0000000..6b6e166 --- /dev/null +++ b/exosphere/sc7fw/src/emc.c @@ -0,0 +1,73 @@ +/* + * 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 "utils.h" +#include "sc7.h" +#include "emc.h" +#include "pmc.h" +#include "timer.h" + +static void emc_trigger_timing_update(void) { + EMC_TIMING_CONTROL_0 = 1; + while (EMC_EMC_STATUS_0 & 0x800000) { + /* Wait until TIMING_UPDATE_STALLED is unset. */ + } +} + +/* Puts DRAM into self refresh mode. */ +void emc_put_dram_in_self_refresh_mode(void) { + /* Verify CH1_ENABLE [PMC]. */ + if (!(EMC_FBIO_CFG7_0 & 4)) { + reboot(); + } + + /* Clear config. */ + EMC_CFG_0 = 0; + emc_trigger_timing_update(); + timer_wait(5); + + /* Set calibration intervals. */ + EMC_ZCAL_INTERVAL_0 = 0; + EMC_AUTO_CAL_CONFIG_0 = 0x600; /* AUTO_CAL_MEASURE_STALL | AUTO_CAL_UPDATE_STALL */ + + /* If EMC0 mirror is set, clear digital DLL. */ + if (EMC0_CFG_DIG_DLL_0 & 1) { + EMC_CFG_DIG_DLL_0 &= 0xFFFFFFFE; + emc_trigger_timing_update(); + while (EMC0_CFG_DIG_DLL_0 & 1) { /* Wait for EMC0 to clear. */ } + while (EMC1_CFG_DIG_DLL_0 & 1) { /* Wait for EMC1 to clear. */ } + } else { + emc_trigger_timing_update(); + } + + /* Stall all transactions to DRAM. */ + EMC_REQ_CTRL_0 = 3; /* STALL_ALL_WRITES | STALL_ALL_READS. */ + while (!(EMC0_EMC_STATUS_0 & 4)) { /* Wait for NO_OUTSTANDING_TRANSACTIONS for EMC0. */ } + while (!(EMC1_EMC_STATUS_0 & 4)) { /* Wait for NO_OUTSTANDING_TRANSACTIONS for EMC1. */ } + + /* Enable Self-Refresh Mode. */ + EMC_SELF_REF_0 |= 1; + + + /* Wait until we see the right devices in self refresh mode. */ + uint32_t num_populated_devices = 1; + if (EMC_ADR_CFG_0) { + num_populated_devices = 3; + } + + while (((EMC0_EMC_STATUS_0 >> 8) & 3) != num_populated_devices) { /* Wait for EMC0 DRAM_IN_SELF_REFRESH to be correct. */ } + while (((EMC1_EMC_STATUS_0 >> 8) & 3) != num_populated_devices) { /* Wait for EMC1 DRAM_IN_SELF_REFRESH to be correct. */ } +} diff --git a/exosphere/sc7fw/src/emc.h b/exosphere/sc7fw/src/emc.h new file mode 100644 index 0000000..30ac6e6 --- /dev/null +++ b/exosphere/sc7fw/src/emc.h @@ -0,0 +1,67 @@ +/* + * 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 EXOSPHERE_BPMPFW_EMC_H +#define EXOSPHERE_BPMPFW_EMC_H + +#include "utils.h" + +#define EMC_BASE (0x7001B000) + +#define EMC0_BASE (0x7001E000) +#define EMC1_BASE (0x7001F000) + + +#define MAKE_EMC_REG(ofs) (MAKE_REG32(EMC_BASE + ofs)) + +#define MAKE_EMC0_REG(ofs) (MAKE_REG32(EMC0_BASE + ofs)) +#define MAKE_EMC1_REG(ofs) (MAKE_REG32(EMC1_BASE + ofs)) + +#define EMC_CFG_0 MAKE_EMC_REG(0x00C) + +#define EMC_ADR_CFG_0 MAKE_EMC_REG(0x10) + +#define EMC_TIMING_CONTROL_0 MAKE_EMC_REG(0x028) + +#define EMC_SELF_REF_0 MAKE_EMC_REG(0x0E0) + +#define EMC_MRW_0 MAKE_EMC_REG(0x0E8) + +#define EMC_FBIO_CFG5_0 MAKE_EMC_REG(0x104) + +#define EMC_MRW3_0 MAKE_EMC_REG(0x138) + +#define EMC_AUTO_CAL_CONFIG_0 MAKE_EMC_REG(0x2A4) + +#define EMC_REQ_CTRL_0 MAKE_EMC_REG(0x2B0) + +#define EMC_EMC_STATUS_0 MAKE_EMC_REG(0x2B4) +#define EMC0_EMC_STATUS_0 MAKE_EMC0_REG(0x2B4) +#define EMC1_EMC_STATUS_0 MAKE_EMC1_REG(0x2B4) + +#define EMC_CFG_DIG_DLL_0 MAKE_EMC_REG(0x2BC) +#define EMC0_CFG_DIG_DLL_0 MAKE_EMC0_REG(0x2BC) +#define EMC1_CFG_DIG_DLL_0 MAKE_EMC1_REG(0x2BC) + +#define EMC_ZCAL_INTERVAL_0 MAKE_EMC_REG(0x2E0) + +#define EMC_PMC_SCRATCH3_0 MAKE_EMC_REG(0x448) + +#define EMC_FBIO_CFG7_0 MAKE_EMC_REG(0x584) + +void emc_put_dram_in_self_refresh_mode(void); + +#endif diff --git a/exosphere/sc7fw/src/i2c.c b/exosphere/sc7fw/src/i2c.c new file mode 100644 index 0000000..55225c9 --- /dev/null +++ b/exosphere/sc7fw/src/i2c.c @@ -0,0 +1,104 @@ +/* + * 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 "timer.h" + +/* Prototypes for internal commands. */ +void i2c_load_config(void); +int i2c_write(unsigned int device, uint32_t val, unsigned int num_bytes); +int i2c_send_byte_command(unsigned int device, unsigned char reg, unsigned char b); + +/* Load hardware config for I2C4. */ +void i2c_load_config(void) { + /* Set MSTR_CONFIG_LOAD, TIMEOUT_CONFIG_LOAD, undocumented bit. */ + I2C_I2C_CONFIG_LOAD_0 = 0x25; + + /* Wait a bit for master config to be loaded. */ + for (unsigned int i = 0; i < 20; i++) { + timer_wait(1); + if (!(I2C_I2C_CONFIG_LOAD_0 & 1)) { + break; + } + } +} + +/* Initialize I2C4. */ +void i2c_init(void) { + /* Setup divisor, and clear the bus. */ + I2C_I2C_CLK_DIVISOR_REGISTER_0 = 0x50001; + I2C_I2C_BUS_CLEAR_CONFIG_0 = 0x90003; + + /* Load hardware configuration. */ + i2c_load_config(); + + /* Wait a while until BUS_CLEAR_DONE is set. */ + for (unsigned int i = 0; i < 10; i++) { + timer_wait(20000); + if (I2C_INTERRUPT_STATUS_REGISTER_0 & 0x800) { + break; + } + } + + /* Read the BUS_CLEAR_STATUS. Result doesn't matter. */ + I2C_I2C_BUS_CLEAR_STATUS_0; + + /* Read and set the Interrupt Status. */ + uint32_t int_status = I2C_INTERRUPT_STATUS_REGISTER_0; + I2C_INTERRUPT_STATUS_REGISTER_0 = int_status; +} + +/* Writes a value to an i2c device. */ +int i2c_write(unsigned int device, uint32_t val, unsigned int num_bytes) { + if (num_bytes > 4) { + return 0; + } + + /* Set device for 7-bit mode. */ + I2C_I2C_CMD_ADDR0_0 = device << 1; + + /* Load in data to write. */ + I2C_I2C_CMD_DATA1_0 = val; + + /* Set config with LENGTH = num_bytes, NEW_MASTER_FSM, DEBOUNCE_CNT = 4T. */ + I2C_I2C_CNFG_0 = ((num_bytes << 1) - 2) | 0x2800; + + i2c_load_config(); + + /* Config |= SEND; */ + I2C_I2C_CNFG_0 |= 0x200; + + + while (I2C_I2C_STATUS_0 & 0x100) { + /* Wait until not busy. */ + } + + /* Return CMD1_STAT == SL1_XFER_SUCCESSFUL. */ + return (I2C_I2C_STATUS_0 & 0xF) == 0; +} + +/* Writes a byte val to reg for given device. */ +int i2c_send_byte_command(unsigned int device, unsigned char reg, unsigned char b) { + uint32_t val = (reg) | (b << 8); + /* Write 1 byte (reg) + 1 byte (value) */ + return i2c_write(device, val, 2); +} + +/* Actually reset device 27. This might turn off the screen? */ +int i2c_send_reset_cmd(void) { + /* Write 00 to Device 27 Reg 00. */ + return i2c_send_byte_command(27, 0, 0); +} diff --git a/exosphere/sc7fw/src/i2c.h b/exosphere/sc7fw/src/i2c.h new file mode 100644 index 0000000..b2a755a --- /dev/null +++ b/exosphere/sc7fw/src/i2c.h @@ -0,0 +1,50 @@ +/* + * 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 EXOSPHERE_BPMPFW_I2C_H +#define EXOSPHERE_BPMPFW_I2C_H + +#include "utils.h" + +/* I2C_BASE = I2C4. */ +#define I2C_BASE (0x7000D000) + +#define MAKE_I2C_REG(ofs) (MAKE_REG32(I2C_BASE + ofs)) + +#define I2C_I2C_CNFG_0 MAKE_I2C_REG(0x000) + +#define I2C_I2C_CMD_ADDR0_0 MAKE_I2C_REG(0x004) + +#define I2C_I2C_CMD_DATA1_0 MAKE_I2C_REG(0x00C) + +#define I2C_I2C_STATUS_0 MAKE_I2C_REG(0x01C) + +#define I2C_INTERRUPT_STATUS_REGISTER_0 MAKE_I2C_REG(0x068) + +#define I2C_I2C_CLK_DIVISOR_REGISTER_0 MAKE_I2C_REG(0x06C) + +#define I2C_I2C_BUS_CLEAR_CONFIG_0 MAKE_I2C_REG(0x084) + +#define I2C_I2C_BUS_CLEAR_STATUS_0 MAKE_I2C_REG(0x088) + + +#define I2C_I2C_CONFIG_LOAD_0 MAKE_I2C_REG(0x08C) + +void i2c_init(void); + +int i2c_send_reset_cmd(void); + +#endif diff --git a/exosphere/sc7fw/src/pmc.h b/exosphere/sc7fw/src/pmc.h new file mode 100644 index 0000000..6b8120c --- /dev/null +++ b/exosphere/sc7fw/src/pmc.h @@ -0,0 +1,53 @@ +/* + * 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 EXOSPHERE_BPMPFW_PMC_H +#define EXOSPHERE_BPMPFW_PMC_H + +#include "utils.h" + +#define PMC_BASE (0x7000E400) + +#define MAKE_PMC_REG(ofs) (MAKE_REG32(PMC_BASE + ofs)) + +#define APBDEV_PMC_CNTRL_0 MAKE_PMC_REG(0x000) + +#define APBDEV_PMC_DPD_SAMPLE_0 MAKE_PMC_REG(0x020) + +#define APBDEV_PMC_DPD_ENABLE_0 MAKE_PMC_REG(0x024) + +#define APBDEV_PMC_CLAMP_STATUS_0 MAKE_PMC_REG(0x02C) + +#define APBDEV_PMC_PWRGATE_STATUS_0 MAKE_PMC_REG(0x038) + +#define APBDEV_PMC_SCRATCH12_0 MAKE_PMC_REG(0x080) +#define APBDEV_PMC_SCRATCH13_0 MAKE_PMC_REG(0x084) +#define APBDEV_PMC_SCRATCH18_0 MAKE_PMC_REG(0x098) + + +#define APBDEV_PMC_WEAK_BIAS_0 MAKE_PMC_REG(0x2C8) + +#define APBDEV_PMC_IO_DPD3_REQ_0 MAKE_PMC_REG(0x45C) +#define APBDEV_PMC_IO_DPD3_STATUS_0 MAKE_PMC_REG(0x460) + +#define APBDEV_PMC_IO_DPD4_REQ_0 MAKE_PMC_REG(0x464) +#define APBDEV_PMC_IO_DPD4_STATUS_0 MAKE_PMC_REG(0x468) + +#define APBDEV_PMC_SET_SW_CLAMP_0 MAKE_PMC_REG(0x47C) + +#define APBDEV_PMC_DDR_CNTRL_0 MAKE_PMC_REG(0x4E4) + +#endif diff --git a/exosphere/sc7fw/src/sc7.c b/exosphere/sc7fw/src/sc7.c new file mode 100644 index 0000000..4ae84b1 --- /dev/null +++ b/exosphere/sc7fw/src/sc7.c @@ -0,0 +1,120 @@ +/* + * 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 "utils.h" +#include "sc7.h" +#include "i2c.h" +#include "pmc.h" +#include "emc.h" +#include "timer.h" + +#define CACHE_CTRL MAKE_REG32(0x50040000) + +#define PRI_ICTLR_COP_IER_CLR_0 MAKE_REG32(0x60004038) +#define SEC_ICTLR_COP_IER_CLR_0 MAKE_REG32(0x60004138) +#define TRI_ICTLR_COP_IER_CLR_0 MAKE_REG32(0x60004238) +#define QUAD_ICTLR_COP_IER_CLR_0 MAKE_REG32(0x60004338) +#define PENTA_ICTLR_COP_IER_CLR_0 MAKE_REG32(0x60004438) +#define HEXA_ICTLR_COP_IER_CLR_0 MAKE_REG32(0x60004538) + +void reboot(void) { + /* Write MAIN_RST */ + APBDEV_PMC_CNTRL_0 = 0x10; + while (true) { + /* Wait for reboot. */ + } +} + + +static void set_pmc_dpd_io_pads(void) { + /* Read val from EMC_PMC scratch, configure accordingly. */ + uint32_t emc_pmc_val = EMC_PMC_SCRATCH3_0; + APBDEV_PMC_DDR_CNTRL_0 = emc_pmc_val & 0x7FFFF; + if (emc_pmc_val & 0x40000000) { + APBDEV_PMC_WEAK_BIAS_0 = 0x7FFF0000; + } + /* Request to put pads in Deep Power Down. */ + APBDEV_PMC_IO_DPD3_REQ_0 = 0x8FFFFFFF; + while (APBDEV_PMC_IO_DPD3_STATUS_0 != 0xFFFFFFF) { /* Wait a while. */ } + spinlock_wait(32); + APBDEV_PMC_IO_DPD4_REQ_0 = 0x8FFFFFFF; + while (APBDEV_PMC_IO_DPD4_STATUS_0 != 0xFFF1FFF) { /* Wait a while. */ } + spinlock_wait(32); +} + +void sc7_entry_main(void) { + /* Disable the BPMP Cache. */ + CACHE_CTRL |= 0xC00; + + /* Wait until the CPU Rail is turned off. */ + while (APBDEV_PMC_PWRGATE_STATUS_0 & 1) { /* Wait for TrustZone to finish. */ } + + /* Clamp the CPU Rail. */ + APBDEV_PMC_SET_SW_CLAMP_0 |= 0x1; + while (!(APBDEV_PMC_CLAMP_STATUS_0 & 1)) { /* Wait for CPU Rail to be clamped. */ } + + /* Waste some time. */ + spinlock_wait(10); + + /* Reset device 27 over I2C, then wait a while. */ + i2c_init(); + i2c_send_reset_cmd(); + timer_wait(700); + + /* Clear Interrupt Enable for BPMP in all ICTLRs. */ + PRI_ICTLR_COP_IER_CLR_0 = 0xFFFFFFFF; + SEC_ICTLR_COP_IER_CLR_0 = 0xFFFFFFFF; + TRI_ICTLR_COP_IER_CLR_0 = 0xFFFFFFFF; + QUAD_ICTLR_COP_IER_CLR_0 = 0xFFFFFFFF; + PENTA_ICTLR_COP_IER_CLR_0 = 0xFFFFFFFF; + HEXA_ICTLR_COP_IER_CLR_0 = 0xFFFFFFFF; + + /* Write EMC's DRAM op into PMC scratch. */ + if ((EMC_FBIO_CFG5_0 & 3) != 1) { + /* If DRAM_TYPE != LPDDR4, something's gone wrong. Reboot. */ + reboot(); + } + /* Write MRW3_OP into scratch. */ + APBDEV_PMC_SCRATCH18_0 = (APBDEV_PMC_SCRATCH18_0 & 0xFFFFFF3F) | (EMC_MRW3_0 & 0xC0); + uint32_t mrw3_op = ((EMC_MRW3_0 & 0xC0) << 8) | (EMC_MRW3_0 & 0xC0); + APBDEV_PMC_SCRATCH12_0 = (APBDEV_PMC_SCRATCH12_0 & 0xFFFF3F3F) | mrw3_op; + APBDEV_PMC_SCRATCH13_0 = (APBDEV_PMC_SCRATCH13_0 & 0xFFFF3F3F) | mrw3_op; + + /* Ready DRAM for deep sleep. */ + emc_put_dram_in_self_refresh_mode(); + + /* Setup LPDDR MRW based on device config. */ + EMC_MRW_0 = 0x88110000; + if (EMC_ADR_CFG_0 & 1) { + EMC_MRW_0 = 0x48110000; + } + + /* Put IO pads in Deep Power Down. */ + set_pmc_dpd_io_pads(); + + /* Enable pad sampling during deep sleep. */ + APBDEV_PMC_DPD_SAMPLE_0 |= 1; + + /* Waste some more time. */ + spinlock_wait(0x128); + + /* Enter deep sleep. */ + APBDEV_PMC_DPD_ENABLE_0 |= 1; + + while (true) { /* Wait until we're asleep. */ } +} + + diff --git a/exosphere/sc7fw/src/sc7.h b/exosphere/sc7fw/src/sc7.h new file mode 100644 index 0000000..37f95cb --- /dev/null +++ b/exosphere/sc7fw/src/sc7.h @@ -0,0 +1,26 @@ +/* + * 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 EXOSPHERE_BPMPFW_SC7_H +#define EXOSPHERE_BPMPFW_SC7_H + +#include "utils.h" + +void sc7_entry_main(void); + +void reboot(void); + +#endif diff --git a/exosphere/sc7fw/src/start.s b/exosphere/sc7fw/src/start.s new file mode 100644 index 0000000..c648a10 --- /dev/null +++ b/exosphere/sc7fw/src/start.s @@ -0,0 +1,40 @@ +/* + * 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 +.align 4 +.global _start +_start: + b crt0 +.global _reboot + b reboot + +.global crt0 +.type crt0, %function +crt0: + @ setup to call sc7_entry_main + msr cpsr_cxsf, #0xD3 + ldr sp, =__stack_top__ + ldr lr, =reboot + b sc7_entry_main + + +.global spinlock_wait +.type spinlock_wait, %function +spinlock_wait: + subs r0, r0, #1 + bgt spinlock_wait + bx lr diff --git a/exosphere/sc7fw/src/timer.h b/exosphere/sc7fw/src/timer.h new file mode 100644 index 0000000..62ab23c --- /dev/null +++ b/exosphere/sc7fw/src/timer.h @@ -0,0 +1,33 @@ +/* + * 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 EXOSPHERE_BPMPFW_TIMER_H +#define EXOSPHERE_BPMPFW_TIMER_H + +#include "utils.h" + +#define TIMERUS_CNTR_1US_0 MAKE_REG32(0x60005010) + +static inline void timer_wait(uint32_t microseconds) { + uint32_t old_time = TIMERUS_CNTR_1US_0; + while (TIMERUS_CNTR_1US_0 - old_time <= microseconds) { + /* Spin-lock. */ + } +} + +void spinlock_wait(uint32_t count); + +#endif diff --git a/exosphere/sc7fw/src/utils.h b/exosphere/sc7fw/src/utils.h new file mode 100644 index 0000000..e0b908e --- /dev/null +++ b/exosphere/sc7fw/src/utils.h @@ -0,0 +1,38 @@ +/* + * 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 EXOSPHERE_BPMPFW_UTILS_H +#define EXOSPHERE_BPMPFW_UTILS_H + +#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)) + +#endif diff --git a/exosphere/src/lp0.c b/exosphere/src/lp0.c deleted file mode 100644 index effb2dc..0000000 --- a/exosphere/src/lp0.c +++ /dev/null @@ -1,304 +0,0 @@ -/* - * 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 "utils.h" - -#include "car.h" -#include "bpmp.h" -#include "arm.h" -#include "configitem.h" -#include "cpu_context.h" -#include "flow.h" -#include "fuse.h" -#include "i2c.h" -#include "lp0.h" -#include "masterkey.h" -#include "pmc.h" -#include "se.h" -#include "smc_api.h" -#include "timers.h" -#include "misc.h" -#include "uart.h" -#include "exocfg.h" - -#define u8 uint8_t -#define u32 uint32_t -#include "bpmpfw_bin.h" -#undef u8 -#undef u32 - -static void configure_battery_hi_z_mode(void) { - clkrst_reboot(CARDEVICE_I2C1); - - if (configitem_should_profile_battery() && !i2c_query_ti_charger_bit_7()) { - /* Profile the battery. */ - i2c_set_ti_charger_bit_7(); - uint32_t start_time = get_time(); - bool should_wait = true; - /* TODO: This is GPIO-6 GPIO_IN_1 */ - while (MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_GPIO) + 0x634) & 1) { - if (get_time() - start_time > 50000) { - should_wait = false; - break; - } - } - if (should_wait) { - wait(0x100); - } - } - clkrst_disable(CARDEVICE_I2C1); -} - -static void enable_lp0_wake_events(void) { - wait(75); - APBDEV_PMC_CNTRL2_0 |= 0x200; /* Set WAKE_DET_EN. */ - wait(75); - APBDEV_PM_0 = 0xFFFFFFFF; /* Set all wake events. */ - APBDEV_PMC_WAKE2_STATUS_0 = 0xFFFFFFFF; /* Set all wake events. */ - wait(75); -} - -static void notify_pmic_shutdown(void) { - clkrst_reboot(CARDEVICE_I2C5); - if (fuse_get_bootrom_patch_version() >= 0x7F) { - i2c_send_pmic_cpu_shutdown_cmd(); - } -} - -static void mitigate_jamais_vu(void) { - /* Jamais Vu mitigation #1: Ensure all other cores are off. */ - if (APBDEV_PMC_PWRGATE_STATUS_0 & 0xE00) { - generic_panic(); - } - - /* For debugging, make this check always pass. */ - if ((exosphere_get_target_firmware() < EXOSPHERE_TARGET_FIRMWARE_400 || (get_debug_authentication_status() & 3) == 3)) { - FLOW_CTLR_HALT_COP_EVENTS_0 = 0x50000000; - } else { - FLOW_CTLR_HALT_COP_EVENTS_0 = 0x40000000; - } - - /* Jamais Vu mitigation #2: Ensure the BPMP is halted. */ - if (exosphere_get_target_firmware() < EXOSPHERE_TARGET_FIRMWARE_400 || (get_debug_authentication_status() & 3) == 3) { - /* BPMP should just be plainly halted, in debugging conditions. */ - if (FLOW_CTLR_HALT_COP_EVENTS_0 != 0x50000000) { - generic_panic(); - } - } else { - /* BPMP must be in never-woken-up halt mode, under normal conditions. */ - if (FLOW_CTLR_HALT_COP_EVENTS_0 != 0x40000000) { - generic_panic(); - } - } - - /* Jamais Vu mitigation #3: Ensure all relevant DMA controllers are held in reset. */ - if ((CLK_RST_CONTROLLER_RST_DEVICES_H_0 & 0x4000004) != 0x4000004) { - generic_panic(); - } -} - -static void configure_pmc_for_deep_powerdown(void) { - APBDEV_PMC_SCRATCH0_0 = 1; - APBDEV_PMC_DPD_ENABLE_0 |= 2; -} - -static void setup_bpmp_sc7_firmware(void) { - /* Mark PMC registers as not secure-world only, so BPMP can access them. */ - APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0 &= 0xFFFFDFFF; - - /* Setup BPMP vectors. */ - BPMP_VECTOR_RESET = 0x40003000; /* lp0_entry_firmware_crt0 */ - BPMP_VECTOR_UNDEF = 0x40003004; /* Reboot. */ - BPMP_VECTOR_SWI = 0x40003004; /* Reboot. */ - BPMP_VECTOR_PREFETCH_ABORT = 0x40003004; /* Reboot. */ - BPMP_VECTOR_DATA_ABORT = 0x40003004; /* Reboot. */ - BPMP_VECTOR_UNK = 0x40003004; /* Reboot. */ - BPMP_VECTOR_IRQ = 0x40003004; /* Reboot. */ - BPMP_VECTOR_FIQ = 0x40003004; /* Reboot. */ - - /* Hold the BPMP in reset. */ - MAKE_CAR_REG(0x300) = 2; - - /* Copy BPMP firmware. */ - uint8_t *lp0_entry_code = (uint8_t *)(LP0_ENTRY_GET_RAM_SEGMENT_ADDRESS(LP0_ENTRY_RAM_SEGMENT_ID_LP0_ENTRY_CODE)); - for (unsigned int i = 0; i < bpmpfw_bin_size; i += 4) { - write32le(lp0_entry_code, i, read32le(bpmpfw_bin, i)); - } - - flush_dcache_range(lp0_entry_code, lp0_entry_code + bpmpfw_bin_size); - - /* Take the BPMP out of reset. */ - MAKE_CAR_REG(0x304) = 2; - - /* Start executing BPMP firmware. */ - FLOW_CTLR_HALT_COP_EVENTS_0 = 0; -} - -static void configure_flow_regs_for_sleep(void) { - unsigned int current_core = get_core_id(); - flow_set_cc4_ctrl(current_core, 0); - flow_set_halt_events(current_core, false); - FLOW_CTLR_L2FLUSH_CONTROL_0 = 0; - flow_set_csr(current_core, 2); -} - -static void save_tzram_state(void) { - /* TODO: Remove set suspend call once exo warmboots fully */ - set_suspend_for_debug(); - uint32_t tzram_cmac[0x4] = {0}; - - uint8_t *tzram_encryption_dst = (uint8_t *)(LP0_ENTRY_GET_RAM_SEGMENT_ADDRESS(LP0_ENTRY_RAM_SEGMENT_ID_ENCRYPTED_TZRAM)); - uint8_t *tzram_encryption_src = (uint8_t *)(LP0_ENTRY_GET_RAM_SEGMENT_ADDRESS(LP0_ENTRY_RAM_SEGMENT_ID_CURRENT_TZRAM)); - if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_500) { - tzram_encryption_src += 0x2000ull; - } - uint8_t *tzram_store_address = (uint8_t *)(WARMBOOT_GET_RAM_SEGMENT_ADDRESS(WARMBOOT_RAM_SEGMENT_ID_TZRAM)); - clear_priv_smc_in_progress(); - - /* Flush cache. */ - flush_dcache_all(); - - /* Encrypt and save TZRAM into DRAM using a random aes-256 key. */ - se_generate_random_key(KEYSLOT_SWITCH_LP0TZRAMKEY, KEYSLOT_SWITCH_RNGKEY); - - flush_dcache_range(tzram_encryption_dst, tzram_encryption_dst + LP0_TZRAM_SAVE_SIZE); - flush_dcache_range(tzram_encryption_src, tzram_encryption_src + LP0_TZRAM_SAVE_SIZE); - - /* Use the all-zero cmac buffer as an IV. */ - se_aes_256_cbc_encrypt(KEYSLOT_SWITCH_LP0TZRAMKEY, tzram_encryption_dst, LP0_TZRAM_SAVE_SIZE, tzram_encryption_src, LP0_TZRAM_SAVE_SIZE, tzram_cmac); - flush_dcache_range(tzram_encryption_dst, tzram_encryption_dst + LP0_TZRAM_SAVE_SIZE); - - /* Copy encrypted TZRAM from IRAM to DRAM. */ - for (unsigned int i = 0; i < LP0_TZRAM_SAVE_SIZE; i += 4) { - write32le(tzram_store_address, i, read32le(tzram_encryption_dst, i)); - } - - flush_dcache_range(tzram_store_address, tzram_store_address + LP0_TZRAM_SAVE_SIZE); - - /* Compute CMAC. */ - se_compute_aes_256_cmac(KEYSLOT_SWITCH_LP0TZRAMKEY, tzram_cmac, sizeof(tzram_cmac), tzram_encryption_src, LP0_TZRAM_SAVE_SIZE); - - /* Write CMAC, lock registers. */ - APBDEV_PMC_SECURE_SCRATCH112_0 = tzram_cmac[0]; - APBDEV_PMC_SECURE_SCRATCH113_0 = tzram_cmac[1]; - APBDEV_PMC_SECURE_SCRATCH114_0 = tzram_cmac[2]; - APBDEV_PMC_SECURE_SCRATCH115_0 = tzram_cmac[3]; - APBDEV_PMC_SEC_DISABLE8_0 = 0x550000; - - /* Perform pre-2.0.0 PMC writes. */ - if (exosphere_get_target_firmware() < EXOSPHERE_TARGET_FIRMWARE_200) { - /* TODO: Give these writes appropriate defines in pmc.h */ - - /* Save Encrypted context location + lock scratch register. */ - MAKE_REG32(PMC_BASE + 0x360) = WARMBOOT_GET_RAM_SEGMENT_PA(WARMBOOT_RAM_SEGMENT_ID_TZRAM); - MAKE_REG32(PMC_BASE + 0x2D8) = 0x10000; - - /* Save Encryption parameters (where to copy TZRAM to, source, destination, size) */ - MAKE_REG32(PMC_BASE + 0x340) = LP0_ENTRY_GET_RAM_SEGMENT_PA(LP0_ENTRY_RAM_SEGMENT_ID_CURRENT_TZRAM); - MAKE_REG32(PMC_BASE + 0x344) = 0; - MAKE_REG32(PMC_BASE + 0x348) = LP0_ENTRY_GET_RAM_SEGMENT_PA(LP0_ENTRY_RAM_SEGMENT_ID_CURRENT_TZRAM); - MAKE_REG32(PMC_BASE + 0x34C) = 0; - MAKE_REG32(PMC_BASE + 0x350) = LP0_ENTRY_GET_RAM_SEGMENT_PA(LP0_ENTRY_RAM_SEGMENT_ID_CURRENT_TZRAM); - MAKE_REG32(PMC_BASE + 0x354) = LP0_TZRAM_SAVE_SIZE; - - /* Lock scratch registers. */ - MAKE_REG32(PMC_BASE + 0x2D8) = 0x555; - } -} - -static void save_se_state(void) { - /* Save security engine state. */ - uint8_t *se_state_dst = (uint8_t *)(WARMBOOT_GET_RAM_SEGMENT_ADDRESS(WARMBOOT_RAM_SEGMENT_ID_SE_STATE)); - se_check_error_status_reg(); - se_set_in_context_save_mode(true); - se_save_context(KEYSLOT_SWITCH_SRKGENKEY, KEYSLOT_SWITCH_RNGKEY, se_state_dst); - flush_dcache_range(se_state_dst, se_state_dst + 0x840); - APBDEV_PMC_SCRATCH43_0 = (uint32_t)(WARMBOOT_GET_RAM_SEGMENT_PA(WARMBOOT_RAM_SEGMENT_ID_SE_STATE)); - se_set_in_context_save_mode(false); - se_check_error_status_reg(); -} - -/* Save security engine, and go to sleep. */ -void save_se_and_power_down_cpu(void) { - /* Save context for warmboot to restore. */ - save_tzram_state(); - save_se_state(); - - /* Patch the bootrom to disable warmboot signature checks. */ - MAKE_REG32(PMC_BASE + 0x118) = 0x2202E012; - MAKE_REG32(PMC_BASE + 0x11C) = 0x6001DC28; - - if (!configitem_is_retail()) { - uart_send(UART_A, "OYASUMI", 8); - } - - finalize_powerdown(); -} - -uint32_t cpu_suspend(uint64_t power_state, uint64_t entrypoint, uint64_t argument) { - /* TODO: 6.0.0 introduces heavy deja vu mitigations. */ - /* Exosphere may want to implement these. */ - - /* Ensure SMC call is to enter deep sleep. */ - if ((power_state & 0x17FFF) != 0x1001B) { - return 0xFFFFFFFD; - } - - /* Perform I2C comms with TI charger if required. */ - configure_battery_hi_z_mode(); - - /* Enable LP0 Wake Event Detection. */ - enable_lp0_wake_events(); - - /* Alert the PMC of an iminent shutdown. */ - notify_pmic_shutdown(); - - /* Validate that the shutdown has correct context. */ - if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_200) { - mitigate_jamais_vu(); - } - - /* Signal to bootrom the next reset should be a warmboot. */ - configure_pmc_for_deep_powerdown(); - - /* Ensure that BPMP SC7 firmware is active. */ - if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_200) { - setup_bpmp_sc7_firmware(); - } - - /* Prepare the current core for sleep. */ - configure_flow_regs_for_sleep(); - - /* Save core context. */ - set_core_entrypoint_and_argument(get_core_id(), entrypoint, argument); - save_current_core_context(); - set_current_core_inactive(); - - /* Ensure that other cores are already asleep. */ - if (!(APBDEV_PMC_PWRGATE_STATUS_0 & 0xE00)) { - if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_200) { - call_with_stack_pointer(get_smc_core012_stack_address(), save_se_and_power_down_cpu); - } else { - save_se_and_power_down_cpu(); - } - } - - generic_panic(); -} diff --git a/exosphere/src/lp0.h b/exosphere/src/lp0.h deleted file mode 100644 index 2937898..0000000 --- a/exosphere/src/lp0.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 EXOSPHERE_LP0_H -#define EXOSPHERE_LP0_H - -#include - -/* Exosphere Deep Sleep Entry implementation. */ - -#define LP0_TZRAM_SAVE_SIZE 0xE000 - -uint32_t cpu_suspend(uint64_t power_state, uint64_t entrypoint, uint64_t argument); - -#endif \ No newline at end of file diff --git a/exosphere/src/sc7.c b/exosphere/src/sc7.c new file mode 100644 index 0000000..f168a89 --- /dev/null +++ b/exosphere/src/sc7.c @@ -0,0 +1,304 @@ +/* + * 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 "utils.h" + +#include "car.h" +#include "bpmp.h" +#include "arm.h" +#include "configitem.h" +#include "cpu_context.h" +#include "flow.h" +#include "fuse.h" +#include "i2c.h" +#include "sc7.h" +#include "masterkey.h" +#include "pmc.h" +#include "se.h" +#include "smc_api.h" +#include "timers.h" +#include "misc.h" +#include "uart.h" +#include "exocfg.h" + +#define u8 uint8_t +#define u32 uint32_t +#include "sc7fw_bin.h" +#undef u8 +#undef u32 + +static void configure_battery_hi_z_mode(void) { + clkrst_reboot(CARDEVICE_I2C1); + + if (configitem_should_profile_battery() && !i2c_query_ti_charger_bit_7()) { + /* Profile the battery. */ + i2c_set_ti_charger_bit_7(); + uint32_t start_time = get_time(); + bool should_wait = true; + /* TODO: This is GPIO-6 GPIO_IN_1 */ + while (MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_GPIO) + 0x634) & 1) { + if (get_time() - start_time > 50000) { + should_wait = false; + break; + } + } + if (should_wait) { + wait(0x100); + } + } + clkrst_disable(CARDEVICE_I2C1); +} + +static void enable_lp0_wake_events(void) { + wait(75); + APBDEV_PMC_CNTRL2_0 |= 0x200; /* Set WAKE_DET_EN. */ + wait(75); + APBDEV_PM_0 = 0xFFFFFFFF; /* Set all wake events. */ + APBDEV_PMC_WAKE2_STATUS_0 = 0xFFFFFFFF; /* Set all wake events. */ + wait(75); +} + +static void notify_pmic_shutdown(void) { + clkrst_reboot(CARDEVICE_I2C5); + if (fuse_get_bootrom_patch_version() >= 0x7F) { + i2c_send_pmic_cpu_shutdown_cmd(); + } +} + +static void mitigate_jamais_vu(void) { + /* Jamais Vu mitigation #1: Ensure all other cores are off. */ + if (APBDEV_PMC_PWRGATE_STATUS_0 & 0xE00) { + generic_panic(); + } + + /* For debugging, make this check always pass. */ + if ((exosphere_get_target_firmware() < EXOSPHERE_TARGET_FIRMWARE_400 || (get_debug_authentication_status() & 3) == 3)) { + FLOW_CTLR_HALT_COP_EVENTS_0 = 0x50000000; + } else { + FLOW_CTLR_HALT_COP_EVENTS_0 = 0x40000000; + } + + /* Jamais Vu mitigation #2: Ensure the BPMP is halted. */ + if (exosphere_get_target_firmware() < EXOSPHERE_TARGET_FIRMWARE_400 || (get_debug_authentication_status() & 3) == 3) { + /* BPMP should just be plainly halted, in debugging conditions. */ + if (FLOW_CTLR_HALT_COP_EVENTS_0 != 0x50000000) { + generic_panic(); + } + } else { + /* BPMP must be in never-woken-up halt mode, under normal conditions. */ + if (FLOW_CTLR_HALT_COP_EVENTS_0 != 0x40000000) { + generic_panic(); + } + } + + /* Jamais Vu mitigation #3: Ensure all relevant DMA controllers are held in reset. */ + if ((CLK_RST_CONTROLLER_RST_DEVICES_H_0 & 0x4000004) != 0x4000004) { + generic_panic(); + } +} + +static void configure_pmc_for_deep_powerdown(void) { + APBDEV_PMC_SCRATCH0_0 = 1; + APBDEV_PMC_DPD_ENABLE_0 |= 2; +} + +static void setup_bpmp_sc7_firmware(void) { + /* Mark PMC registers as not secure-world only, so BPMP can access them. */ + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0 &= 0xFFFFDFFF; + + /* Setup BPMP vectors. */ + BPMP_VECTOR_RESET = 0x40003000; /* lp0_entry_firmware_crt0 */ + BPMP_VECTOR_UNDEF = 0x40003004; /* Reboot. */ + BPMP_VECTOR_SWI = 0x40003004; /* Reboot. */ + BPMP_VECTOR_PREFETCH_ABORT = 0x40003004; /* Reboot. */ + BPMP_VECTOR_DATA_ABORT = 0x40003004; /* Reboot. */ + BPMP_VECTOR_UNK = 0x40003004; /* Reboot. */ + BPMP_VECTOR_IRQ = 0x40003004; /* Reboot. */ + BPMP_VECTOR_FIQ = 0x40003004; /* Reboot. */ + + /* Hold the BPMP in reset. */ + MAKE_CAR_REG(0x300) = 2; + + /* Copy BPMP firmware. */ + uint8_t *lp0_entry_code = (uint8_t *)(LP0_ENTRY_GET_RAM_SEGMENT_ADDRESS(LP0_ENTRY_RAM_SEGMENT_ID_LP0_ENTRY_CODE)); + for (unsigned int i = 0; i < sc7fw_bin_size; i += 4) { + write32le(lp0_entry_code, i, read32le(sc7fw_bin, i)); + } + + flush_dcache_range(lp0_entry_code, lp0_entry_code + sc7fw_bin_size); + + /* Take the BPMP out of reset. */ + MAKE_CAR_REG(0x304) = 2; + + /* Start executing BPMP firmware. */ + FLOW_CTLR_HALT_COP_EVENTS_0 = 0; +} + +static void configure_flow_regs_for_sleep(void) { + unsigned int current_core = get_core_id(); + flow_set_cc4_ctrl(current_core, 0); + flow_set_halt_events(current_core, false); + FLOW_CTLR_L2FLUSH_CONTROL_0 = 0; + flow_set_csr(current_core, 2); +} + +static void save_tzram_state(void) { + /* TODO: Remove set suspend call once exo warmboots fully */ + set_suspend_for_debug(); + uint32_t tzram_cmac[0x4] = {0}; + + uint8_t *tzram_encryption_dst = (uint8_t *)(LP0_ENTRY_GET_RAM_SEGMENT_ADDRESS(LP0_ENTRY_RAM_SEGMENT_ID_ENCRYPTED_TZRAM)); + uint8_t *tzram_encryption_src = (uint8_t *)(LP0_ENTRY_GET_RAM_SEGMENT_ADDRESS(LP0_ENTRY_RAM_SEGMENT_ID_CURRENT_TZRAM)); + if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_500) { + tzram_encryption_src += 0x2000ull; + } + uint8_t *tzram_store_address = (uint8_t *)(WARMBOOT_GET_RAM_SEGMENT_ADDRESS(WARMBOOT_RAM_SEGMENT_ID_TZRAM)); + clear_priv_smc_in_progress(); + + /* Flush cache. */ + flush_dcache_all(); + + /* Encrypt and save TZRAM into DRAM using a random aes-256 key. */ + se_generate_random_key(KEYSLOT_SWITCH_LP0TZRAMKEY, KEYSLOT_SWITCH_RNGKEY); + + flush_dcache_range(tzram_encryption_dst, tzram_encryption_dst + LP0_TZRAM_SAVE_SIZE); + flush_dcache_range(tzram_encryption_src, tzram_encryption_src + LP0_TZRAM_SAVE_SIZE); + + /* Use the all-zero cmac buffer as an IV. */ + se_aes_256_cbc_encrypt(KEYSLOT_SWITCH_LP0TZRAMKEY, tzram_encryption_dst, LP0_TZRAM_SAVE_SIZE, tzram_encryption_src, LP0_TZRAM_SAVE_SIZE, tzram_cmac); + flush_dcache_range(tzram_encryption_dst, tzram_encryption_dst + LP0_TZRAM_SAVE_SIZE); + + /* Copy encrypted TZRAM from IRAM to DRAM. */ + for (unsigned int i = 0; i < LP0_TZRAM_SAVE_SIZE; i += 4) { + write32le(tzram_store_address, i, read32le(tzram_encryption_dst, i)); + } + + flush_dcache_range(tzram_store_address, tzram_store_address + LP0_TZRAM_SAVE_SIZE); + + /* Compute CMAC. */ + se_compute_aes_256_cmac(KEYSLOT_SWITCH_LP0TZRAMKEY, tzram_cmac, sizeof(tzram_cmac), tzram_encryption_src, LP0_TZRAM_SAVE_SIZE); + + /* Write CMAC, lock registers. */ + APBDEV_PMC_SECURE_SCRATCH112_0 = tzram_cmac[0]; + APBDEV_PMC_SECURE_SCRATCH113_0 = tzram_cmac[1]; + APBDEV_PMC_SECURE_SCRATCH114_0 = tzram_cmac[2]; + APBDEV_PMC_SECURE_SCRATCH115_0 = tzram_cmac[3]; + APBDEV_PMC_SEC_DISABLE8_0 = 0x550000; + + /* Perform pre-2.0.0 PMC writes. */ + if (exosphere_get_target_firmware() < EXOSPHERE_TARGET_FIRMWARE_200) { + /* TODO: Give these writes appropriate defines in pmc.h */ + + /* Save Encrypted context location + lock scratch register. */ + MAKE_REG32(PMC_BASE + 0x360) = WARMBOOT_GET_RAM_SEGMENT_PA(WARMBOOT_RAM_SEGMENT_ID_TZRAM); + MAKE_REG32(PMC_BASE + 0x2D8) = 0x10000; + + /* Save Encryption parameters (where to copy TZRAM to, source, destination, size) */ + MAKE_REG32(PMC_BASE + 0x340) = LP0_ENTRY_GET_RAM_SEGMENT_PA(LP0_ENTRY_RAM_SEGMENT_ID_CURRENT_TZRAM); + MAKE_REG32(PMC_BASE + 0x344) = 0; + MAKE_REG32(PMC_BASE + 0x348) = LP0_ENTRY_GET_RAM_SEGMENT_PA(LP0_ENTRY_RAM_SEGMENT_ID_CURRENT_TZRAM); + MAKE_REG32(PMC_BASE + 0x34C) = 0; + MAKE_REG32(PMC_BASE + 0x350) = LP0_ENTRY_GET_RAM_SEGMENT_PA(LP0_ENTRY_RAM_SEGMENT_ID_CURRENT_TZRAM); + MAKE_REG32(PMC_BASE + 0x354) = LP0_TZRAM_SAVE_SIZE; + + /* Lock scratch registers. */ + MAKE_REG32(PMC_BASE + 0x2D8) = 0x555; + } +} + +static void save_se_state(void) { + /* Save security engine state. */ + uint8_t *se_state_dst = (uint8_t *)(WARMBOOT_GET_RAM_SEGMENT_ADDRESS(WARMBOOT_RAM_SEGMENT_ID_SE_STATE)); + se_check_error_status_reg(); + se_set_in_context_save_mode(true); + se_save_context(KEYSLOT_SWITCH_SRKGENKEY, KEYSLOT_SWITCH_RNGKEY, se_state_dst); + flush_dcache_range(se_state_dst, se_state_dst + 0x840); + APBDEV_PMC_SCRATCH43_0 = (uint32_t)(WARMBOOT_GET_RAM_SEGMENT_PA(WARMBOOT_RAM_SEGMENT_ID_SE_STATE)); + se_set_in_context_save_mode(false); + se_check_error_status_reg(); +} + +/* Save security engine, and go to sleep. */ +void save_se_and_power_down_cpu(void) { + /* Save context for warmboot to restore. */ + save_tzram_state(); + save_se_state(); + + /* Patch the bootrom to disable warmboot signature checks. */ + MAKE_REG32(PMC_BASE + 0x118) = 0x2202E012; + MAKE_REG32(PMC_BASE + 0x11C) = 0x6001DC28; + + if (!configitem_is_retail()) { + uart_send(UART_A, "OYASUMI", 8); + } + + finalize_powerdown(); +} + +uint32_t cpu_suspend(uint64_t power_state, uint64_t entrypoint, uint64_t argument) { + /* TODO: 6.0.0 introduces heavy deja vu mitigations. */ + /* Exosphere may want to implement these. */ + + /* Ensure SMC call is to enter deep sleep. */ + if ((power_state & 0x17FFF) != 0x1001B) { + return 0xFFFFFFFD; + } + + /* Perform I2C comms with TI charger if required. */ + configure_battery_hi_z_mode(); + + /* Enable LP0 Wake Event Detection. */ + enable_lp0_wake_events(); + + /* Alert the PMC of an iminent shutdown. */ + notify_pmic_shutdown(); + + /* Validate that the shutdown has correct context. */ + if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_200) { + mitigate_jamais_vu(); + } + + /* Signal to bootrom the next reset should be a warmboot. */ + configure_pmc_for_deep_powerdown(); + + /* Ensure that BPMP SC7 firmware is active. */ + if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_200) { + setup_bpmp_sc7_firmware(); + } + + /* Prepare the current core for sleep. */ + configure_flow_regs_for_sleep(); + + /* Save core context. */ + set_core_entrypoint_and_argument(get_core_id(), entrypoint, argument); + save_current_core_context(); + set_current_core_inactive(); + + /* Ensure that other cores are already asleep. */ + if (!(APBDEV_PMC_PWRGATE_STATUS_0 & 0xE00)) { + if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_200) { + call_with_stack_pointer(get_smc_core012_stack_address(), save_se_and_power_down_cpu); + } else { + save_se_and_power_down_cpu(); + } + } + + generic_panic(); +} diff --git a/exosphere/src/sc7.h b/exosphere/src/sc7.h new file mode 100644 index 0000000..c5612da --- /dev/null +++ b/exosphere/src/sc7.h @@ -0,0 +1,28 @@ +/* + * 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 EXOSPHERE_SC7_H +#define EXOSPHERE_SC7_H + +#include + +/* Exosphere Deep Sleep Entry implementation. */ + +#define LP0_TZRAM_SAVE_SIZE 0xE000 + +uint32_t cpu_suspend(uint64_t power_state, uint64_t entrypoint, uint64_t argument); + +#endif \ No newline at end of file diff --git a/exosphere/src/smc_api.c b/exosphere/src/smc_api.c index 902dd20..336f593 100644 --- a/exosphere/src/smc_api.c +++ b/exosphere/src/smc_api.c @@ -34,7 +34,7 @@ #include "se.h" #include "userpage.h" #include "titlekey.h" -#include "lp0.h" +#include "sc7.h" #include "exocfg.h" #define SMC_USER_HANDLERS 0x13