Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff9671c481 | ||
|
|
da1bb77d8e | ||
|
|
14c50ed7f8 | ||
|
|
61401d733e | ||
|
|
be09b68532 | ||
|
|
50eff41351 | ||
|
|
4b78198f33 | ||
|
|
dfb5640bfe | ||
|
|
f139f9c56f | ||
|
|
4f4df9ccd1 | ||
|
|
bafc6f4a1d | ||
|
|
b1110caed1 | ||
|
|
e7f72b711a | ||
|
|
0ddc1c71a8 | ||
|
|
4e7c39d6a0 | ||
|
|
72a81e7c2a | ||
|
|
2e9a89aa20 | ||
|
|
ca68818efe | ||
|
|
3b9bf65071 | ||
|
|
50d4cbbda1 | ||
|
|
f911fab9f2 | ||
|
|
aae7689bf5 | ||
|
|
7d908c9ac5 | ||
|
|
2fb37db707 | ||
|
|
c8052e5b50 | ||
|
|
de830df7e7 | ||
|
|
04907e2823 | ||
|
|
4f5fcf9fbd | ||
|
|
ec890c7c97 | ||
|
|
4f2bbbf101 | ||
|
|
b677d6cad3 | ||
|
|
b3f8961e45 | ||
|
|
2f37811aba | ||
|
|
5cd596e53c | ||
|
|
4ae42c3a9d | ||
|
|
e105634b0d | ||
|
|
4781dc2ab4 | ||
|
|
e779e53406 | ||
|
|
9f5b97620a | ||
|
|
98d715243a | ||
|
|
e809745120 | ||
|
|
0d9aebda7b | ||
|
|
5ed875ce90 | ||
|
|
30d3c76655 | ||
|
|
949a034500 | ||
|
|
b2893d7fb6 | ||
|
|
9a3fdd944e | ||
|
|
8b8f3c564c | ||
|
|
cd1bb96241 | ||
|
|
8b59ddf3a8 | ||
|
|
09bfed9146 | ||
|
|
cbe75d7769 | ||
|
|
dad380344f | ||
|
|
71b0975730 | ||
|
|
20040ae70f | ||
|
|
22e179d1cf | ||
|
|
1b075c91bd | ||
|
|
1ac7f61f49 | ||
|
|
4b3599b2d8 | ||
|
|
ceabbb0be0 | ||
|
|
471c1e514c | ||
|
|
267a04c4ac | ||
|
|
4eb5b5f91b | ||
|
|
cfef8b4f72 | ||
|
|
683ca6af1d | ||
|
|
14cdcc1497 | ||
|
|
ec1bb508b3 | ||
|
|
cae9044c17 | ||
|
|
5674dad1e9 | ||
|
|
288b5c08db |
121
Makefile
121
Makefile
@@ -4,91 +4,106 @@ endif
|
||||
|
||||
include $(DEVKITARM)/base_rules
|
||||
|
||||
TARGET := hekate
|
||||
################################################################################
|
||||
|
||||
IPL_LOAD_ADDR := 0x40008000
|
||||
IPL_MAGIC := 0x43544349 #"ICTC"
|
||||
BLVERSION_MAJOR := 4
|
||||
BLVERSION_MINOR := 2
|
||||
BUILD := build
|
||||
OUTPUT := output
|
||||
BLVERSION_MINOR := 9
|
||||
BLVERSION_HOTFX := 1
|
||||
|
||||
BL_RESERVED := 0
|
||||
|
||||
################################################################################
|
||||
|
||||
TARGET := hekate
|
||||
BUILDDIR := build
|
||||
OUTPUTDIR := output
|
||||
SOURCEDIR = bootloader
|
||||
VPATH = $(dir $(wildcard ./$(SOURCEDIR)/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/))
|
||||
|
||||
OBJS = $(addprefix $(BUILD)/$(TARGET)/, \
|
||||
# Main and graphics.
|
||||
OBJS = $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||
start.o \
|
||||
main.o \
|
||||
config.o \
|
||||
btn.o \
|
||||
clock.o \
|
||||
cluster.o \
|
||||
fuse.o \
|
||||
gpio.o \
|
||||
heap.o \
|
||||
hos.o \
|
||||
i2c.o \
|
||||
kfuse.o \
|
||||
bq24193.o \
|
||||
max7762x.o \
|
||||
max17050.o \
|
||||
mc.o \
|
||||
nx_emmc.o \
|
||||
sdmmc.o \
|
||||
sdmmc_driver.o \
|
||||
sdram.o \
|
||||
tui.o \
|
||||
util.o \
|
||||
di.o \
|
||||
gfx.o \
|
||||
pinmux.o \
|
||||
pkg1.o \
|
||||
pkg2.o \
|
||||
se.o \
|
||||
tsec.o \
|
||||
uart.o \
|
||||
dirlist.o \
|
||||
ini.o \
|
||||
ianos.o \
|
||||
main.o heap.o \
|
||||
gfx.o tui.o \
|
||||
fe_emmc_tools.o fe_info.o fe_tools.o \
|
||||
)
|
||||
|
||||
OBJS += $(addprefix $(BUILD)/$(TARGET)/, \
|
||||
# Hardware.
|
||||
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||
clock.o cluster.o di.o gpio.o i2c.o mc.o sdram.o pinmux.o se.o smmu.o tsec.o uart.o \
|
||||
fuse.o kfuse.o \
|
||||
sdmmc.o sdmmc_driver.o \
|
||||
bq24193.o max17050.o max7762x.o max77620-rtc.o \
|
||||
hw_init.o \
|
||||
)
|
||||
|
||||
# Utilities.
|
||||
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||
btn.o dirlist.o ianos.o util.o \
|
||||
config.o ini.o \
|
||||
)
|
||||
|
||||
# Horizon.
|
||||
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||
nx_emmc.o \
|
||||
hos.o hos_config.o pkg1.o pkg2.o fss.o secmon_exo.o sept.o \
|
||||
)
|
||||
|
||||
# Libraries.
|
||||
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||
lz.o blz.o \
|
||||
diskio.o ff.o ffunicode.o ffsystem.o \
|
||||
elfload.o elfreloc_arm.o \
|
||||
)
|
||||
|
||||
################################################################################
|
||||
|
||||
CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR) -DBL_MAGIC=$(IPL_MAGIC)
|
||||
CUSTOMDEFINES += -DBL_VER_MJ=$(BLVERSION_MAJOR) -DBL_VER_MN=$(BLVERSION_MINOR) -DBL_VER_HF=$(BLVERSION_HOTFX) -DBL_RESERVED=$(BL_RESERVED)
|
||||
CUSTOMDEFINES += -DMENU_LOGO_ENABLE
|
||||
|
||||
# 0: UART_A, 1: UART_B.
|
||||
#CUSTOMDEFINES += -DDEBUG_UART_PORT=0
|
||||
|
||||
#CUSTOMDEFINES += -DDEBUG
|
||||
|
||||
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork
|
||||
CUSTOMDEFINES := -DBLVERSIONMJ=$(BLVERSION_MAJOR) -DBLVERSIONMN=$(BLVERSION_MINOR)
|
||||
CUSTOMDEFINES += -DMENU_LOGO_ENABLE #-DDEBUG
|
||||
CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 -Wall $(CUSTOMDEFINES)
|
||||
LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections
|
||||
LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=IPL_LOAD_ADDR=$(IPL_LOAD_ADDR)
|
||||
|
||||
MODULEDIRS := $(wildcard modules/*)
|
||||
|
||||
################################################################################
|
||||
|
||||
.PHONY: all clean $(MODULEDIRS)
|
||||
|
||||
all: $(TARGET).bin
|
||||
@echo -n "Payload size is "
|
||||
@wc -c < $(OUTPUT)/$(TARGET).bin
|
||||
@wc -c < $(OUTPUTDIR)/$(TARGET).bin
|
||||
@echo "Max size is 126296 Bytes."
|
||||
|
||||
clean:
|
||||
@rm -rf $(OBJS)
|
||||
@rm -rf $(BUILD)
|
||||
@rm -rf $(OUTPUT)
|
||||
@rm -rf $(BUILDDIR)
|
||||
@rm -rf $(OUTPUTDIR)
|
||||
|
||||
$(MODULEDIRS):
|
||||
$(MAKE) -C $@ $(MAKECMDGOALS)
|
||||
|
||||
$(TARGET).bin: $(BUILD)/$(TARGET)/$(TARGET).elf $(MODULEDIRS)
|
||||
$(OBJCOPY) -S -O binary $< $(OUTPUT)/$@
|
||||
@printf ICTC$(BLVERSION_MAJOR)$(BLVERSION_MINOR) >> $(OUTPUT)/$@
|
||||
$(TARGET).bin: $(BUILDDIR)/$(TARGET)/$(TARGET).elf $(MODULEDIRS)
|
||||
$(OBJCOPY) -S -O binary $< $(OUTPUTDIR)/$@
|
||||
@printf ICTC$(BLVERSION_MAJOR)$(BLVERSION_MINOR) >> $(OUTPUTDIR)/$@
|
||||
|
||||
$(BUILD)/$(TARGET)/$(TARGET).elf: $(OBJS)
|
||||
$(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS)
|
||||
$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@
|
||||
|
||||
$(BUILD)/$(TARGET)/%.o: %.c
|
||||
$(BUILDDIR)/$(TARGET)/%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(BUILD)/$(TARGET)/%.o: %.S
|
||||
@mkdir -p "$(BUILD)"
|
||||
@mkdir -p "$(BUILD)/$(TARGET)"
|
||||
@mkdir -p "$(OUTPUT)"
|
||||
$(BUILDDIR)/$(TARGET)/%.o: %.S
|
||||
@mkdir -p "$(BUILDDIR)"
|
||||
@mkdir -p "$(BUILDDIR)/$(TARGET)"
|
||||
@mkdir -p "$(OUTPUTDIR)"
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
34
README.md
34
README.md
@@ -20,6 +20,8 @@ Custom Nintendo Switch bootloader, firmware patcher, and more.
|
||||
| bootloader/payloads/ | For payloads. 'Payloads...' menu. Autoboot only supported by including them into an ini. All CFW bootloaders, tools, Linux payloads are supported. |
|
||||
| bootloader/libtools/ | Future reserved |
|
||||
|
||||
**Note**: Sept files for booting 7.0.0 and up are expected at /sept folder at root of sd card.
|
||||
|
||||
|
||||
## Bootloader configuration
|
||||
|
||||
@@ -29,15 +31,15 @@ The bootloader can be configured via 'bootloader/hekate_ipl.ini' (if it is prese
|
||||
There are four possible type of entries. "**[ ]**": Boot entry, "**{ }**": Caption, "**#**": Comment, "*newline*": .ini cosmetic newline.
|
||||
|
||||
|
||||
### Configuration keys/values when boot entry is **config**:
|
||||
### Global Configuration keys/values when boot entry is **config**:
|
||||
|
||||
| Config option | Description |
|
||||
| ------------------ | ---------------------------------------------------------- |
|
||||
| autoboot=0 | 0: Disable, #: Boot entry number to auto boot. |
|
||||
| bootwait=3 | 0: Disable (It also disables bootlogo. Having **VOL-** pressed since injection goes to menu.), #: Time to wait for **VOL-** to enter menu. |
|
||||
| customlogo=0 | 0: Use default hekate bootlogo, 1: Use bootlogo.bmp. |
|
||||
| verification=2 | 0: Disable Backup/Restore verification, 1: Sparse (block based, fast and not 100% reliable), 2: Full (sha256 based, slow and 100% reliable). |
|
||||
| autohosoff=1 | If woke up from HOS via an rtc alarm, power off completely.|
|
||||
| autohosoff=1 | 0: Disable, 1: If woke up from HOS via an RTC alarm, shows logo, then powers off completely, 2: No logo, immediately powers off.|
|
||||
| autonogc=1 | 0: Disable, 1: Automatically applies nogc patch if unburnt fuses found and a >= 4.0.0 HOS is booted. |
|
||||
| backlight=100 | Screen backlight level. 0-255. |
|
||||
|
||||
|
||||
@@ -51,12 +53,34 @@ There are four possible type of entries. "**[ ]**": Boot entry, "**{ }**": Capti
|
||||
| kernel={SD path} | Replaces the kernel binary |
|
||||
| kip1={SD path} | Replaces/Adds kernel initial process. Multiple can be set. |
|
||||
| kip1={SD folder}/* | Loads every .kip/.kip1 inside a folder. Compatible with single kip1 keys. |
|
||||
| kip1patch=patchname| Enables a kip1 patch. Specify with multiple lines and/or as CSV. Implemented patches right now are nosigchk,nogc |
|
||||
| fss0={SD path} | Takes a fusee-secondary binary and extracts all needed parts from it. |
|
||||
| kip1patch=patchname| Enables a kip1 patch. Specify with multiple lines and/or as CSV. Current available patches nosigchk. |
|
||||
| fullsvcperm=1 | Disables SVC verification (full services permission) |
|
||||
| debugmode=1 | Enables Debug mode |
|
||||
| debugmode=1 | Enables Debug mode. Obsolete when used with exosphere as secmon. |
|
||||
| atmosphere=1 | Enables Atmosphère patching |
|
||||
| stock=1 | Disables unneeded kernel patching when running stock or semi-stock. |
|
||||
| payload={SD path} | Payload launching. Tools, Linux, CFW bootloaders, etc. |
|
||||
|
||||
**Note1**: When using the wildcard (`/*`) with `kip1` you can still use the normal `kip1` after that to load extra signle kips.
|
||||
|
||||
**Note2**: When using FSS0 it parses exosphere, warmboot and all core kips. You can override the first 2 by using `secmon`/`warmboot` after defining `fss0`.
|
||||
You can define `kip1` to load an extra kip or many via the wildcard (`/*`) usage.
|
||||
|
||||
**Warning**: Never define core kips when using `fss0` and make sure that the folder (when using `/*`), does not include them.
|
||||
|
||||
|
||||
### Payload storage:
|
||||
|
||||
Hekate now has a new storage in the binary that helps it configure it outside of BPMP enviroment:
|
||||
|
||||
| Offset / Name | Description |
|
||||
| -------------------- | ----------------------------------------------------------------- |
|
||||
| '0x94' boot_cfg | bit0: Force AutoBoot, bit1: Show launch log, bit2: sept run. |
|
||||
| '0x98' autoboot | If `Force AutoBoot`: 0: Force go to menu, else boot that entry. |
|
||||
| '0x9C' autoboot_list | If `Force AutoBoot` and `autoboot` then it boots from ini folder. |
|
||||
| '0xA0' extra_cfg | Reserved. |
|
||||
| '0xA4' rsvd[128] | Reserved. |
|
||||
|
||||
|
||||
You can find a template [Here](./res/hekate_ipl_template.ini)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018 CTCaer
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -17,20 +17,15 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../utils/btn.h"
|
||||
#include "config.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "ini.h"
|
||||
#include "../utils/list.h"
|
||||
#include "../gfx/tui.h"
|
||||
#include "../utils/util.h"
|
||||
#include "../gfx/gfx.h"
|
||||
|
||||
extern gfx_ctxt_t gfx_ctxt;
|
||||
extern gfx_con_t gfx_con;
|
||||
//TODO: Create more macros (info, header, debug, etc) with different colors and utilize them for consistency.
|
||||
#define EPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
|
||||
#define EPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
|
||||
#include "../gfx/tui.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../utils/btn.h"
|
||||
#include "../utils/list.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
extern hekate_config h_cfg;
|
||||
extern int sd_mount();
|
||||
@@ -41,13 +36,14 @@ void set_default_configuration()
|
||||
h_cfg.autoboot = 0;
|
||||
h_cfg.autoboot_list = 0;
|
||||
h_cfg.bootwait = 3;
|
||||
h_cfg.customlogo = 0;
|
||||
h_cfg.verification = 2;
|
||||
h_cfg.verification = 1;
|
||||
h_cfg.se_keygen_done = 0;
|
||||
h_cfg.sbar_time_keeping = 0;
|
||||
h_cfg.backlight = 100;
|
||||
h_cfg.autohosoff = 1;
|
||||
h_cfg.autohosoff = 0;
|
||||
h_cfg.errors = 0;
|
||||
h_cfg.autonogc = 1;
|
||||
h_cfg.sept_run = EMC(EMC_SCRATCH0) & EMC_SEPT_RUN;
|
||||
}
|
||||
|
||||
int create_config_entry()
|
||||
@@ -93,9 +89,6 @@ int create_config_entry()
|
||||
f_puts("\nbootwait=", &fp);
|
||||
itoa(h_cfg.bootwait, lbuf, 10);
|
||||
f_puts(lbuf, &fp);
|
||||
f_puts("\ncustomlogo=", &fp);
|
||||
itoa(h_cfg.customlogo, lbuf, 10);
|
||||
f_puts(lbuf, &fp);
|
||||
f_puts("\nverification=", &fp);
|
||||
itoa(h_cfg.verification, lbuf, 10);
|
||||
f_puts(lbuf, &fp);
|
||||
@@ -105,6 +98,9 @@ int create_config_entry()
|
||||
f_puts("\nautohosoff=", &fp);
|
||||
itoa(h_cfg.autohosoff, lbuf, 10);
|
||||
f_puts(lbuf, &fp);
|
||||
f_puts("\nautonogc=", &fp);
|
||||
itoa(h_cfg.autonogc, lbuf, 10);
|
||||
f_puts(lbuf, &fp);
|
||||
f_puts("\n", &fp);
|
||||
|
||||
if (mainIniFound)
|
||||
@@ -156,7 +152,19 @@ int create_config_entry()
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _config_autoboot_list()
|
||||
static void _save_config()
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
if (!create_config_entry())
|
||||
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
|
||||
else
|
||||
EPRINTF("\nConfiguration saving failed!");
|
||||
gfx_puts(&gfx_con, "\nPress any key...");
|
||||
}
|
||||
|
||||
static void _config_autoboot_list(void *ent)
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
@@ -216,28 +224,23 @@ void _config_autoboot_list()
|
||||
}
|
||||
|
||||
memset(&ments[i], 0, sizeof(ment_t));
|
||||
menu_t menu = {ments, "Select a list entry to auto boot", 0, 0};
|
||||
menu_t menu = {ments, "Select an entry to auto boot", 0, 0};
|
||||
temp_autoboot = (u32 *)tui_do_menu(&gfx_con, &menu);
|
||||
if (temp_autoboot != NULL)
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
h_cfg.autoboot = *(u32 *)temp_autoboot;
|
||||
h_cfg.autoboot_list = 1;
|
||||
// Save choice to ini file.
|
||||
if (!create_config_entry())
|
||||
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
|
||||
else
|
||||
EPRINTF("\nConfiguration saving failed!");
|
||||
gfx_puts(&gfx_con, "\nPress any key...");
|
||||
_save_config();
|
||||
|
||||
ment_t *tmp = (ment_t *)ent;
|
||||
tmp->data = NULL;
|
||||
}
|
||||
else
|
||||
goto out2;
|
||||
}
|
||||
else
|
||||
{
|
||||
EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists in SD Card!.");
|
||||
EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists!.");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -251,9 +254,6 @@ out2:;
|
||||
ini_free(&ini_sections);
|
||||
|
||||
sd_unmount();
|
||||
|
||||
if (temp_autoboot == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
void config_autoboot()
|
||||
@@ -291,13 +291,13 @@ void config_autoboot()
|
||||
ments[2].caption = " Disable";
|
||||
ments[2].data = &boot_values[0];
|
||||
|
||||
ments[3].type = MENT_HANDLER;
|
||||
ments[3].type = MENT_HDLR_RE;
|
||||
if (h_cfg.autoboot_list)
|
||||
ments[3].caption = "*More configs...";
|
||||
else
|
||||
ments[3].caption = " More configs...";
|
||||
ments[3].handler = _config_autoboot_list;
|
||||
ments[3].data = NULL;
|
||||
ments[3].data = (void *)0xCAFE;
|
||||
|
||||
ments[4].type = MENT_CHGLINE;
|
||||
|
||||
@@ -344,24 +344,16 @@ void config_autoboot()
|
||||
temp_autoboot = (u32 *)tui_do_menu(&gfx_con, &menu);
|
||||
if (temp_autoboot != NULL)
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
h_cfg.autoboot = *(u32 *)temp_autoboot;
|
||||
h_cfg.autoboot_list = 0;
|
||||
// Save choice to ini file.
|
||||
if (!create_config_entry())
|
||||
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
|
||||
else
|
||||
EPRINTF("\nConfiguration saving failed!");
|
||||
gfx_puts(&gfx_con, "\nPress any key...");
|
||||
_save_config();
|
||||
}
|
||||
else
|
||||
goto out2;
|
||||
}
|
||||
else
|
||||
{
|
||||
EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists in SD Card!.");
|
||||
EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists!.");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -427,16 +419,8 @@ void config_bootdelay()
|
||||
u32 *temp_bootwait = (u32 *)tui_do_menu(&gfx_con, &menu);
|
||||
if (temp_bootwait != NULL)
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
h_cfg.bootwait = *(u32 *)temp_bootwait;
|
||||
// Save choice to ini file.
|
||||
if (!create_config_entry())
|
||||
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
|
||||
else
|
||||
EPRINTF("\nConfiguration saving failed!");
|
||||
gfx_puts(&gfx_con, "\nPress any key...");
|
||||
_save_config();
|
||||
}
|
||||
|
||||
free(ments);
|
||||
@@ -448,64 +432,6 @@ void config_bootdelay()
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void config_customlogo()
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 5);
|
||||
u32 *cb_values = (u32 *)malloc(sizeof(u32) * 2);
|
||||
|
||||
for (u32 j = 0; j < 2; j++)
|
||||
{
|
||||
cb_values[j] = j;
|
||||
ments[j + 2].type = MENT_DATA;
|
||||
ments[j + 2].data = &cb_values[j];
|
||||
}
|
||||
|
||||
ments[0].type = MENT_BACK;
|
||||
ments[0].caption = "Back";
|
||||
|
||||
ments[1].type = MENT_CHGLINE;
|
||||
|
||||
if (h_cfg.customlogo)
|
||||
{
|
||||
ments[2].caption = " Disable";
|
||||
ments[3].caption = "*Enable";
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
ments[2].caption = "*Disable";
|
||||
ments[3].caption = " Enable";
|
||||
}
|
||||
|
||||
memset(&ments[4], 0, sizeof(ment_t));
|
||||
menu_t menu = {ments, "Custom bootlogo", 0, 0};
|
||||
|
||||
u32 *temp_customlogo = (u32 *)tui_do_menu(&gfx_con, &menu);
|
||||
if (temp_customlogo != NULL)
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
h_cfg.customlogo = *(u32 *)temp_customlogo;
|
||||
// Save choice to ini file.
|
||||
if (!create_config_entry())
|
||||
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
|
||||
else
|
||||
EPRINTF("\nConfiguration saving failed!");
|
||||
gfx_puts(&gfx_con, "\nPress any key...");
|
||||
}
|
||||
|
||||
free(ments);
|
||||
free(cb_values);
|
||||
|
||||
if (temp_customlogo == NULL)
|
||||
return;
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void config_verification()
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
@@ -527,22 +453,17 @@ void config_verification()
|
||||
|
||||
ments[1].type = MENT_CHGLINE;
|
||||
|
||||
memcpy(vr_text, " Disable (Fastest)", 19);
|
||||
memcpy(vr_text + 64, " Sparse (Fast - Not reliable)", 32);
|
||||
memcpy(vr_text + 128, " Full (Slow - 100% reliable)", 32);
|
||||
memcpy(vr_text, " Disable (Fastest - Unsafe)", 28);
|
||||
memcpy(vr_text + 64, " Sparse (Fast - Safe)", 23);
|
||||
memcpy(vr_text + 128, " Full (Slow - Safe)", 23);
|
||||
|
||||
for (u32 i = 0; i < 3; i++)
|
||||
{
|
||||
if (h_cfg.verification != i)
|
||||
{
|
||||
vr_text[64 * i] = ' ';
|
||||
ments[2 + i].caption = vr_text + (i * 64);
|
||||
}
|
||||
else
|
||||
{
|
||||
vr_text[64 * i] = '*';
|
||||
ments[2 + i].caption = vr_text + (i * 64);
|
||||
}
|
||||
ments[2 + i].caption = vr_text + (i * 64);
|
||||
}
|
||||
|
||||
memset(&ments[5], 0, sizeof(ment_t));
|
||||
@@ -551,16 +472,8 @@ void config_verification()
|
||||
u32 *temp_verification = (u32 *)tui_do_menu(&gfx_con, &menu);
|
||||
if (temp_verification != NULL)
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
h_cfg.verification = *(u32 *)temp_verification;
|
||||
// Save choice to ini file.
|
||||
if (!create_config_entry())
|
||||
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
|
||||
else
|
||||
EPRINTF("\nConfiguration saving failed!");
|
||||
gfx_puts(&gfx_con, "\nPress any key...");
|
||||
_save_config();
|
||||
}
|
||||
|
||||
free(ments);
|
||||
@@ -604,7 +517,6 @@ void config_backlight()
|
||||
bri_text[i * 32 + 1] = i + '0';
|
||||
memcpy(bri_text + i * 32 + 2, "0%", 3);
|
||||
}
|
||||
|
||||
else
|
||||
memcpy(bri_text + i * 32 + 1, "100%", 5);
|
||||
|
||||
@@ -619,16 +531,8 @@ void config_backlight()
|
||||
u32 *temp_backlight = (u32 *)tui_do_menu(&gfx_con, &menu);
|
||||
if (temp_backlight != NULL)
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
h_cfg.backlight = (*(u32 *)temp_backlight) * 2;
|
||||
//Save choice to ini file.
|
||||
if (!create_config_entry())
|
||||
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
|
||||
else
|
||||
EPRINTF("\nConfiguration saving failed!");
|
||||
gfx_puts(&gfx_con, "\nPress any key...");
|
||||
_save_config();
|
||||
}
|
||||
|
||||
free(ments);
|
||||
@@ -645,10 +549,10 @@ void config_auto_hos_poweroff()
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 5);
|
||||
u32 *hp_values = (u32 *)malloc(sizeof(u32) * 2);
|
||||
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6);
|
||||
u32 *hp_values = (u32 *)malloc(sizeof(u32) * 3);
|
||||
|
||||
for (u32 j = 0; j < 2; j++)
|
||||
for (u32 j = 0; j < 3; j++)
|
||||
{
|
||||
hp_values[j] = j;
|
||||
ments[j + 2].type = MENT_DATA;
|
||||
@@ -660,34 +564,33 @@ void config_auto_hos_poweroff()
|
||||
|
||||
ments[1].type = MENT_CHGLINE;
|
||||
|
||||
if (h_cfg.autohosoff)
|
||||
if (h_cfg.autohosoff == 1)
|
||||
{
|
||||
ments[2].caption = " Disable";
|
||||
ments[3].caption = "*Enable";
|
||||
|
||||
ments[4].caption = " Enable (No logo)";
|
||||
}
|
||||
else if (h_cfg.autohosoff >= 2)
|
||||
{
|
||||
ments[2].caption = " Disable";
|
||||
ments[3].caption = " Enable";
|
||||
ments[4].caption = "*Enable (No logo)";
|
||||
}
|
||||
else
|
||||
{
|
||||
ments[2].caption = "*Disable";
|
||||
ments[3].caption = " Enable";
|
||||
ments[4].caption = " Enable (No logo)";
|
||||
}
|
||||
|
||||
memset(&ments[4], 0, sizeof(ment_t));
|
||||
memset(&ments[5], 0, sizeof(ment_t));
|
||||
menu_t menu = {ments, "Power off if woke up from HOS", 0, 0};
|
||||
|
||||
u32 *temp_autohosoff = (u32 *)tui_do_menu(&gfx_con, &menu);
|
||||
if (temp_autohosoff != NULL)
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
h_cfg.autohosoff = *(u32 *)temp_autohosoff;
|
||||
// Save choice to ini file.
|
||||
if (!create_config_entry())
|
||||
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
|
||||
else
|
||||
EPRINTF("\nConfiguration saving failed!");
|
||||
gfx_puts(&gfx_con, "\nPress any key...");
|
||||
_save_config();
|
||||
}
|
||||
|
||||
free(ments);
|
||||
@@ -697,3 +600,52 @@ void config_auto_hos_poweroff()
|
||||
return;
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void config_nogc()
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 5);
|
||||
u32 *cb_values = (u32 *)malloc(sizeof(u32) * 2);
|
||||
|
||||
for (u32 j = 0; j < 2; j++)
|
||||
{
|
||||
cb_values[j] = j;
|
||||
ments[j + 2].type = MENT_DATA;
|
||||
ments[j + 2].data = &cb_values[j];
|
||||
}
|
||||
|
||||
ments[0].type = MENT_BACK;
|
||||
ments[0].caption = "Back";
|
||||
|
||||
ments[1].type = MENT_CHGLINE;
|
||||
|
||||
if (h_cfg.autonogc)
|
||||
{
|
||||
ments[2].caption = " Disable";
|
||||
ments[3].caption = "*Auto";
|
||||
}
|
||||
else
|
||||
{
|
||||
ments[2].caption = "*Disable";
|
||||
ments[3].caption = " Auto";
|
||||
}
|
||||
|
||||
memset(&ments[4], 0, sizeof(ment_t));
|
||||
menu_t menu = {ments, "No Gamecard", 0, 0};
|
||||
|
||||
u32 *temp_nogc = (u32 *)tui_do_menu(&gfx_con, &menu);
|
||||
if (temp_nogc != NULL)
|
||||
{
|
||||
h_cfg.autonogc = *(u32 *)temp_nogc;
|
||||
_save_config();
|
||||
}
|
||||
|
||||
free(ments);
|
||||
free(cb_values);
|
||||
|
||||
if (temp_nogc == NULL)
|
||||
return;
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018 CTCaer
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -25,14 +25,15 @@ typedef struct _hekate_config
|
||||
u32 autoboot;
|
||||
u32 autoboot_list;
|
||||
u32 bootwait;
|
||||
u32 customlogo;
|
||||
u32 verification;
|
||||
u32 backlight;
|
||||
u32 autohosoff;
|
||||
u32 errors;
|
||||
u32 autonogc;
|
||||
// Global temporary config.
|
||||
int se_keygen_done;
|
||||
u32 sbar_time_keeping;
|
||||
u32 errors;
|
||||
int sept_run;
|
||||
} hekate_config;
|
||||
|
||||
typedef enum
|
||||
@@ -44,9 +45,9 @@ void set_default_configuration();
|
||||
int create_config_entry();
|
||||
void config_autoboot();
|
||||
void config_bootdelay();
|
||||
void config_customlogo();
|
||||
void config_verification();
|
||||
void config_backlight();
|
||||
void config_auto_hos_poweroff();
|
||||
void config_nogc();
|
||||
|
||||
#endif /* _CONFIG_H_ */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (C) 2018-2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -24,11 +24,39 @@
|
||||
|
||||
static char *_strdup(char *str)
|
||||
{
|
||||
if (!str)
|
||||
return NULL;
|
||||
char *res = (char *)malloc(strlen(str) + 1);
|
||||
strcpy(res, str);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
u32 _find_section_name(char *lbuf, u32 lblen, char schar)
|
||||
{
|
||||
u32 i;
|
||||
for (i = 0; i < lblen && lbuf[i] != schar && lbuf[i] != '\n' && lbuf[i] != '\r'; i++)
|
||||
;
|
||||
lbuf[i] = 0;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
ini_sec_t *_ini_create_section(link_t *dst, ini_sec_t *csec, char *name, u8 type)
|
||||
{
|
||||
if (csec)
|
||||
{
|
||||
list_append(dst, &csec->link);
|
||||
csec = NULL;
|
||||
}
|
||||
|
||||
csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
|
||||
csec->name = _strdup(name);
|
||||
csec->type = type;
|
||||
|
||||
return csec;
|
||||
}
|
||||
|
||||
int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
||||
{
|
||||
u32 lblen;
|
||||
@@ -43,9 +71,10 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
||||
|
||||
memcpy(filename, ini_path, pathlen + 1);
|
||||
|
||||
// Get all ini filenames.
|
||||
if (is_dir)
|
||||
{
|
||||
filelist = dirlist(filename, "*.ini");
|
||||
filelist = dirlist(filename, "*.ini", false);
|
||||
if (!filelist)
|
||||
{
|
||||
free(filename);
|
||||
@@ -57,6 +86,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
||||
|
||||
do
|
||||
{
|
||||
// Copy ini filename in path string.
|
||||
if (is_dir)
|
||||
{
|
||||
if (filelist[k * 256])
|
||||
@@ -68,6 +98,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
||||
break;
|
||||
}
|
||||
|
||||
// Open ini.
|
||||
if (f_open(&fp, filename, FA_READ) != FR_OK)
|
||||
{
|
||||
free(filelist);
|
||||
@@ -84,80 +115,36 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
||||
lblen = strlen(lbuf);
|
||||
|
||||
// Remove trailing newline.
|
||||
if (lbuf[lblen - 1] == '\n')
|
||||
if (lbuf[lblen - 1] == '\n' || lbuf[lblen - 1] == '\r')
|
||||
lbuf[lblen - 1] = 0;
|
||||
|
||||
if (lblen > 2 && lbuf[0] == '[') // Create new section.
|
||||
{
|
||||
if (csec)
|
||||
{
|
||||
list_append(dst, &csec->link);
|
||||
csec = NULL;
|
||||
}
|
||||
_find_section_name(lbuf, lblen, ']');
|
||||
|
||||
u32 i;
|
||||
for (i = 0; i < lblen && lbuf[i] != '\n' && lbuf[i] != ']'; i++)
|
||||
;
|
||||
lbuf[i] = 0;
|
||||
|
||||
csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
|
||||
csec->name = _strdup(&lbuf[1]);
|
||||
csec->type = INI_CHOICE;
|
||||
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CHOICE);
|
||||
list_init(&csec->kvs);
|
||||
}
|
||||
else if (lblen > 2 && lbuf[0] == '{') //Create new caption.
|
||||
{
|
||||
if (csec)
|
||||
{
|
||||
list_append(dst, &csec->link);
|
||||
csec = NULL;
|
||||
}
|
||||
_find_section_name(lbuf, lblen, '}');
|
||||
|
||||
u32 i;
|
||||
for (i = 0; i < lblen && lbuf[i] != '\n' && lbuf[i] != '}'; i++)
|
||||
;
|
||||
lbuf[i] = 0;
|
||||
|
||||
csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
|
||||
csec->name = _strdup(&lbuf[1]);
|
||||
csec->type = INI_CAPTION;
|
||||
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CAPTION);
|
||||
csec->color = 0xFF0AB9E6;
|
||||
}
|
||||
else if (lblen > 2 && lbuf[0] == '#') //Create empty lines and comments.
|
||||
{
|
||||
if (csec)
|
||||
{
|
||||
list_append(dst, &csec->link);
|
||||
csec = NULL;
|
||||
}
|
||||
_find_section_name(lbuf, lblen, '\0');
|
||||
|
||||
u32 i;
|
||||
for (i = 0; i < lblen && lbuf[i] != '\n'; i++)
|
||||
;
|
||||
lbuf[i] = 0;
|
||||
|
||||
csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
|
||||
csec->name = _strdup(&lbuf[1]);
|
||||
csec->type = INI_COMMENT;
|
||||
csec = _ini_create_section(dst, csec, &lbuf[1], INI_COMMENT);
|
||||
}
|
||||
else if (lblen < 2)
|
||||
{
|
||||
if (csec)
|
||||
{
|
||||
list_append(dst, &csec->link);
|
||||
csec = NULL;
|
||||
}
|
||||
|
||||
csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
|
||||
csec->name = NULL;
|
||||
csec->type = INI_NEWLINE;
|
||||
csec = _ini_create_section(dst, csec, NULL, INI_NEWLINE);
|
||||
}
|
||||
else if (csec && csec->type == INI_CHOICE) //Extract key/value.
|
||||
{
|
||||
u32 i;
|
||||
for (i = 0; i < lblen && lbuf[i] != '\n' && lbuf[i] != '='; i++)
|
||||
;
|
||||
lbuf[i] = 0;
|
||||
u32 i = _find_section_name(lbuf, lblen, '=');
|
||||
|
||||
ini_kv_t *kv = (ini_kv_t *)malloc(sizeof(ini_kv_t));
|
||||
kv->key = _strdup(&lbuf[0]);
|
||||
@@ -169,8 +156,11 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
||||
f_close(&fp);
|
||||
|
||||
if (csec)
|
||||
{
|
||||
list_append(dst, &csec->link);
|
||||
|
||||
if (is_dir)
|
||||
csec = NULL;
|
||||
}
|
||||
} while (is_dir);
|
||||
|
||||
free(filename);
|
||||
@@ -230,9 +220,9 @@ void ini_free_section(ini_sec_t *cfg)
|
||||
{
|
||||
free(kv->key);
|
||||
free(kv->val);
|
||||
free(kv);
|
||||
//free(kv);
|
||||
}
|
||||
free(cfg);
|
||||
//free(cfg);
|
||||
|
||||
cfg = NULL;
|
||||
}
|
||||
|
||||
942
bootloader/frontend/fe_emmc_tools.c
Normal file
942
bootloader/frontend/fe_emmc_tools.c
Normal file
@@ -0,0 +1,942 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018 Rajko Stojadinovic
|
||||
* Copyright (c) 2018 CTCaer
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "fe_emmc_tools.h"
|
||||
#include "../config/config.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../gfx/tui.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../sec/se.h"
|
||||
#include "../storage/nx_emmc.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
#include "../utils/btn.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
#define EMMC_BUF_ALIGNED 0xB5000000
|
||||
#define SDXC_BUF_ALIGNED 0xB6000000
|
||||
#define MIXD_BUF_ALIGNED 0xB7000000
|
||||
|
||||
extern sdmmc_t sd_sdmmc;
|
||||
extern sdmmc_storage_t sd_storage;
|
||||
extern FATFS sd_fs;
|
||||
extern hekate_config h_cfg;
|
||||
|
||||
extern bool sd_mount();
|
||||
extern void sd_unmount();
|
||||
extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);
|
||||
|
||||
static int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFilename, emmc_part_t *part)
|
||||
{
|
||||
FIL fp;
|
||||
u8 sparseShouldVerify = 0;
|
||||
u32 btn = 0;
|
||||
u32 prevPct = 200;
|
||||
int res = 0;
|
||||
u32 sdFileSector = 0;
|
||||
|
||||
u8 hashEm[0x20];
|
||||
u8 hashSd[0x20];
|
||||
|
||||
if (f_open(&fp, outFilename, FA_READ) == FR_OK)
|
||||
{
|
||||
u32 totalSectorsVer = (u32)((u64)f_size(&fp) >> (u64)9);
|
||||
|
||||
const u32 NUM_SECTORS_PER_ITER = 8192; // 4MB Cache.
|
||||
|
||||
u8 *bufEm = (u8 *)EMMC_BUF_ALIGNED;
|
||||
u8 *bufSd = (u8 *)SDXC_BUF_ALIGNED;
|
||||
|
||||
u32 pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
|
||||
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFF96FF00, 0xFF155500);
|
||||
|
||||
u32 num = 0;
|
||||
while (totalSectorsVer > 0)
|
||||
{
|
||||
num = MIN(totalSectorsVer, NUM_SECTORS_PER_ITER);
|
||||
|
||||
// Check every time or every 4.
|
||||
// Every 4 protects from fake sd, sector corruption and frequent I/O corruption.
|
||||
// Full provides all that, plus protection from extremely rare I/O corruption.
|
||||
if ((h_cfg.verification & 2) || !(sparseShouldVerify % 4))
|
||||
{
|
||||
if (!sdmmc_storage_read(storage, lba_curr, num, bufEm))
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTFARGS("\nFailed to read %d blocks (@LBA %08X),\nfrom eMMC!\n\nVerification failed..\n",
|
||||
num, lba_curr);
|
||||
|
||||
f_close(&fp);
|
||||
return 1;
|
||||
}
|
||||
f_lseek(&fp, (u64)sdFileSector << (u64)9);
|
||||
if (f_read(&fp, bufSd, num << 9, NULL))
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTFARGS("\nFailed to read %d blocks (@LBA %08X),\nfrom sd card!\n\nVerification failed..\n", num, lba_curr);
|
||||
|
||||
f_close(&fp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
se_calc_sha256(hashEm, bufEm, num << 9);
|
||||
se_calc_sha256(hashSd, bufSd, num << 9);
|
||||
res = memcmp(hashEm, hashSd, 0x10);
|
||||
|
||||
if (res)
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTFARGS("\nSD and eMMC data (@LBA %08X),\ndo not match!\n\nVerification failed..\n", lba_curr);
|
||||
|
||||
f_close(&fp);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
sparseShouldVerify++;
|
||||
sdFileSector += NUM_SECTORS_PER_ITER;
|
||||
|
||||
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
|
||||
if (pct != prevPct)
|
||||
{
|
||||
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFF96FF00, 0xFF155500);
|
||||
prevPct = pct;
|
||||
}
|
||||
|
||||
lba_curr += num;
|
||||
totalSectorsVer -= num;
|
||||
|
||||
btn = btn_wait_timeout(0, BTN_VOL_DOWN | BTN_VOL_UP);
|
||||
if ((btn & BTN_VOL_DOWN) && (btn & BTN_VOL_UP))
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
WPRINTF("\n\nVerification was cancelled!");
|
||||
gfx_con.fntsz = 8;
|
||||
msleep(1000);
|
||||
|
||||
f_close(&fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
f_close(&fp);
|
||||
|
||||
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555);
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTF("\nFile not found or could not be loaded.\n\nVerification failed..\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void _update_filename(char *outFilename, u32 sdPathLen, u32 numSplitParts, u32 currPartIdx)
|
||||
{
|
||||
if (numSplitParts >= 10 && currPartIdx < 10)
|
||||
{
|
||||
outFilename[sdPathLen] = '0';
|
||||
itoa(currPartIdx, &outFilename[sdPathLen + 1], 10);
|
||||
}
|
||||
else
|
||||
itoa(currPartIdx, &outFilename[sdPathLen], 10);
|
||||
}
|
||||
|
||||
static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
|
||||
{
|
||||
static const u32 FAT32_FILESIZE_LIMIT = 0xFFFFFFFF;
|
||||
static const u32 SECTORS_TO_MIB_COEFF = 11;
|
||||
|
||||
u32 multipartSplitSize = (1u << 31);
|
||||
u32 totalSectors = part->lba_end - part->lba_start + 1;
|
||||
u32 currPartIdx = 0;
|
||||
u32 numSplitParts = 0;
|
||||
u32 maxSplitParts = 0;
|
||||
u32 btn = 0;
|
||||
bool isSmallSdCard = false;
|
||||
bool partialDumpInProgress = false;
|
||||
int res = 0;
|
||||
char *outFilename = sd_path;
|
||||
u32 sdPathLen = strlen(sd_path);
|
||||
|
||||
FIL partialIdxFp;
|
||||
char partialIdxFilename[12];
|
||||
memcpy(partialIdxFilename, "partial.idx", 12);
|
||||
|
||||
gfx_con.fntsz = 8;
|
||||
gfx_printf(&gfx_con, "\nSD Card free space: %d MiB, Total backup size %d MiB\n\n",
|
||||
sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF,
|
||||
totalSectors >> SECTORS_TO_MIB_COEFF);
|
||||
|
||||
// 1GB parts for sd cards 8GB and less.
|
||||
if ((sd_storage.csd.capacity >> (20 - sd_storage.csd.read_blkbits)) <= 8192)
|
||||
multipartSplitSize = (1u << 30);
|
||||
// Maximum parts fitting the free space available.
|
||||
maxSplitParts = (sd_fs.free_clst * sd_fs.csize) / (multipartSplitSize / NX_EMMC_BLOCKSIZE);
|
||||
|
||||
// Check if the USER partition or the RAW eMMC fits the sd card free space.
|
||||
if (totalSectors > (sd_fs.free_clst * sd_fs.csize))
|
||||
{
|
||||
isSmallSdCard = true;
|
||||
|
||||
gfx_printf(&gfx_con, "%k\nSD card free space is smaller than total backup size.%k\n", 0xFFFFBA00, 0xFFCCCCCC);
|
||||
|
||||
if (!maxSplitParts)
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTF("Not enough free space for Partial Backup.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// Check if we are continuing a previous raw eMMC or USER partition backup in progress.
|
||||
if (f_open(&partialIdxFp, partialIdxFilename, FA_READ) == FR_OK && totalSectors > (FAT32_FILESIZE_LIMIT / NX_EMMC_BLOCKSIZE))
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kFound Partial Backup in progress. Continuing...%k\n\n", 0xFFAEFD14, 0xFFCCCCCC);
|
||||
|
||||
partialDumpInProgress = true;
|
||||
// Force partial dumping, even if the card is larger.
|
||||
isSmallSdCard = true;
|
||||
|
||||
f_read(&partialIdxFp, &currPartIdx, 4, NULL);
|
||||
f_close(&partialIdxFp);
|
||||
|
||||
if (!maxSplitParts)
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTF("Not enough free space for Partial Backup.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Increase maxSplitParts to accommodate previously backed up parts.
|
||||
maxSplitParts += currPartIdx;
|
||||
}
|
||||
else if (isSmallSdCard)
|
||||
gfx_printf(&gfx_con, "%kPartial Backup enabled (with %d MiB parts)...%k\n\n", 0xFFFFBA00, multipartSplitSize >> 20, 0xFFCCCCCC);
|
||||
|
||||
// Check if filesystem is FAT32 or the free space is smaller and backup in parts.
|
||||
if (((sd_fs.fs_type != FS_EXFAT) && totalSectors > (FAT32_FILESIZE_LIMIT / NX_EMMC_BLOCKSIZE)) | isSmallSdCard)
|
||||
{
|
||||
u32 multipartSplitSectors = multipartSplitSize / NX_EMMC_BLOCKSIZE;
|
||||
numSplitParts = (totalSectors + multipartSplitSectors - 1) / multipartSplitSectors;
|
||||
|
||||
outFilename[sdPathLen++] = '.';
|
||||
|
||||
// Continue from where we left, if Partial Backup in progress.
|
||||
_update_filename(outFilename, sdPathLen, numSplitParts, partialDumpInProgress ? currPartIdx : 0);
|
||||
}
|
||||
|
||||
FIL fp;
|
||||
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
|
||||
if (!f_open(&fp, outFilename, FA_READ))
|
||||
{
|
||||
f_close(&fp);
|
||||
gfx_con.fntsz = 16;
|
||||
|
||||
WPRINTF("An existing backup has been detected!");
|
||||
WPRINTF("Press POWER to Continue.\nPress VOL to go to the menu.\n");
|
||||
msleep(500);
|
||||
|
||||
if (!(btn_wait() & BTN_POWER))
|
||||
return 0;
|
||||
gfx_con.fntsz = 8;
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, gfx_con.savedy, 48);
|
||||
}
|
||||
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf(&gfx_con, "Filename: %s\n\n", outFilename);
|
||||
res = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE);
|
||||
if (res)
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTFARGS("Error (%d) creating file %s.\n", res, outFilename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const u32 NUM_SECTORS_PER_ITER = 8192;
|
||||
|
||||
u8 *buf = (u8 *)MIXD_BUF_ALIGNED;
|
||||
|
||||
u32 lba_curr = part->lba_start;
|
||||
u32 lbaStartPart = part->lba_start;
|
||||
u32 bytesWritten = 0;
|
||||
u32 prevPct = 200;
|
||||
int retryCount = 0;
|
||||
|
||||
// Continue from where we left, if Partial Backup in progress.
|
||||
if (partialDumpInProgress)
|
||||
{
|
||||
lba_curr += currPartIdx * (multipartSplitSize / NX_EMMC_BLOCKSIZE);
|
||||
totalSectors -= currPartIdx * (multipartSplitSize / NX_EMMC_BLOCKSIZE);
|
||||
lbaStartPart = lba_curr; // Update the start LBA for verification.
|
||||
}
|
||||
u64 totalSize = (u64)((u64)totalSectors << 9);
|
||||
if (!isSmallSdCard && sd_fs.fs_type == FS_EXFAT)
|
||||
f_lseek(&fp, totalSize);
|
||||
else
|
||||
f_lseek(&fp, MIN(totalSize, multipartSplitSize));
|
||||
f_lseek(&fp, 0);
|
||||
|
||||
u32 num = 0;
|
||||
u32 pct = 0;
|
||||
while (totalSectors > 0)
|
||||
{
|
||||
if (numSplitParts != 0 && bytesWritten >= multipartSplitSize)
|
||||
{
|
||||
f_close(&fp);
|
||||
memset(&fp, 0, sizeof(fp));
|
||||
currPartIdx++;
|
||||
|
||||
if (h_cfg.verification)
|
||||
{
|
||||
// Verify part.
|
||||
if (_dump_emmc_verify(storage, lbaStartPart, outFilename, part))
|
||||
{
|
||||
EPRINTF("\nPress any key and try again...\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
_update_filename(outFilename, sdPathLen, numSplitParts, currPartIdx);
|
||||
|
||||
// Always create partial.idx before next part, in case a fatal error occurs.
|
||||
if (isSmallSdCard)
|
||||
{
|
||||
// Create partial backup index file.
|
||||
if (f_open(&partialIdxFp, partialIdxFilename, FA_CREATE_ALWAYS | FA_WRITE) == FR_OK)
|
||||
{
|
||||
f_write(&partialIdxFp, &currPartIdx, 4, NULL);
|
||||
f_close(&partialIdxFp);
|
||||
}
|
||||
else
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTF("\nError creating partial.idx file.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// More parts to backup that do not currently fit the sd card free space or fatal error.
|
||||
if (currPartIdx >= maxSplitParts)
|
||||
{
|
||||
gfx_puts(&gfx_con, "\n\n1. Press any key to unmount SD Card.\n\
|
||||
2. Remove SD Card and move files to free space.\n\
|
||||
Don\'t move the partial.idx file!\n\
|
||||
3. Re-insert SD Card.\n\
|
||||
4. Select the SAME option again to continue.\n");
|
||||
gfx_con.fntsz = 16;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Create next part.
|
||||
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf(&gfx_con, "Filename: %s\n\n", outFilename);
|
||||
lbaStartPart = lba_curr;
|
||||
res = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE);
|
||||
if (res)
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTFARGS("Error (%d) creating file %s.\n", res, outFilename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
bytesWritten = 0;
|
||||
|
||||
totalSize = (u64)((u64)totalSectors << 9);
|
||||
f_lseek(&fp, MIN(totalSize, multipartSplitSize));
|
||||
f_lseek(&fp, 0);
|
||||
}
|
||||
|
||||
retryCount = 0;
|
||||
num = MIN(totalSectors, NUM_SECTORS_PER_ITER);
|
||||
while (!sdmmc_storage_read(storage, lba_curr, num, buf))
|
||||
{
|
||||
EPRINTFARGS("Error reading %d blocks @ LBA %08X,\nfrom eMMC (try %d), retrying...",
|
||||
num, lba_curr, ++retryCount);
|
||||
|
||||
msleep(150);
|
||||
if (retryCount >= 3)
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTFARGS("\nFailed to read %d blocks @ LBA %08X\nfrom eMMC. Aborting..\n",
|
||||
num, lba_curr);
|
||||
EPRINTF("\nPress any key and try again...\n");
|
||||
|
||||
f_close(&fp);
|
||||
f_unlink(outFilename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
res = f_write(&fp, buf, NX_EMMC_BLOCKSIZE * num, NULL);
|
||||
if (res)
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTFARGS("\nFatal error (%d) when writing to SD Card", res);
|
||||
EPRINTF("\nPress any key and try again...\n");
|
||||
|
||||
f_close(&fp);
|
||||
f_unlink(outFilename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
|
||||
if (pct != prevPct)
|
||||
{
|
||||
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555);
|
||||
prevPct = pct;
|
||||
}
|
||||
|
||||
lba_curr += num;
|
||||
totalSectors -= num;
|
||||
bytesWritten += num * NX_EMMC_BLOCKSIZE;
|
||||
|
||||
// Force a flush after a lot of data if not splitting.
|
||||
if (numSplitParts == 0 && bytesWritten >= multipartSplitSize)
|
||||
{
|
||||
f_sync(&fp);
|
||||
bytesWritten = 0;
|
||||
}
|
||||
|
||||
btn = btn_wait_timeout(0, BTN_VOL_DOWN | BTN_VOL_UP);
|
||||
if ((btn & BTN_VOL_DOWN) && (btn & BTN_VOL_UP))
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
WPRINTF("\n\nThe backup was cancelled!");
|
||||
EPRINTF("\nPress any key...\n");
|
||||
msleep(1500);
|
||||
|
||||
f_close(&fp);
|
||||
f_unlink(outFilename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
tui_pbar(&gfx_con, 0, gfx_con.y, 100, 0xFFCCCCCC, 0xFF555555);
|
||||
|
||||
// Backup operation ended successfully.
|
||||
f_close(&fp);
|
||||
|
||||
if (h_cfg.verification)
|
||||
{
|
||||
// Verify last part or single file backup.
|
||||
if (_dump_emmc_verify(storage, lbaStartPart, outFilename, part))
|
||||
{
|
||||
EPRINTF("\nPress any key and try again...\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
tui_pbar(&gfx_con, 0, gfx_con.y, 100, 0xFF96FF00, 0xFF155500);
|
||||
}
|
||||
|
||||
gfx_con.fntsz = 16;
|
||||
// Remove partial backup index file if no fatal errors occurred.
|
||||
if (isSmallSdCard)
|
||||
{
|
||||
f_unlink(partialIdxFilename);
|
||||
gfx_printf(&gfx_con, "%k\n\nYou can now join the files\nand get the complete eMMC RAW GPP backup.", 0xFFCCCCCC);
|
||||
}
|
||||
gfx_puts(&gfx_con, "\n\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PART_BOOT = (1 << 0),
|
||||
PART_SYSTEM = (1 << 1),
|
||||
PART_USER = (1 << 2),
|
||||
PART_RAW = (1 << 3),
|
||||
PART_GP_ALL = (1 << 7)
|
||||
} emmcPartType_t;
|
||||
|
||||
static void _dump_emmc_selected(emmcPartType_t dumpType)
|
||||
{
|
||||
int res = 0;
|
||||
u32 timer = 0;
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
tui_sbar(&gfx_con, true);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
if (!sd_mount())
|
||||
goto out;
|
||||
|
||||
gfx_puts(&gfx_con, "Checking for available free space...\n\n");
|
||||
// Get SD Card free space for Partial Backup.
|
||||
f_getfree("", &sd_fs.free_clst, NULL);
|
||||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
{
|
||||
EPRINTF("Failed to init eMMC.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
char sdPath[80];
|
||||
// Create Restore folders, if they do not exist.
|
||||
emmcsn_path_impl(sdPath, "/restore", "", &storage);
|
||||
emmcsn_path_impl(sdPath, "/restore/partitions", "", &storage);
|
||||
|
||||
timer = get_tmr_s();
|
||||
if (dumpType & PART_BOOT)
|
||||
{
|
||||
const u32 BOOT_PART_SIZE = storage.ext_csd.boot_mult << 17;
|
||||
|
||||
emmc_part_t bootPart;
|
||||
memset(&bootPart, 0, sizeof(bootPart));
|
||||
bootPart.lba_start = 0;
|
||||
bootPart.lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1;
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
memcpy(bootPart.name, "BOOT", 5);
|
||||
bootPart.name[4] = (u8)('0' + i);
|
||||
bootPart.name[5] = 0;
|
||||
|
||||
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i,
|
||||
bootPart.name, bootPart.lba_start, bootPart.lba_end, 0xFFCCCCCC);
|
||||
|
||||
sdmmc_storage_set_mmc_partition(&storage, i + 1);
|
||||
|
||||
emmcsn_path_impl(sdPath, "", bootPart.name, &storage);
|
||||
res = _dump_emmc_part(sdPath, &storage, &bootPart);
|
||||
}
|
||||
}
|
||||
|
||||
if ((dumpType & PART_SYSTEM) || (dumpType & PART_USER) || (dumpType & PART_RAW))
|
||||
{
|
||||
sdmmc_storage_set_mmc_partition(&storage, 0);
|
||||
|
||||
if ((dumpType & PART_SYSTEM) || (dumpType & PART_USER))
|
||||
{
|
||||
LIST_INIT(gpt);
|
||||
nx_emmc_gpt_parse(&gpt, &storage);
|
||||
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
|
||||
{
|
||||
if ((dumpType & PART_USER) == 0 && !strcmp(part->name, "USER"))
|
||||
continue;
|
||||
if ((dumpType & PART_SYSTEM) == 0 && strcmp(part->name, "USER"))
|
||||
continue;
|
||||
|
||||
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
|
||||
part->name, part->lba_start, part->lba_end, 0xFFCCCCCC);
|
||||
|
||||
emmcsn_path_impl(sdPath, "/partitions", part->name, &storage);
|
||||
res = _dump_emmc_part(sdPath, &storage, part);
|
||||
// If a part failed, don't continue.
|
||||
if (!res)
|
||||
break;
|
||||
}
|
||||
nx_emmc_gpt_free(&gpt);
|
||||
}
|
||||
|
||||
if (dumpType & PART_RAW)
|
||||
{
|
||||
// Get GP partition size dynamically.
|
||||
const u32 RAW_AREA_NUM_SECTORS = storage.sec_cnt;
|
||||
|
||||
emmc_part_t rawPart;
|
||||
memset(&rawPart, 0, sizeof(rawPart));
|
||||
rawPart.lba_start = 0;
|
||||
rawPart.lba_end = RAW_AREA_NUM_SECTORS - 1;
|
||||
strcpy(rawPart.name, "rawnand.bin");
|
||||
{
|
||||
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
|
||||
rawPart.name, rawPart.lba_start, rawPart.lba_end, 0xFFCCCCCC);
|
||||
|
||||
emmcsn_path_impl(sdPath, "", rawPart.name, &storage);
|
||||
res = _dump_emmc_part(sdPath, &storage, &rawPart);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gfx_putc(&gfx_con, '\n');
|
||||
timer = get_tmr_s() - timer;
|
||||
gfx_printf(&gfx_con, "Time taken: %dm %ds.\n", timer / 60, timer % 60);
|
||||
sdmmc_storage_end(&storage);
|
||||
if (res && h_cfg.verification)
|
||||
gfx_printf(&gfx_con, "\n%kFinished and verified!%k\nPress any key...\n", 0xFF96FF00, 0xFFCCCCCC);
|
||||
else if (res)
|
||||
gfx_printf(&gfx_con, "\nFinished! Press any key...\n");
|
||||
|
||||
out:
|
||||
sd_unmount();
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void dump_emmc_system() { _dump_emmc_selected(PART_SYSTEM); }
|
||||
void dump_emmc_user() { _dump_emmc_selected(PART_USER); }
|
||||
void dump_emmc_boot() { _dump_emmc_selected(PART_BOOT); }
|
||||
void dump_emmc_rawnand() { _dump_emmc_selected(PART_RAW); }
|
||||
|
||||
static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part, bool allow_multi_part)
|
||||
{
|
||||
static const u32 SECTORS_TO_MIB_COEFF = 11;
|
||||
|
||||
u32 totalSectors = part->lba_end - part->lba_start + 1;
|
||||
u32 currPartIdx = 0;
|
||||
u32 numSplitParts = 0;
|
||||
u32 lbaStartPart = part->lba_start;
|
||||
int res = 0;
|
||||
char *outFilename = sd_path;
|
||||
u32 sdPathLen = strlen(sd_path);
|
||||
u64 fileSize = 0;
|
||||
u64 totalCheckFileSize = 0;
|
||||
gfx_con.fntsz = 8;
|
||||
|
||||
FIL fp;
|
||||
FILINFO fno;
|
||||
|
||||
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
|
||||
|
||||
bool use_multipart = false;
|
||||
|
||||
if (allow_multi_part)
|
||||
{
|
||||
// Check to see if there is a combined file and if so then use that.
|
||||
if (f_stat(outFilename, &fno))
|
||||
{
|
||||
// If not, check if there are partial files and the total size matches.
|
||||
gfx_printf(&gfx_con, "No single file, checking for part files...\n");
|
||||
|
||||
outFilename[sdPathLen++] = '.';
|
||||
|
||||
// Stat total size of the part files.
|
||||
while ((u32)((u64)totalCheckFileSize >> (u64)9) != totalSectors)
|
||||
{
|
||||
_update_filename(outFilename, sdPathLen, 99, numSplitParts);
|
||||
|
||||
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf(&gfx_con, "\nFilename: %s\n", outFilename);
|
||||
|
||||
if (f_stat(outFilename, &fno))
|
||||
{
|
||||
WPRINTFARGS("Error (%d) file not found '%s'. Aborting...\n", res, outFilename);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
totalCheckFileSize += (u64)fno.fsize;
|
||||
|
||||
numSplitParts++;
|
||||
}
|
||||
|
||||
gfx_printf(&gfx_con, "\n%X sectors total.\n", (u32)((u64)totalCheckFileSize >> (u64)9));
|
||||
|
||||
if ((u32)((u64)totalCheckFileSize >> (u64)9) != totalSectors)
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTF("Size of SD Card split backups does not match,\neMMC's selected part size.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
use_multipart = true;
|
||||
_update_filename(outFilename, sdPathLen, numSplitParts, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res = f_open(&fp, outFilename, FA_READ);
|
||||
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf(&gfx_con, "\nFilename: %s\n", outFilename);
|
||||
if (res)
|
||||
{
|
||||
if (res != FR_NO_FILE)
|
||||
EPRINTFARGS("Error (%d) while opening backup. Continuing...\n", res);
|
||||
else
|
||||
WPRINTFARGS("Error (%d) file not found. Continuing...\n", res);
|
||||
gfx_con.fntsz = 16;
|
||||
|
||||
return 0;
|
||||
}
|
||||
else if (!use_multipart && (((u32)((u64)f_size(&fp) >> (u64)9)) != totalSectors)) // Check total restore size vs emmc size.
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTF("Size of the SD Card backup does not match,\neMMC's selected part size.\n");
|
||||
f_close(&fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
fileSize = (u64)f_size(&fp);
|
||||
gfx_printf(&gfx_con, "\nTotal restore size: %d MiB.\n\n",
|
||||
(u32)((use_multipart ? (u64)totalCheckFileSize : fileSize) >> (u64)9) >> SECTORS_TO_MIB_COEFF);
|
||||
}
|
||||
|
||||
const u32 NUM_SECTORS_PER_ITER = 8192; // 4MB Cache.
|
||||
|
||||
u8 *buf = (u8 *)MIXD_BUF_ALIGNED;
|
||||
|
||||
u32 lba_curr = part->lba_start;
|
||||
u32 bytesWritten = 0;
|
||||
u32 prevPct = 200;
|
||||
int retryCount = 0;
|
||||
|
||||
u32 num = 0;
|
||||
u32 pct = 0;
|
||||
|
||||
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
|
||||
|
||||
while (totalSectors > 0)
|
||||
{
|
||||
// If we have more than one part, check the size for the split parts and make sure that the bytes written is not more than that.
|
||||
if (numSplitParts != 0 && bytesWritten >= fileSize)
|
||||
{
|
||||
// If we have more bytes written then close the file pointer and increase the part index we are using
|
||||
f_close(&fp);
|
||||
memset(&fp, 0, sizeof(fp));
|
||||
currPartIdx++;
|
||||
|
||||
if (h_cfg.verification)
|
||||
{
|
||||
// Verify part.
|
||||
if (_dump_emmc_verify(storage, lbaStartPart, outFilename, part))
|
||||
{
|
||||
EPRINTF("\nPress any key and try again...\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
_update_filename(outFilename, sdPathLen, numSplitParts, currPartIdx);
|
||||
|
||||
// Read from next part.
|
||||
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf(&gfx_con, "Filename: %s\n\n", outFilename);
|
||||
|
||||
lbaStartPart = lba_curr;
|
||||
|
||||
// Try to open the next file part
|
||||
res = f_open(&fp, outFilename, FA_READ);
|
||||
if (res)
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTFARGS("Error (%d) opening file %s.\n", res, outFilename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
fileSize = (u64)f_size(&fp);
|
||||
bytesWritten = 0;
|
||||
}
|
||||
|
||||
retryCount = 0;
|
||||
num = MIN(totalSectors, NUM_SECTORS_PER_ITER);
|
||||
|
||||
res = f_read(&fp, buf, NX_EMMC_BLOCKSIZE * num, NULL);
|
||||
if (res)
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTFARGS("\nFatal error (%d) when reading from SD Card", res);
|
||||
EPRINTF("\nYour device may be in an inoperative state!\n\nPress any key and try again now...\n");
|
||||
|
||||
f_close(&fp);
|
||||
return 0;
|
||||
}
|
||||
while (!sdmmc_storage_write(storage, lba_curr, num, buf))
|
||||
{
|
||||
EPRINTFARGS("Error writing %d blocks @ LBA %08X\nto eMMC (try %d), retrying...",
|
||||
num, lba_curr, ++retryCount);
|
||||
|
||||
msleep(150);
|
||||
if (retryCount >= 3)
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTFARGS("\nFailed to write %d blocks @ LBA %08X\nfrom eMMC. Aborting..\n",
|
||||
num, lba_curr);
|
||||
EPRINTF("\nYour device may be in an inoperative state!\n\nPress any key and try again...\n");
|
||||
|
||||
f_close(&fp);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
|
||||
if (pct != prevPct)
|
||||
{
|
||||
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555);
|
||||
prevPct = pct;
|
||||
}
|
||||
|
||||
lba_curr += num;
|
||||
totalSectors -= num;
|
||||
bytesWritten += num * NX_EMMC_BLOCKSIZE;
|
||||
}
|
||||
tui_pbar(&gfx_con, 0, gfx_con.y, 100, 0xFFCCCCCC, 0xFF555555);
|
||||
|
||||
// Restore operation ended successfully.
|
||||
f_close(&fp);
|
||||
|
||||
if (h_cfg.verification)
|
||||
{
|
||||
// Verify restored data.
|
||||
if (_dump_emmc_verify(storage, lbaStartPart, outFilename, part))
|
||||
{
|
||||
EPRINTF("\nPress any key and try again...\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
tui_pbar(&gfx_con, 0, gfx_con.y, 100, 0xFF96FF00, 0xFF155500);
|
||||
}
|
||||
|
||||
gfx_con.fntsz = 16;
|
||||
gfx_puts(&gfx_con, "\n\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _restore_emmc_selected(emmcPartType_t restoreType)
|
||||
{
|
||||
int res = 0;
|
||||
u32 timer = 0;
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
tui_sbar(&gfx_con, true);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
gfx_printf(&gfx_con, "%kThis may render your device inoperative!\n\n", 0xFFFFDD00);
|
||||
gfx_printf(&gfx_con, "Are you really sure?\n\n%k", 0xFFCCCCCC);
|
||||
if ((restoreType & PART_BOOT) || (restoreType & PART_GP_ALL))
|
||||
{
|
||||
gfx_puts(&gfx_con, "The mode you selected will only restore\nthe ");
|
||||
if (restoreType & PART_BOOT)
|
||||
gfx_puts(&gfx_con, "boot ");
|
||||
gfx_puts(&gfx_con, "partitions that it can find.\n");
|
||||
gfx_puts(&gfx_con, "If it is not found, it will be skipped\nand continue with the next.\n\n");
|
||||
}
|
||||
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
|
||||
|
||||
u8 failsafe_wait = 10;
|
||||
while (failsafe_wait > 0)
|
||||
{
|
||||
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf(&gfx_con, "%kWait... (%ds) %k", 0xFF888888, failsafe_wait, 0xFFCCCCCC);
|
||||
msleep(1000);
|
||||
failsafe_wait--;
|
||||
}
|
||||
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
|
||||
|
||||
gfx_puts(&gfx_con, "Press POWER to Continue.\nPress VOL to go to the menu.\n\n\n");
|
||||
|
||||
u32 btn = btn_wait();
|
||||
if (!(btn & BTN_POWER))
|
||||
goto out;
|
||||
|
||||
if (!sd_mount())
|
||||
goto out;
|
||||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
{
|
||||
EPRINTF("Failed to init eMMC.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
char sdPath[80];
|
||||
|
||||
timer = get_tmr_s();
|
||||
if (restoreType & PART_BOOT)
|
||||
{
|
||||
const u32 BOOT_PART_SIZE = storage.ext_csd.boot_mult << 17;
|
||||
|
||||
emmc_part_t bootPart;
|
||||
memset(&bootPart, 0, sizeof(bootPart));
|
||||
bootPart.lba_start = 0;
|
||||
bootPart.lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1;
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
memcpy(bootPart.name, "BOOT", 4);
|
||||
bootPart.name[4] = (u8)('0' + i);
|
||||
bootPart.name[5] = 0;
|
||||
|
||||
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i,
|
||||
bootPart.name, bootPart.lba_start, bootPart.lba_end, 0xFFCCCCCC);
|
||||
|
||||
sdmmc_storage_set_mmc_partition(&storage, i + 1);
|
||||
|
||||
emmcsn_path_impl(sdPath, "/restore", bootPart.name, &storage);
|
||||
res = _restore_emmc_part(sdPath, &storage, &bootPart, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (restoreType & PART_GP_ALL)
|
||||
{
|
||||
sdmmc_storage_set_mmc_partition(&storage, 0);
|
||||
|
||||
LIST_INIT(gpt);
|
||||
nx_emmc_gpt_parse(&gpt, &storage);
|
||||
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
|
||||
{
|
||||
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
|
||||
part->name, part->lba_start, part->lba_end, 0xFFCCCCCC);
|
||||
|
||||
emmcsn_path_impl(sdPath, "/restore/partitions/", part->name, &storage);
|
||||
res = _restore_emmc_part(sdPath, &storage, part, false);
|
||||
}
|
||||
nx_emmc_gpt_free(&gpt);
|
||||
}
|
||||
|
||||
if (restoreType & PART_RAW)
|
||||
{
|
||||
// Get GP partition size dynamically.
|
||||
const u32 RAW_AREA_NUM_SECTORS = storage.sec_cnt;
|
||||
|
||||
emmc_part_t rawPart;
|
||||
memset(&rawPart, 0, sizeof(rawPart));
|
||||
rawPart.lba_start = 0;
|
||||
rawPart.lba_end = RAW_AREA_NUM_SECTORS - 1;
|
||||
strcpy(rawPart.name, "rawnand.bin");
|
||||
{
|
||||
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
|
||||
rawPart.name, rawPart.lba_start, rawPart.lba_end, 0xFFCCCCCC);
|
||||
|
||||
emmcsn_path_impl(sdPath, "/restore", rawPart.name, &storage);
|
||||
res = _restore_emmc_part(sdPath, &storage, &rawPart, true);
|
||||
}
|
||||
}
|
||||
|
||||
gfx_putc(&gfx_con, '\n');
|
||||
timer = get_tmr_s() - timer;
|
||||
gfx_printf(&gfx_con, "Time taken: %dm %ds.\n", timer / 60, timer % 60);
|
||||
sdmmc_storage_end(&storage);
|
||||
if (res && h_cfg.verification)
|
||||
gfx_printf(&gfx_con, "\n%kFinished and verified!%k\nPress any key...\n", 0xFF96FF00, 0xFFCCCCCC);
|
||||
else if (res)
|
||||
gfx_printf(&gfx_con, "\nFinished! Press any key...\n");
|
||||
|
||||
out:
|
||||
sd_unmount();
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void restore_emmc_boot() { _restore_emmc_selected(PART_BOOT); }
|
||||
void restore_emmc_rawnand() { _restore_emmc_selected(PART_RAW); }
|
||||
void restore_emmc_gpp_parts() { _restore_emmc_selected(PART_GP_ALL); }
|
||||
30
bootloader/frontend/fe_emmc_tools.h
Normal file
30
bootloader/frontend/fe_emmc_tools.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Rajko Stojadinovic
|
||||
* Copyright (c) 2018 CTCaer
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _FE_EMMC_TOOLS_H_
|
||||
#define _FE_EMMC_TOOLS_H_
|
||||
|
||||
void dump_emmc_system();
|
||||
void dump_emmc_user();
|
||||
void dump_emmc_boot();
|
||||
void dump_emmc_rawnand();
|
||||
|
||||
void restore_emmc_boot();
|
||||
void restore_emmc_rawnand();
|
||||
void restore_emmc_gpp_parts();
|
||||
|
||||
#endif
|
||||
682
bootloader/frontend/fe_info.c
Normal file
682
bootloader/frontend/fe_info.c
Normal file
@@ -0,0 +1,682 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
* Copyright (c) 2018 balika011
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "fe_info.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../hos/hos.h"
|
||||
#include "../hos/pkg1.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../power/bq24193.h"
|
||||
#include "../power/max17050.h"
|
||||
#include "../sec/tsec.h"
|
||||
#include "../soc/fuse.h"
|
||||
#include "../soc/i2c.h"
|
||||
#include "../soc/kfuse.h"
|
||||
#include "../soc/smmu.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../storage/mmc.h"
|
||||
#include "../storage/nx_emmc.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
#include "../utils/btn.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
extern sdmmc_storage_t sd_storage;
|
||||
extern FATFS sd_fs;
|
||||
|
||||
extern bool sd_mount();
|
||||
extern void sd_unmount();
|
||||
extern int sd_save_to_file(void *buf, u32 size, const char *filename);
|
||||
extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);
|
||||
|
||||
void print_fuseinfo()
|
||||
{
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
u32 burntFuses = 0;
|
||||
for (u32 i = 0; i < 32; i++)
|
||||
{
|
||||
if ((fuse_read_odm(7) >> i) & 1)
|
||||
burntFuses++;
|
||||
}
|
||||
|
||||
gfx_printf(&gfx_con, "\nSKU: %X - ", FUSE(FUSE_SKU_INFO));
|
||||
switch (fuse_read_odm(4) & 3)
|
||||
{
|
||||
case 0:
|
||||
gfx_printf(&gfx_con, "Retail\n");
|
||||
break;
|
||||
case 3:
|
||||
gfx_printf(&gfx_con, "Dev\n");
|
||||
break;
|
||||
}
|
||||
gfx_printf(&gfx_con, "Sdram ID: %d\n", (fuse_read_odm(4) >> 3) & 0x1F);
|
||||
gfx_printf(&gfx_con, "Burnt fuses: %d / 64\n", burntFuses);
|
||||
gfx_printf(&gfx_con, "Secure key: %08X%08X%08X%08X\n\n\n",
|
||||
byte_swap_32(FUSE(FUSE_PRIVATE_KEY0)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY1)),
|
||||
byte_swap_32(FUSE(FUSE_PRIVATE_KEY2)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY3)));
|
||||
|
||||
gfx_printf(&gfx_con, "%k(Unlocked) fuse cache:\n\n%k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
gfx_hexdump(&gfx_con, 0x7000F900, (u8 *)0x7000F900, 0x2FC);
|
||||
|
||||
gfx_puts(&gfx_con, "\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
|
||||
|
||||
u32 btn = btn_wait();
|
||||
if (btn & BTN_POWER)
|
||||
{
|
||||
if (sd_mount())
|
||||
{
|
||||
char path[64];
|
||||
emmcsn_path_impl(path, "/dumps", "fuses.bin", NULL);
|
||||
if (!sd_save_to_file((u8 *)0x7000F900, 0x2FC, path))
|
||||
gfx_puts(&gfx_con, "\nDone!\n");
|
||||
sd_unmount();
|
||||
}
|
||||
|
||||
btn_wait();
|
||||
}
|
||||
}
|
||||
|
||||
void print_kfuseinfo()
|
||||
{
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
gfx_printf(&gfx_con, "%kKFuse contents:\n\n%k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
u32 buf[KFUSE_NUM_WORDS];
|
||||
if (!kfuse_read(buf))
|
||||
EPRINTF("CRC fail.");
|
||||
else
|
||||
gfx_hexdump(&gfx_con, 0, (u8 *)buf, KFUSE_NUM_WORDS * 4);
|
||||
|
||||
gfx_puts(&gfx_con, "\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
|
||||
|
||||
u32 btn = btn_wait();
|
||||
if (btn & BTN_POWER)
|
||||
{
|
||||
if (sd_mount())
|
||||
{
|
||||
char path[64];
|
||||
emmcsn_path_impl(path, "/dumps", "kfuses.bin", NULL);
|
||||
if (!sd_save_to_file((u8 *)buf, KFUSE_NUM_WORDS * 4, path))
|
||||
gfx_puts(&gfx_con, "\nDone!\n");
|
||||
sd_unmount();
|
||||
}
|
||||
|
||||
btn_wait();
|
||||
}
|
||||
}
|
||||
|
||||
void print_mmc_info()
|
||||
{
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
static const u32 SECTORS_TO_MIB_COEFF = 11;
|
||||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
{
|
||||
EPRINTF("Failed to init eMMC.");
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
u16 card_type;
|
||||
u32 speed = 0;
|
||||
|
||||
gfx_printf(&gfx_con, "%kCID:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
switch (storage.csd.mmca_vsn)
|
||||
{
|
||||
case 0: /* MMC v1.0 - v1.2 */
|
||||
case 1: /* MMC v1.4 */
|
||||
gfx_printf(&gfx_con,
|
||||
" Vendor ID: %03X\n"
|
||||
" Model: %c%c%c%c%c%c%c\n"
|
||||
" HW rev: %X\n"
|
||||
" FW rev: %X\n"
|
||||
" S/N: %03X\n"
|
||||
" Month/Year: %02d/%04d\n\n",
|
||||
storage.cid.manfid,
|
||||
storage.cid.prod_name[0], storage.cid.prod_name[1], storage.cid.prod_name[2],
|
||||
storage.cid.prod_name[3], storage.cid.prod_name[4], storage.cid.prod_name[5],
|
||||
storage.cid.prod_name[6], storage.cid.hwrev, storage.cid.fwrev,
|
||||
storage.cid.serial, storage.cid.month, storage.cid.year);
|
||||
break;
|
||||
case 2: /* MMC v2.0 - v2.2 */
|
||||
case 3: /* MMC v3.1 - v3.3 */
|
||||
case 4: /* MMC v4 */
|
||||
gfx_printf(&gfx_con,
|
||||
" Vendor ID: %X\n"
|
||||
" Card/BGA: %X\n"
|
||||
" OEM ID: %02X\n"
|
||||
" Model: %c%c%c%c%c%c\n"
|
||||
" Prd Rev: %X\n"
|
||||
" S/N: %04X\n"
|
||||
" Month/Year: %02d/%04d\n\n",
|
||||
storage.cid.manfid, storage.cid.card_bga, storage.cid.oemid,
|
||||
storage.cid.prod_name[0], storage.cid.prod_name[1], storage.cid.prod_name[2],
|
||||
storage.cid.prod_name[3], storage.cid.prod_name[4], storage.cid.prod_name[5],
|
||||
storage.cid.prv, storage.cid.serial, storage.cid.month, storage.cid.year);
|
||||
break;
|
||||
default:
|
||||
EPRINTFARGS("eMMC has unknown MMCA version %d", storage.csd.mmca_vsn);
|
||||
break;
|
||||
}
|
||||
|
||||
if (storage.csd.structure == 0)
|
||||
EPRINTF("Unknown CSD structure.");
|
||||
else
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kExtended CSD V1.%d:%k\n",
|
||||
0xFF00DDFF, storage.ext_csd.ext_struct, 0xFFCCCCCC);
|
||||
card_type = storage.ext_csd.card_type;
|
||||
u8 card_type_support[96];
|
||||
u8 pos_type = 0;
|
||||
card_type_support[0] = 0;
|
||||
if (card_type & EXT_CSD_CARD_TYPE_HS_26)
|
||||
{
|
||||
memcpy(card_type_support, "HS26", 4);
|
||||
speed = (26 << 16) | 26;
|
||||
pos_type += 4;
|
||||
}
|
||||
if (card_type & EXT_CSD_CARD_TYPE_HS_52)
|
||||
{
|
||||
memcpy(card_type_support + pos_type, ", HS52", 6);
|
||||
speed = (52 << 16) | 52;
|
||||
pos_type += 6;
|
||||
}
|
||||
if (card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
|
||||
{
|
||||
memcpy(card_type_support + pos_type, ", DDR52_1.8V", 12);
|
||||
speed = (52 << 16) | 104;
|
||||
pos_type += 12;
|
||||
}
|
||||
if (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
|
||||
{
|
||||
memcpy(card_type_support + pos_type, ", HS200_1.8V", 12);
|
||||
speed = (200 << 16) | 200;
|
||||
pos_type += 12;
|
||||
}
|
||||
if (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V)
|
||||
{
|
||||
memcpy(card_type_support + pos_type, ", HS400_1.8V", 12);
|
||||
speed = (200 << 16) | 400;
|
||||
pos_type += 12;
|
||||
}
|
||||
card_type_support[pos_type] = 0;
|
||||
|
||||
gfx_printf(&gfx_con,
|
||||
" Spec Version: %02X\n"
|
||||
" Extended Rev: 1.%d\n"
|
||||
" Dev Version: %d\n"
|
||||
" Cmd Classes: %02X\n"
|
||||
" Capacity: %s\n"
|
||||
" Max Rate: %d MB/s (%d MHz)\n"
|
||||
" Current Rate: %d MB/s\n"
|
||||
" Type Support: ",
|
||||
storage.csd.mmca_vsn, storage.ext_csd.rev, storage.ext_csd.dev_version, storage.csd.cmdclass,
|
||||
storage.csd.capacity == (4096 * 512) ? "High" : "Low", speed & 0xFFFF, (speed >> 16) & 0xFFFF,
|
||||
storage.csd.busspeed);
|
||||
gfx_con.fntsz = 8;
|
||||
gfx_printf(&gfx_con, "%s", card_type_support);
|
||||
gfx_con.fntsz = 16;
|
||||
gfx_printf(&gfx_con, "\n\n", card_type_support);
|
||||
|
||||
u32 boot_size = storage.ext_csd.boot_mult << 17;
|
||||
u32 rpmb_size = storage.ext_csd.rpmb_mult << 17;
|
||||
gfx_printf(&gfx_con, "%keMMC Partitions:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
gfx_printf(&gfx_con, " 1: %kBOOT0 %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
|
||||
boot_size / 1024, boot_size / 1024 / 512);
|
||||
gfx_put_small_sep(&gfx_con);
|
||||
gfx_printf(&gfx_con, " 2: %kBOOT1 %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
|
||||
boot_size / 1024, boot_size / 1024 / 512);
|
||||
gfx_put_small_sep(&gfx_con);
|
||||
gfx_printf(&gfx_con, " 3: %kRPMB %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
|
||||
rpmb_size / 1024, rpmb_size / 1024 / 512);
|
||||
gfx_put_small_sep(&gfx_con);
|
||||
gfx_printf(&gfx_con, " 0: %kGPP (USER) %k\n Size: %5d MiB (LBA Sectors: 0x%07X)\n\n", 0xFF96FF00, 0xFFCCCCCC,
|
||||
storage.sec_cnt >> SECTORS_TO_MIB_COEFF, storage.sec_cnt);
|
||||
gfx_put_small_sep(&gfx_con);
|
||||
gfx_printf(&gfx_con, "%kGPP (eMMC USER) partition table:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
|
||||
sdmmc_storage_set_mmc_partition(&storage, 0);
|
||||
LIST_INIT(gpt);
|
||||
nx_emmc_gpt_parse(&gpt, &storage);
|
||||
int gpp_idx = 0;
|
||||
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
|
||||
{
|
||||
gfx_printf(&gfx_con, " %02d: %k%s%k\n Size: % 5d MiB (LBA Sectors 0x%07X)\n LBA Range: %08X-%08X\n",
|
||||
gpp_idx++, 0xFFAEFD14, part->name, 0xFFCCCCCC, (part->lba_end - part->lba_start + 1) >> SECTORS_TO_MIB_COEFF,
|
||||
part->lba_end - part->lba_start + 1, part->lba_start, part->lba_end);
|
||||
gfx_put_small_sep(&gfx_con);
|
||||
}
|
||||
nx_emmc_gpt_free(&gpt);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
sdmmc_storage_end(&storage);
|
||||
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void print_sdcard_info()
|
||||
{
|
||||
static const u32 SECTORS_TO_MIB_COEFF = 11;
|
||||
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
if (sd_mount())
|
||||
{
|
||||
u32 capacity;
|
||||
|
||||
gfx_printf(&gfx_con, "%kCard IDentification:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
gfx_printf(&gfx_con,
|
||||
" Vendor ID: %02x\n"
|
||||
" OEM ID: %c%c\n"
|
||||
" Model: %c%c%c%c%c\n"
|
||||
" HW rev: %X\n"
|
||||
" FW rev: %X\n"
|
||||
" S/N: %08x\n"
|
||||
" Month/Year: %02d/%04d\n\n",
|
||||
sd_storage.cid.manfid, (sd_storage.cid.oemid >> 8) & 0xFF, sd_storage.cid.oemid & 0xFF,
|
||||
sd_storage.cid.prod_name[0], sd_storage.cid.prod_name[1], sd_storage.cid.prod_name[2],
|
||||
sd_storage.cid.prod_name[3], sd_storage.cid.prod_name[4],
|
||||
sd_storage.cid.hwrev, sd_storage.cid.fwrev, sd_storage.cid.serial,
|
||||
sd_storage.cid.month, sd_storage.cid.year);
|
||||
|
||||
gfx_printf(&gfx_con, "%kCard-Specific Data V%d.0:%k\n", 0xFF00DDFF, sd_storage.csd.structure + 1, 0xFFCCCCCC);
|
||||
capacity = sd_storage.csd.capacity >> (20 - sd_storage.csd.read_blkbits);
|
||||
gfx_printf(&gfx_con,
|
||||
" Cmd Classes: %02X\n"
|
||||
" Capacity: %d MiB\n"
|
||||
" Bus Width: %d\n"
|
||||
" Current Rate: %d MB/s (%d MHz)\n"
|
||||
" Speed Class: %d\n"
|
||||
" UHS Grade: U%d\n"
|
||||
" Video Class: V%d\n"
|
||||
" App perf class: A%d\n"
|
||||
" Write Protect: %d\n\n",
|
||||
sd_storage.csd.cmdclass, capacity,
|
||||
sd_storage.ssr.bus_width, sd_storage.csd.busspeed, sd_storage.csd.busspeed * 2,
|
||||
sd_storage.ssr.speed_class, sd_storage.ssr.uhs_grade, sd_storage.ssr.video_class,
|
||||
sd_storage.ssr.app_class, sd_storage.csd.write_protect);
|
||||
|
||||
gfx_puts(&gfx_con, "Acquiring FAT volume info...\n\n");
|
||||
f_getfree("", &sd_fs.free_clst, NULL);
|
||||
gfx_printf(&gfx_con, "%kFound %s volume:%k\n Free: %d MiB\n Cluster: %d KiB\n",
|
||||
0xFF00DDFF, sd_fs.fs_type == FS_EXFAT ? "exFAT" : "FAT32", 0xFFCCCCCC,
|
||||
sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF, (sd_fs.csize > 1) ? (sd_fs.csize >> 1) : 512);
|
||||
sd_unmount();
|
||||
}
|
||||
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void print_tsec_key()
|
||||
{
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
u32 retries = 0;
|
||||
|
||||
tsec_ctxt_t tsec_ctxt;
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
|
||||
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4);
|
||||
|
||||
// Read package1.
|
||||
u8 *pkg1 = (u8 *)malloc(0x40000);
|
||||
sdmmc_storage_set_mmc_partition(&storage, 1);
|
||||
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
|
||||
sdmmc_storage_end(&storage);
|
||||
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
|
||||
if (!pkg1_id)
|
||||
{
|
||||
EPRINTF("Unknown pkg1 version for reading\nTSEC firmware.");
|
||||
goto out_wait;
|
||||
}
|
||||
|
||||
u8 keys[0x10 * 2];
|
||||
memset(keys, 0x00, 0x20);
|
||||
|
||||
tsec_ctxt.fw = (u8 *)pkg1 + pkg1_id->tsec_off;
|
||||
tsec_ctxt.pkg1 = pkg1;
|
||||
tsec_ctxt.pkg11_off = pkg1_id->pkg11_off;
|
||||
tsec_ctxt.secmon_base = pkg1_id->secmon_base;
|
||||
|
||||
if (pkg1_id->kb <= KB_FIRMWARE_VERSION_600)
|
||||
tsec_ctxt.size = 0xF00;
|
||||
else if (pkg1_id->kb == KB_FIRMWARE_VERSION_620)
|
||||
tsec_ctxt.size = 0x2900;
|
||||
else
|
||||
{
|
||||
tsec_ctxt.size = 0x3000;
|
||||
// Exit after TSEC key generation.
|
||||
*((vu16 *)((u32)tsec_ctxt.fw + 0x2DB5)) = 0x02F8;
|
||||
}
|
||||
|
||||
if (pkg1_id->kb == KB_FIRMWARE_VERSION_620)
|
||||
{
|
||||
u8 *tsec_paged = (u8 *)page_alloc(3);
|
||||
memcpy(tsec_paged, (void *)tsec_ctxt.fw, tsec_ctxt.size);
|
||||
tsec_ctxt.fw = tsec_paged;
|
||||
}
|
||||
|
||||
int res = 0;
|
||||
|
||||
while (tsec_query(keys, pkg1_id->kb, &tsec_ctxt) < 0)
|
||||
{
|
||||
memset(keys, 0x00, 0x20);
|
||||
|
||||
retries++;
|
||||
|
||||
if (retries > 3)
|
||||
{
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gfx_printf(&gfx_con, "%kTSEC key: %k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
|
||||
if (res >= 0)
|
||||
{
|
||||
for (u32 j = 0; j < 0x10; j++)
|
||||
gfx_printf(&gfx_con, "%02X", keys[j]);
|
||||
|
||||
|
||||
if (pkg1_id->kb == KB_FIRMWARE_VERSION_620)
|
||||
{
|
||||
gfx_printf(&gfx_con, "\n%kTSEC root: %k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
for (u32 j = 0; j < 0x10; j++)
|
||||
gfx_printf(&gfx_con, "%02X", keys[0x10 + j]);
|
||||
}
|
||||
}
|
||||
else
|
||||
EPRINTFARGS("ERROR %X\n", res);
|
||||
|
||||
gfx_puts(&gfx_con, "\n\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
|
||||
|
||||
u32 btn = btn_wait();
|
||||
if (btn & BTN_POWER)
|
||||
{
|
||||
if (sd_mount())
|
||||
{
|
||||
char path[64];
|
||||
emmcsn_path_impl(path, "/dumps", "tsec_keys.bin", NULL);
|
||||
if (!sd_save_to_file(keys, 0x10 * 2, path))
|
||||
gfx_puts(&gfx_con, "\nDone!\n");
|
||||
sd_unmount();
|
||||
}
|
||||
}
|
||||
else
|
||||
goto out;
|
||||
|
||||
out_wait:
|
||||
btn_wait();
|
||||
|
||||
out:
|
||||
free(pkg1);
|
||||
}
|
||||
|
||||
void print_fuel_gauge_info()
|
||||
{
|
||||
int value = 0;
|
||||
|
||||
gfx_printf(&gfx_con, "%kFuel Gauge IC Info:\n%k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
|
||||
max17050_get_property(MAX17050_Age, &value);
|
||||
gfx_printf(&gfx_con, "Age: %3d%\n", value);
|
||||
|
||||
max17050_get_property(MAX17050_RepSOC, &value);
|
||||
gfx_printf(&gfx_con, "Capacity now: %3d%\n", value >> 8);
|
||||
|
||||
max17050_get_property(MAX17050_RepCap, &value);
|
||||
gfx_printf(&gfx_con, "Capacity now: %4d mAh\n", value);
|
||||
|
||||
max17050_get_property(MAX17050_FullCAP, &value);
|
||||
gfx_printf(&gfx_con, "Capacity full: %4d mAh\n", value);
|
||||
|
||||
max17050_get_property(MAX17050_DesignCap, &value);
|
||||
gfx_printf(&gfx_con, "Capacity (design): %4d mAh\n", value);
|
||||
|
||||
max17050_get_property(MAX17050_Current, &value);
|
||||
if (value >= 0)
|
||||
gfx_printf(&gfx_con, "Current now: %d mA\n", value / 1000);
|
||||
else
|
||||
gfx_printf(&gfx_con, "Current now: -%d mA\n", ~value / 1000);
|
||||
|
||||
max17050_get_property(MAX17050_AvgCurrent, &value);
|
||||
if (value >= 0)
|
||||
gfx_printf(&gfx_con, "Current average: %d mA\n", value / 1000);
|
||||
else
|
||||
gfx_printf(&gfx_con, "Current average: -%d mA\n", ~value / 1000);
|
||||
|
||||
max17050_get_property(MAX17050_VCELL, &value);
|
||||
gfx_printf(&gfx_con, "Voltage now: %4d mV\n", value);
|
||||
|
||||
max17050_get_property(MAX17050_OCVInternal, &value);
|
||||
gfx_printf(&gfx_con, "Voltage open-circuit: %4d mV\n", value);
|
||||
|
||||
max17050_get_property(MAX17050_MinVolt, &value);
|
||||
gfx_printf(&gfx_con, "Min voltage reached: %4d mV\n", value);
|
||||
|
||||
max17050_get_property(MAX17050_MaxVolt, &value);
|
||||
gfx_printf(&gfx_con, "Max voltage reached: %4d mV\n", value);
|
||||
|
||||
max17050_get_property(MAX17050_V_empty, &value);
|
||||
gfx_printf(&gfx_con, "Empty voltage (design): %4d mV\n", value);
|
||||
|
||||
max17050_get_property(MAX17050_TEMP, &value);
|
||||
if (value >= 0)
|
||||
gfx_printf(&gfx_con, "Battery temperature: %d.%d oC\n", value / 10, value % 10);
|
||||
else
|
||||
gfx_printf(&gfx_con, "Battery temperature: -%d.%d oC\n", ~value / 10, (~value) % 10);
|
||||
}
|
||||
|
||||
void print_battery_charger_info()
|
||||
{
|
||||
int value = 0;
|
||||
|
||||
gfx_printf(&gfx_con, "%k\n\nBattery Charger IC Info:\n%k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
|
||||
bq24193_get_property(BQ24193_InputVoltageLimit, &value);
|
||||
gfx_printf(&gfx_con, "Input voltage limit: %4d mV\n", value);
|
||||
|
||||
bq24193_get_property(BQ24193_InputCurrentLimit, &value);
|
||||
gfx_printf(&gfx_con, "Input current limit: %4d mA\n", value);
|
||||
|
||||
bq24193_get_property(BQ24193_SystemMinimumVoltage, &value);
|
||||
gfx_printf(&gfx_con, "Min voltage limit: %4d mV\n", value);
|
||||
|
||||
bq24193_get_property(BQ24193_FastChargeCurrentLimit, &value);
|
||||
gfx_printf(&gfx_con, "Fast charge current limit: %4d mA\n", value);
|
||||
|
||||
bq24193_get_property(BQ24193_ChargeVoltageLimit, &value);
|
||||
gfx_printf(&gfx_con, "Charge voltage limit: %4d mV\n", value);
|
||||
|
||||
bq24193_get_property(BQ24193_ChargeStatus, &value);
|
||||
gfx_printf(&gfx_con, "Charge status: ");
|
||||
switch (value)
|
||||
{
|
||||
case 0:
|
||||
gfx_printf(&gfx_con, "Not charging\n");
|
||||
break;
|
||||
case 1:
|
||||
gfx_printf(&gfx_con, "Pre-charging\n");
|
||||
break;
|
||||
case 2:
|
||||
gfx_printf(&gfx_con, "Fast charging\n");
|
||||
break;
|
||||
case 3:
|
||||
gfx_printf(&gfx_con, "Charge terminated\n");
|
||||
break;
|
||||
default:
|
||||
gfx_printf(&gfx_con, "Unknown (%d)\n", value);
|
||||
break;
|
||||
}
|
||||
bq24193_get_property(BQ24193_TempStatus, &value);
|
||||
gfx_printf(&gfx_con, "Temperature status: ");
|
||||
switch (value)
|
||||
{
|
||||
case 0:
|
||||
gfx_printf(&gfx_con, "Normal\n");
|
||||
break;
|
||||
case 2:
|
||||
gfx_printf(&gfx_con, "Warm\n");
|
||||
break;
|
||||
case 3:
|
||||
gfx_printf(&gfx_con, "Cool\n");
|
||||
break;
|
||||
case 5:
|
||||
gfx_printf(&gfx_con, "Cold\n");
|
||||
break;
|
||||
case 6:
|
||||
gfx_printf(&gfx_con, "Hot\n");
|
||||
break;
|
||||
default:
|
||||
gfx_printf(&gfx_con, "Unknown (%d)\n", value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void print_battery_info()
|
||||
{
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
print_fuel_gauge_info();
|
||||
|
||||
print_battery_charger_info();
|
||||
|
||||
u8 *buf = (u8 *)malloc(0x100 * 2);
|
||||
|
||||
gfx_printf(&gfx_con, "%k\n\nBattery Fuel Gauge Registers:\n%k", 0xFF00DDFF, 0xFFCCCCCC);
|
||||
|
||||
for (int i = 0; i < 0x200; i += 2)
|
||||
{
|
||||
i2c_recv_buf_small(buf + i, 2, I2C_1, 0x36, i >> 1);
|
||||
usleep(2500);
|
||||
}
|
||||
|
||||
gfx_hexdump(&gfx_con, 0, (u8 *)buf, 0x200);
|
||||
|
||||
gfx_puts(&gfx_con, "\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
|
||||
|
||||
u32 btn = btn_wait();
|
||||
|
||||
if (btn & BTN_POWER)
|
||||
{
|
||||
if (sd_mount())
|
||||
{
|
||||
char path[64];
|
||||
emmcsn_path_impl(path, "/dumps", "fuel_gauge.bin", NULL);
|
||||
if (sd_save_to_file((u8 *)buf, 0x200, path))
|
||||
EPRINTF("\nError creating fuel.bin file.");
|
||||
else
|
||||
gfx_puts(&gfx_con, "\nDone!\n");
|
||||
sd_unmount();
|
||||
}
|
||||
|
||||
btn_wait();
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void _ipatch_process(u32 offset, u32 value)
|
||||
{
|
||||
gfx_printf(&gfx_con, "%8x %8x", BOOTROM_BASE + offset, value);
|
||||
u8 lo = value & 0xff;
|
||||
switch (value >> 8)
|
||||
{
|
||||
case 0x20:
|
||||
gfx_printf(&gfx_con, " MOVS R0, #0x%02X", lo);
|
||||
break;
|
||||
case 0xDF:
|
||||
gfx_printf(&gfx_con, " SVC #0x%02X", lo);
|
||||
break;
|
||||
}
|
||||
gfx_puts(&gfx_con, "\n");
|
||||
}
|
||||
|
||||
void bootrom_ipatches_info()
|
||||
{
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
static const u32 BOOTROM_SIZE = 0x18000;
|
||||
|
||||
u32 res = fuse_read_ipatch(_ipatch_process);
|
||||
if (res != 0)
|
||||
EPRINTFARGS("Failed to read ipatches. Error: %d", res);
|
||||
|
||||
gfx_puts(&gfx_con, "\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
|
||||
|
||||
u32 btn = btn_wait();
|
||||
if (btn & BTN_POWER)
|
||||
{
|
||||
if (sd_mount())
|
||||
{
|
||||
char path[64];
|
||||
u32 iram_evp_thunks[0x200];
|
||||
u32 iram_evp_thunks_len = sizeof(iram_evp_thunks);
|
||||
res = fuse_read_evp_thunk(iram_evp_thunks, &iram_evp_thunks_len);
|
||||
if (res == 0)
|
||||
{
|
||||
emmcsn_path_impl(path, "/dumps", "evp_thunks.bin", NULL);
|
||||
if (!sd_save_to_file((u8 *)iram_evp_thunks, iram_evp_thunks_len, path))
|
||||
gfx_puts(&gfx_con, "\nevp_thunks.bin saved!\n");
|
||||
}
|
||||
else
|
||||
EPRINTFARGS("Failed to read evp_thunks. Error: %d", res);
|
||||
|
||||
u32 words[0x100];
|
||||
read_raw_ipatch_fuses(words);
|
||||
emmcsn_path_impl(path, "/dumps", "ipatches.bin", NULL);
|
||||
if (!sd_save_to_file((u8 *)words, sizeof(words), path))
|
||||
gfx_puts(&gfx_con, "\nipatches.bin saved!\n");
|
||||
|
||||
emmcsn_path_impl(path, "/dumps", "bootrom_patched.bin", NULL);
|
||||
if (!sd_save_to_file((u8 *)BOOTROM_BASE, BOOTROM_SIZE, path))
|
||||
gfx_puts(&gfx_con, "\nbootrom_patched.bin saved!\n");
|
||||
|
||||
u32 ipatch_backup[14];
|
||||
memcpy(ipatch_backup, (void *)IPATCH_BASE, sizeof(ipatch_backup));
|
||||
memset((void*)IPATCH_BASE, 0, sizeof(ipatch_backup));
|
||||
|
||||
emmcsn_path_impl(path, "/dumps", "bootrom_unpatched.bin", NULL);
|
||||
if (!sd_save_to_file((u8 *)BOOTROM_BASE, BOOTROM_SIZE, path))
|
||||
gfx_puts(&gfx_con, "\nbootrom_unpatched.bin saved!\n");
|
||||
|
||||
memcpy((void*)IPATCH_BASE, ipatch_backup, sizeof(ipatch_backup));
|
||||
|
||||
sd_unmount();
|
||||
}
|
||||
|
||||
btn_wait();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018 CTCaer
|
||||
* Copyright (c) 2018 balika011
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -14,21 +16,17 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* TODO: the placement of the relocator is a bit fragile atm, maybe we
|
||||
* should include it in start.S and copy it to some known good
|
||||
* place in IRAM instead. Basically we want it as far back atm
|
||||
* as it might be overwritten during relocation.
|
||||
*/
|
||||
#ifndef _FE_INFO_H_
|
||||
#define _FE_INFO_H_
|
||||
|
||||
.section .text.reloc
|
||||
.arm
|
||||
void print_fuseinfo();
|
||||
void print_kfuseinfo();
|
||||
void print_mmc_info();
|
||||
void print_sdcard_info();
|
||||
void print_tsec_key();
|
||||
void print_fuel_gauge_info();
|
||||
void print_battery_charger_info();
|
||||
void print_battery_info();
|
||||
void bootrom_ipatches_info();
|
||||
|
||||
.globl _reloc_ipl
|
||||
.type _reloc_ipl, %function
|
||||
_reloc_ipl:
|
||||
LDMIA R0!, {R4-R7}
|
||||
STMIA R1!, {R4-R7}
|
||||
SUBS R2, #0x10
|
||||
BNE _reloc_ipl
|
||||
BX R3
|
||||
#endif
|
||||
624
bootloader/frontend/fe_tools.c
Normal file
624
bootloader/frontend/fe_tools.c
Normal file
@@ -0,0 +1,624 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
* Copyright (c) 2018 Reisyukaku
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "fe_tools.h"
|
||||
#include "../config/config.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../gfx/tui.h"
|
||||
#include "../hos/hos.h"
|
||||
#include "../hos/pkg1.h"
|
||||
#include "../hos/pkg2.h"
|
||||
#include "../hos/sept.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../power/max7762x.h"
|
||||
#include "../sec/se.h"
|
||||
#include "../storage/nx_emmc.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
#include "../utils/btn.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
extern boot_cfg_t b_cfg;
|
||||
extern hekate_config h_cfg;
|
||||
|
||||
extern bool sd_mount();
|
||||
extern void sd_unmount();
|
||||
extern int sd_save_to_file(void *buf, u32 size, const char *filename);
|
||||
extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);
|
||||
|
||||
void dump_packages12()
|
||||
{
|
||||
if (!sd_mount())
|
||||
return;
|
||||
|
||||
u8 *pkg1 = (u8 *)calloc(1, 0x40000);
|
||||
u8 *warmboot = (u8 *)calloc(1, 0x40000);
|
||||
u8 *secmon = (u8 *)calloc(1, 0x40000);
|
||||
u8 *loader = (u8 *)calloc(1, 0x40000);
|
||||
u8 *pkg2 = NULL;
|
||||
u8 kb = 0;
|
||||
|
||||
tsec_ctxt_t tsec_ctxt;
|
||||
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
{
|
||||
EPRINTF("Failed to init eMMC.");
|
||||
goto out_free;
|
||||
}
|
||||
sdmmc_storage_set_mmc_partition(&storage, 1);
|
||||
|
||||
// Read package1.
|
||||
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
|
||||
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
|
||||
const pk11_hdr_t *hdr = (pk11_hdr_t *)(pkg1 + pkg1_id->pkg11_off + 0x20);
|
||||
if (!pkg1_id)
|
||||
{
|
||||
gfx_con.fntsz = 8;
|
||||
EPRINTF("Unknown pkg1 version for reading\nTSEC firmware.");
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
kb = pkg1_id->kb;
|
||||
|
||||
if (!h_cfg.se_keygen_done || kb == KB_FIRMWARE_VERSION_620)
|
||||
{
|
||||
tsec_ctxt.fw = (void *)pkg1 + pkg1_id->tsec_off;
|
||||
tsec_ctxt.pkg1 = (void *)pkg1;
|
||||
tsec_ctxt.pkg11_off = pkg1_id->pkg11_off;
|
||||
tsec_ctxt.secmon_base = pkg1_id->secmon_base;
|
||||
|
||||
if (kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run)
|
||||
{
|
||||
b_cfg.autoboot = 0;
|
||||
b_cfg.autoboot_list = 0;
|
||||
|
||||
gfx_printf(&gfx_con, "sept will run to get the keys.\nThen rerun this option.");
|
||||
btn_wait();
|
||||
|
||||
if (!reboot_to_sept((u8 *)tsec_ctxt.fw))
|
||||
{
|
||||
gfx_printf(&gfx_con, "Failed to run sept\n");
|
||||
goto out_free;
|
||||
}
|
||||
}
|
||||
|
||||
// Read keyblob.
|
||||
u8 *keyblob = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1);
|
||||
sdmmc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + kb, 1, keyblob);
|
||||
|
||||
// Decrypt.
|
||||
keygen(keyblob, kb, &tsec_ctxt);
|
||||
|
||||
h_cfg.se_keygen_done = 1;
|
||||
free(keyblob);
|
||||
}
|
||||
|
||||
if (kb <= KB_FIRMWARE_VERSION_600)
|
||||
pkg1_decrypt(pkg1_id, pkg1);
|
||||
|
||||
char path[64];
|
||||
|
||||
if (kb <= KB_FIRMWARE_VERSION_620)
|
||||
{
|
||||
pkg1_unpack(warmboot, secmon, loader, pkg1_id, pkg1);
|
||||
|
||||
// Display info.
|
||||
gfx_printf(&gfx_con, "%kNX Bootloader size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->ldr_size);
|
||||
|
||||
gfx_printf(&gfx_con, "%kSecure monitor addr: %k0x%05X\n", 0xFFC7EA46, 0xFFCCCCCC, pkg1_id->secmon_base);
|
||||
gfx_printf(&gfx_con, "%kSecure monitor size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->sm_size);
|
||||
|
||||
gfx_printf(&gfx_con, "%kWarmboot addr: %k0x%05X\n", 0xFFC7EA46, 0xFFCCCCCC, pkg1_id->warmboot_base);
|
||||
gfx_printf(&gfx_con, "%kWarmboot size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->wb_size);
|
||||
|
||||
// Dump package1.1.
|
||||
emmcsn_path_impl(path, "/pkg1", "pkg1_decr.bin", &storage);
|
||||
if (sd_save_to_file(pkg1, 0x40000, path))
|
||||
goto out_free;
|
||||
gfx_puts(&gfx_con, "\npkg1 dumped to pkg1_decr.bin\n");
|
||||
|
||||
// Dump nxbootloader.
|
||||
emmcsn_path_impl(path, "/pkg1", "nxloader.bin", &storage);
|
||||
if (sd_save_to_file(loader, hdr->ldr_size, path))
|
||||
goto out_free;
|
||||
gfx_puts(&gfx_con, "NX Bootloader dumped to nxloader.bin\n");
|
||||
|
||||
// Dump secmon.
|
||||
emmcsn_path_impl(path, "/pkg1", "secmon.bin", &storage);
|
||||
if (sd_save_to_file(secmon, hdr->sm_size, path))
|
||||
goto out_free;
|
||||
gfx_puts(&gfx_con, "Secure Monitor dumped to secmon.bin\n");
|
||||
|
||||
// Dump warmboot.
|
||||
emmcsn_path_impl(path, "/pkg1", "warmboot.bin", &storage);
|
||||
if (sd_save_to_file(warmboot, hdr->wb_size, path))
|
||||
goto out_free;
|
||||
gfx_puts(&gfx_con, "Warmboot dumped to warmboot.bin\n\n\n");
|
||||
}
|
||||
|
||||
// Dump package2.1.
|
||||
sdmmc_storage_set_mmc_partition(&storage, 0);
|
||||
// Parse eMMC GPT.
|
||||
LIST_INIT(gpt);
|
||||
nx_emmc_gpt_parse(&gpt, &storage);
|
||||
// Find package2 partition.
|
||||
emmc_part_t *pkg2_part = nx_emmc_part_find(&gpt, "BCPKG2-1-Normal-Main");
|
||||
if (!pkg2_part)
|
||||
goto out;
|
||||
|
||||
// Read in package2 header and get package2 real size.
|
||||
u8 *tmp = (u8 *)malloc(NX_EMMC_BLOCKSIZE);
|
||||
nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, 1, tmp);
|
||||
u32 *hdr_pkg2_raw = (u32 *)(tmp + 0x100);
|
||||
u32 pkg2_size = hdr_pkg2_raw[0] ^ hdr_pkg2_raw[2] ^ hdr_pkg2_raw[3];
|
||||
free(tmp);
|
||||
// Read in package2.
|
||||
u32 pkg2_size_aligned = ALIGN(pkg2_size, NX_EMMC_BLOCKSIZE);
|
||||
pkg2 = malloc(pkg2_size_aligned);
|
||||
nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE,
|
||||
pkg2_size_aligned / NX_EMMC_BLOCKSIZE, pkg2);
|
||||
// Decrypt package2 and parse KIP1 blobs in INI1 section.
|
||||
pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(pkg2);
|
||||
|
||||
// Display info.
|
||||
u32 kernel_crc32 = crc32c(pkg2_hdr->data, pkg2_hdr->sec_size[PKG2_SEC_KERNEL]);
|
||||
gfx_printf(&gfx_con, "\n%kKernel CRC32C: %k0x%08X\n\n", 0xFFC7EA46, 0xFFCCCCCC, kernel_crc32);
|
||||
gfx_printf(&gfx_con, "%kKernel size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, pkg2_hdr->sec_size[PKG2_SEC_KERNEL]);
|
||||
gfx_printf(&gfx_con, "%kINI1 size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, pkg2_hdr->sec_size[PKG2_SEC_INI1]);
|
||||
|
||||
// Dump pkg2.1.
|
||||
emmcsn_path_impl(path, "/pkg2", "pkg2_decr.bin", &storage);
|
||||
if (sd_save_to_file(pkg2, pkg2_hdr->sec_size[PKG2_SEC_KERNEL] + pkg2_hdr->sec_size[PKG2_SEC_INI1], path))
|
||||
goto out;
|
||||
gfx_puts(&gfx_con, "\npkg2 dumped to pkg2_decr.bin\n");
|
||||
|
||||
// Dump kernel.
|
||||
emmcsn_path_impl(path, "/pkg2", "kernel.bin", &storage);
|
||||
if (sd_save_to_file(pkg2_hdr->data, pkg2_hdr->sec_size[PKG2_SEC_KERNEL], path))
|
||||
goto out;
|
||||
gfx_puts(&gfx_con, "Kernel dumped to kernel.bin\n");
|
||||
|
||||
// Dump INI1.
|
||||
emmcsn_path_impl(path, "/pkg2", "ini1.bin", &storage);
|
||||
if (sd_save_to_file(pkg2_hdr->data + pkg2_hdr->sec_size[PKG2_SEC_KERNEL],
|
||||
pkg2_hdr->sec_size[PKG2_SEC_INI1], path))
|
||||
goto out;
|
||||
gfx_puts(&gfx_con, "INI1 dumped to ini1.bin\n");
|
||||
|
||||
gfx_puts(&gfx_con, "\nDone. Press any key...\n");
|
||||
|
||||
out:
|
||||
nx_emmc_gpt_free(&gpt);
|
||||
out_free:
|
||||
free(pkg1);
|
||||
free(secmon);
|
||||
free(warmboot);
|
||||
free(loader);
|
||||
free(pkg2);
|
||||
sdmmc_storage_end(&storage);
|
||||
sd_unmount();
|
||||
|
||||
if (kb >= KB_FIRMWARE_VERSION_620)
|
||||
se_aes_key_clear(8);
|
||||
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void _toggle_autorcm(bool enable)
|
||||
{
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
|
||||
u8 randomXor = 0;
|
||||
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
{
|
||||
EPRINTF("Failed to init eMMC.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
u8 *tempbuf = (u8 *)malloc(0x200);
|
||||
sdmmc_storage_set_mmc_partition(&storage, 1);
|
||||
|
||||
int i, sect = 0;
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
sect = (0x200 + (0x4000 * i)) / NX_EMMC_BLOCKSIZE;
|
||||
sdmmc_storage_read(&storage, sect, 1, tempbuf);
|
||||
|
||||
if (enable)
|
||||
{
|
||||
do
|
||||
{
|
||||
randomXor = get_tmr_us() & 0xFF; // Bricmii style of bricking.
|
||||
} while (!randomXor); // Avoid the lottery.
|
||||
|
||||
tempbuf[0x10] ^= randomXor;
|
||||
}
|
||||
else
|
||||
tempbuf[0x10] = 0xF7;
|
||||
sdmmc_storage_write(&storage, sect, 1, tempbuf);
|
||||
}
|
||||
|
||||
free(tempbuf);
|
||||
sdmmc_storage_end(&storage);
|
||||
|
||||
if (enable)
|
||||
gfx_printf(&gfx_con, "%kAutoRCM mode enabled!%k", 0xFFFFBA00, 0xFFCCCCCC);
|
||||
else
|
||||
gfx_printf(&gfx_con, "%kAutoRCM mode disabled!%k", 0xFF96FF00, 0xFFCCCCCC);
|
||||
gfx_printf(&gfx_con, "\n\nPress any key...\n");
|
||||
|
||||
out:
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void _enable_autorcm() { _toggle_autorcm(true); }
|
||||
void _disable_autorcm() { _toggle_autorcm(false); }
|
||||
|
||||
void menu_autorcm()
|
||||
{
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
// Do a simple check on the main BCT.
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
bool disabled = true;
|
||||
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
{
|
||||
EPRINTF("Failed to init eMMC.");
|
||||
btn_wait();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
u8 *tempbuf = (u8 *)malloc(0x200);
|
||||
sdmmc_storage_set_mmc_partition(&storage, 1);
|
||||
sdmmc_storage_read(&storage, 0x200 / NX_EMMC_BLOCKSIZE, 1, tempbuf);
|
||||
|
||||
if (tempbuf[0x10] != 0xF7)
|
||||
disabled = false;
|
||||
|
||||
free(tempbuf);
|
||||
sdmmc_storage_end(&storage);
|
||||
|
||||
// Create AutoRCM menu.
|
||||
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6);
|
||||
|
||||
ments[0].type = MENT_BACK;
|
||||
ments[0].caption = "Back";
|
||||
|
||||
ments[1].type = MENT_CHGLINE;
|
||||
|
||||
ments[2].type = MENT_CAPTION;
|
||||
ments[3].type = MENT_CHGLINE;
|
||||
if (disabled)
|
||||
{
|
||||
ments[2].caption = "Status: Disabled!";
|
||||
ments[2].color = 0xFF96FF00;
|
||||
ments[4].caption = "Enable AutoRCM";
|
||||
ments[4].handler = _enable_autorcm;
|
||||
}
|
||||
else
|
||||
{
|
||||
ments[2].caption = "Status: Enabled!";
|
||||
ments[2].color = 0xFFFFBA00;
|
||||
ments[4].caption = "Disable AutoRCM";
|
||||
ments[4].handler = _disable_autorcm;
|
||||
}
|
||||
ments[4].type = MENT_HDLR_RE;
|
||||
ments[4].data = NULL;
|
||||
|
||||
memset(&ments[5], 0, sizeof(ment_t));
|
||||
menu_t menu = {ments, "This corrupts your BOOT0!", 0, 0};
|
||||
|
||||
tui_do_menu(&gfx_con, &menu);
|
||||
}
|
||||
|
||||
int _fix_attributes(char *path, u32 *total, u32 hos_folder, u32 check_first_run)
|
||||
{
|
||||
FRESULT res;
|
||||
DIR dir;
|
||||
u32 dirLength = 0;
|
||||
static FILINFO fno;
|
||||
|
||||
if (check_first_run)
|
||||
{
|
||||
// Read file attributes.
|
||||
res = f_stat(path, &fno);
|
||||
if (res != FR_OK)
|
||||
return res;
|
||||
|
||||
// Check if archive bit is set.
|
||||
if (fno.fattrib & AM_ARC)
|
||||
{
|
||||
*(u32 *)total = *(u32 *)total + 1;
|
||||
f_chmod(path, 0, AM_ARC);
|
||||
}
|
||||
}
|
||||
|
||||
// Open directory.
|
||||
res = f_opendir(&dir, path);
|
||||
if (res != FR_OK)
|
||||
return res;
|
||||
|
||||
dirLength = strlen(path);
|
||||
for (;;)
|
||||
{
|
||||
// Clear file or folder path.
|
||||
path[dirLength] = 0;
|
||||
|
||||
// Read a directory item.
|
||||
res = f_readdir(&dir, &fno);
|
||||
|
||||
// Break on error or end of dir.
|
||||
if (res != FR_OK || fno.fname[0] == 0)
|
||||
break;
|
||||
|
||||
// Skip official Nintendo dir if started from root.
|
||||
if (!hos_folder && !strcmp(fno.fname, "Nintendo"))
|
||||
continue;
|
||||
|
||||
// Set new directory or file.
|
||||
memcpy(&path[dirLength], "/", 1);
|
||||
memcpy(&path[dirLength + 1], fno.fname, strlen(fno.fname) + 1);
|
||||
|
||||
// Check if archive bit is set.
|
||||
if (fno.fattrib & AM_ARC)
|
||||
{
|
||||
*total = *total + 1;
|
||||
f_chmod(path, 0, AM_ARC);
|
||||
}
|
||||
|
||||
// Is it a directory?
|
||||
if (fno.fattrib & AM_DIR)
|
||||
{
|
||||
// Set archive bit to NCA folders.
|
||||
if (hos_folder && !strcmp(fno.fname + strlen(fno.fname) - 4, ".nca"))
|
||||
{
|
||||
*total = *total + 1;
|
||||
f_chmod(path, AM_ARC, AM_ARC);
|
||||
}
|
||||
// Enter the directory.
|
||||
res = _fix_attributes(path, total, hos_folder, 0);
|
||||
if (res != FR_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
f_closedir(&dir);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void _fix_sd_attr(u32 type)
|
||||
{
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
char path[256];
|
||||
char label[16];
|
||||
|
||||
u32 total = 0;
|
||||
if (sd_mount())
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case 0:
|
||||
memcpy(path, "/", 2);
|
||||
memcpy(label, "SD Card", 8);
|
||||
break;
|
||||
case 1:
|
||||
default:
|
||||
memcpy(path, "/Nintendo", 10);
|
||||
memcpy(label, "Nintendo folder", 16);
|
||||
break;
|
||||
}
|
||||
|
||||
gfx_printf(&gfx_con, "Traversing all %s files!\nThis may take some time...\n\n", label);
|
||||
_fix_attributes(path, &total, type, type);
|
||||
gfx_printf(&gfx_con, "%kTotal archive bits cleared: %d!%k\n\nDone! Press any key...", 0xFF96FF00, total, 0xFFCCCCCC);
|
||||
sd_unmount();
|
||||
}
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void fix_sd_all_attr() { _fix_sd_attr(0); }
|
||||
void fix_sd_nin_attr() { _fix_sd_attr(1); }
|
||||
|
||||
void fix_battery_desync()
|
||||
{
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
max77620_low_battery_monitor_config();
|
||||
|
||||
gfx_puts(&gfx_con, "\nDone!\n");
|
||||
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
/* void fix_fuel_gauge_configuration()
|
||||
{
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
int battVoltage, avgCurrent;
|
||||
|
||||
max17050_get_property(MAX17050_VCELL, &battVoltage);
|
||||
max17050_get_property(MAX17050_AvgCurrent, &avgCurrent);
|
||||
|
||||
// Check if still charging. If not, check if battery is >= 95% (4.1V).
|
||||
if (avgCurrent < 0 && battVoltage > 4100)
|
||||
{
|
||||
if ((avgCurrent / 1000) < -10)
|
||||
EPRINTF("You need to be connected to a wall adapter,\nto apply this fix!");
|
||||
else
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kAre you really sure?\nThis will reset your fuel gauge completely!\n", 0xFFFFDD00);
|
||||
gfx_printf(&gfx_con, "Additionally this will power off your console.\n%k", 0xFFCCCCCC);
|
||||
|
||||
gfx_puts(&gfx_con, "\nPress POWER to Continue.\nPress VOL to go to the menu.\n\n\n");
|
||||
|
||||
u32 btn = btn_wait();
|
||||
if (btn & BTN_POWER)
|
||||
{
|
||||
max17050_fix_configuration();
|
||||
msleep(1000);
|
||||
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
|
||||
u16 value = 0;
|
||||
gfx_printf(&gfx_con, "%kThe console will power off in 45 seconds.\n%k", 0xFFFFDD00, 0xFFCCCCCC);
|
||||
while (value < 46)
|
||||
{
|
||||
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf(&gfx_con, "%2ds elapsed", value);
|
||||
msleep(1000);
|
||||
value++;
|
||||
}
|
||||
msleep(2000);
|
||||
|
||||
power_off();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
EPRINTF("You need a fully charged battery\nand connected to a wall adapter,\nto apply this fix!");
|
||||
|
||||
msleep(500);
|
||||
btn_wait();
|
||||
} */
|
||||
|
||||
/*void reset_pmic_fuel_gauge_charger_config()
|
||||
{
|
||||
int avgCurrent;
|
||||
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
gfx_printf(&gfx_con, "%k\nThis will wipe your battery stats completely!\n"
|
||||
"%kAnd it may not power on without physically\nremoving and re-inserting the battery.\n%k"
|
||||
"\nAre you really sure?%k\n", 0xFFFFDD00, 0xFFFF0000, 0xFFFFDD00, 0xFFCCCCCC);
|
||||
|
||||
gfx_puts(&gfx_con, "\nPress POWER to Continue.\nPress VOL to go to the menu.\n\n\n");
|
||||
u32 btn = btn_wait();
|
||||
if (btn & BTN_POWER)
|
||||
{
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
gfx_printf(&gfx_con, "%kKeep the USB cable connected!%k\n\n", 0xFFFFDD00, 0xFFCCCCCC);
|
||||
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
|
||||
|
||||
u8 value = 30;
|
||||
while (value > 0)
|
||||
{
|
||||
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf(&gfx_con, "%kWait... (%ds) %k", 0xFF888888, value, 0xFFCCCCCC);
|
||||
msleep(1000);
|
||||
value--;
|
||||
}
|
||||
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
|
||||
|
||||
//Check if still connected.
|
||||
max17050_get_property(MAX17050_AvgCurrent, &avgCurrent);
|
||||
if ((avgCurrent / 1000) < -10)
|
||||
EPRINTF("You need to be connected to a wall adapter\nor PC to apply this fix!");
|
||||
else
|
||||
{
|
||||
// Apply fix.
|
||||
bq24193_fake_battery_removal();
|
||||
gfx_printf(&gfx_con, "Done! \n"
|
||||
"%k1. Remove the USB cable\n"
|
||||
"2. Press POWER for 15s.\n"
|
||||
"3. Reconnect the USB to power-on!%k\n", 0xFFFFDD00, 0xFFCCCCCC);
|
||||
}
|
||||
msleep(500);
|
||||
btn_wait();
|
||||
}
|
||||
}*/
|
||||
|
||||
/*
|
||||
#include "../../modules/hekate_libsys_minerva/mtc.h"
|
||||
#include "../ianos/ianos.h"
|
||||
#include "../soc/fuse.h"
|
||||
#include "../soc/clock.h"
|
||||
|
||||
void minerva()
|
||||
{
|
||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
u32 curr_ram_idx = 0;
|
||||
|
||||
if (!sd_mount())
|
||||
return;
|
||||
|
||||
gfx_printf(&gfx_con, "-- Minerva Training Cell --\n\n");
|
||||
|
||||
// Set table to ram.
|
||||
mtc_cfg.mtc_table = NULL;
|
||||
mtc_cfg.sdram_id = (fuse_read_odm(4) >> 3) & 0x1F;
|
||||
ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)&mtc_cfg);
|
||||
|
||||
gfx_printf(&gfx_con, "\nStarting training process..\n\n");
|
||||
|
||||
// Get current frequency
|
||||
for (curr_ram_idx = 0; curr_ram_idx < 10; curr_ram_idx++)
|
||||
{
|
||||
if (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) == mtc_cfg.mtc_table[curr_ram_idx].clk_src_emc)
|
||||
break;
|
||||
}
|
||||
|
||||
// Change DRAM voltage.
|
||||
//i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD1, 42); //40 = (1000 * 1100 - 600000) / 12500 -> 1.1V
|
||||
|
||||
mtc_cfg.rate_from = mtc_cfg.mtc_table[curr_ram_idx].rate_khz;
|
||||
mtc_cfg.rate_to = 800000;
|
||||
mtc_cfg.train_mode = OP_TRAIN_SWITCH;
|
||||
gfx_printf(&gfx_con, "Training and switching %7d -> %7d\n\n", mtc_cfg.mtc_table[curr_ram_idx].rate_khz, 800000);
|
||||
ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)&mtc_cfg);
|
||||
|
||||
// Thefollowing frequency needs periodic training every 100ms.
|
||||
//msleep(200);
|
||||
|
||||
//mtc_cfg.rate_to = 1600000;
|
||||
//gfx_printf(&gfx_con, "Training and switching %7d -> %7d\n\n", mtc_cfg.current_emc_table->rate_khz, 1600000);
|
||||
//ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)&mtc_cfg);
|
||||
|
||||
//mtc_cfg.train_mode = OP_PERIODIC_TRAIN;
|
||||
|
||||
sd_unmount();
|
||||
|
||||
gfx_printf(&gfx_con, "Finished!");
|
||||
|
||||
btn_wait();
|
||||
}
|
||||
*/
|
||||
28
bootloader/frontend/fe_tools.h
Normal file
28
bootloader/frontend/fe_tools.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018 CTCaer
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _FE_TOOLS_H_
|
||||
#define _FE_TOOLS_H_
|
||||
|
||||
void dump_packages12();
|
||||
void fix_sd_all_attr();
|
||||
void fix_sd_nin_attr();
|
||||
void fix_battery_desync();
|
||||
void menu_autorcm();
|
||||
//void minerva();
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (c) 2018 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "../soc/i2c.h"
|
||||
#include "../soc/pmc.h"
|
||||
#include "../power/max77620.h"
|
||||
#include "../power/max7762x.h"
|
||||
#include "../soc/gpio.h"
|
||||
#include "../soc/pinmux.h"
|
||||
#include "../soc/clock.h"
|
||||
@@ -42,8 +43,8 @@ static void _display_dsi_wait(u32 timeout, u32 off, u32 mask)
|
||||
void display_init()
|
||||
{
|
||||
// Power on.
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_LDO0_CFG, 0xD0); // Configure to 1.2V.
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO7, 0x09);
|
||||
max77620_regulator_set_volt_and_flags(REGULATOR_LDO0, 1200000, MAX77620_POWER_MODE_NORMAL); // Configure to 1.2V.
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO7, MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH | MAX77620_CNFG_GPIO_DRV_PUSHPULL);
|
||||
|
||||
// Enable MIPI CAL, DSI, DISP1, HOST1X, UART_FST_MIPI_CAL, DSIA LP clocks.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x1010000;
|
||||
@@ -81,7 +82,7 @@ void display_init()
|
||||
gpio_write(GPIO_PORT_V, GPIO_PIN_1, GPIO_HIGH); // Backlight Enable enable.
|
||||
|
||||
// Config display interface and display.
|
||||
MIPI_CAL(0x60) = 0;
|
||||
MIPI_CAL(MIPI_CAL_MIPI_BIAS_PAD_CFG2) = 0;
|
||||
|
||||
exec_cfg((u32 *)CLOCK_BASE, _display_config_1, 4);
|
||||
exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_2, 94);
|
||||
@@ -94,11 +95,11 @@ void display_init()
|
||||
usleep(60000);
|
||||
|
||||
DSI(_DSIREG(DSI_BTA_TIMING)) = 0x50204;
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x337;
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x337; // MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE
|
||||
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
|
||||
_display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO);
|
||||
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x406;
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x406; // MIPI_DCS_GET_DISPLAY_ID
|
||||
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
|
||||
_display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO);
|
||||
|
||||
@@ -111,12 +112,12 @@ void display_init()
|
||||
if (_display_ver == 0x10)
|
||||
exec_cfg((u32 *)DSI_BASE, _display_config_4, 43);
|
||||
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x1105;
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x1105; // MIPI_DCS_EXIT_SLEEP_MODE
|
||||
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
|
||||
|
||||
usleep(180000);
|
||||
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x2905;
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x2905; // MIPI_DCS_SET_DISPLAY_ON
|
||||
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
|
||||
|
||||
usleep(20000);
|
||||
@@ -187,7 +188,7 @@ void display_end()
|
||||
display_backlight_brightness(0, 1000);
|
||||
|
||||
DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 1;
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x2805;
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x2805; // MIPI_DCS_SET_DISPLAY_OFF
|
||||
|
||||
DISPLAY_A(_DIREG(DC_CMD_STATE_ACCESS)) = READ_MUX | WRITE_MUX;
|
||||
DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0;
|
||||
@@ -200,7 +201,7 @@ void display_end()
|
||||
if (_display_ver == 0x10)
|
||||
exec_cfg((u32 *)DSI_BASE, _display_config_14, 22);
|
||||
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x1005;
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x1005; // MIPI_DCS_ENTER_SLEEP_MODE
|
||||
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
|
||||
|
||||
usleep(50000);
|
||||
|
||||
@@ -238,6 +238,10 @@
|
||||
#define DC_WINBUF_ADDR_H_OFFSET 0x806
|
||||
#define DC_WINBUF_ADDR_V_OFFSET 0x808
|
||||
#define DC_WINBUF_SURFACE_KIND 0x80B
|
||||
#define PITCH (0 << 0)
|
||||
#define TILED (1 << 0)
|
||||
#define BLOCK (2 << 0)
|
||||
#define BLOCK_HEIGHT(x) (((x) & 0x7) << 4)
|
||||
|
||||
/*! Display serial interface registers. */
|
||||
#define _DSIREG(reg) ((reg) * 4)
|
||||
@@ -342,9 +346,10 @@
|
||||
#define DSI_PAD_PREEMP_PU(x) (((x) & 0x3) << 0)
|
||||
|
||||
#define DSI_PAD_CONTROL_4 0x52
|
||||
|
||||
#define DSI_INIT_SEQ_DATA_15 0x5F
|
||||
|
||||
#define MIPI_CAL_MIPI_BIAS_PAD_CFG2 0x60
|
||||
|
||||
/*! Display backlight related PWM registers. */
|
||||
#define PWM_CONTROLLER_PWM_CSR 0x00
|
||||
|
||||
|
||||
@@ -287,12 +287,12 @@ static const cfg_op_t _display_config_7[10] = {
|
||||
|
||||
//MIPI CAL config.
|
||||
static const cfg_op_t _display_config_8[6] = {
|
||||
{0x18, 0},
|
||||
{2, 0xF3F10000},
|
||||
{0x16, 0},
|
||||
{0x18, 0},
|
||||
{0x18, 0x10010},
|
||||
{0x17, 0x300}
|
||||
{0x18, 0}, // MIPI_CAL_MIPI_BIAS_PAD_CFG2
|
||||
{0x02, 0xF3F10000}, // MIPI_CAL_CIL_MIPI_CAL_STATUS
|
||||
{0x16, 0}, // MIPI_CAL_MIPI_BIAS_PAD_CFG0
|
||||
{0x18, 0}, // MIPI_CAL_MIPI_BIAS_PAD_CFG2
|
||||
{0x18, 0x10010}, // MIPI_CAL_MIPI_BIAS_PAD_CFG2
|
||||
{0x17, 0x300} // MIPI_CAL_MIPI_BIAS_PAD_CFG1
|
||||
};
|
||||
|
||||
//DSI config.
|
||||
@@ -305,22 +305,22 @@ static const cfg_op_t _display_config_9[4] = {
|
||||
|
||||
//MIPI CAL config.
|
||||
static const cfg_op_t _display_config_10[16] = {
|
||||
{0xE, 0x200200},
|
||||
{0xF, 0x200200},
|
||||
{0x19, 0x200002},
|
||||
{0x1A, 0x200002},
|
||||
{5, 0},
|
||||
{6, 0},
|
||||
{7, 0},
|
||||
{8, 0},
|
||||
{9, 0},
|
||||
{0xA, 0},
|
||||
{0x10, 0},
|
||||
{0x11, 0},
|
||||
{0x1A, 0},
|
||||
{0x1C, 0},
|
||||
{0x1D, 0},
|
||||
{0, 0x2A000001}
|
||||
{0x0E, 0x200200}, // MIPI_CAL_DSIA_MIPI_CAL_CONFIG
|
||||
{0x0F, 0x200200}, // MIPI_CAL_DSIB_MIPI_CAL_CONFIG
|
||||
{0x19, 0x200002}, // MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2
|
||||
{0x1A, 0x200002}, // MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2
|
||||
{0x05, 0}, // MIPI_CAL_CILA_MIPI_CAL_CONFIG
|
||||
{0x06, 0}, // MIPI_CAL_CILB_MIPI_CAL_CONFIG
|
||||
{0x07, 0}, // MIPI_CAL_CILC_MIPI_CAL_CONFIG
|
||||
{0x08, 0}, // MIPI_CAL_CILD_MIPI_CAL_CONFIG
|
||||
{0x09, 0}, // MIPI_CAL_CILE_MIPI_CAL_CONFIG
|
||||
{0x0A, 0}, // MIPI_CAL_CILF_MIPI_CAL_CONFIG
|
||||
{0x10, 0}, // MIPI_CAL_DSIC_MIPI_CAL_CONFIG
|
||||
{0x11, 0}, // MIPI_CAL_DSID_MIPI_CAL_CONFIG
|
||||
{0x1A, 0}, // MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2
|
||||
{0x1C, 0}, // MIPI_CAL_DSIC_MIPI_CAL_CONFIG_2
|
||||
{0x1D, 0}, // MIPI_CAL_DSID_MIPI_CAL_CONFIG_2
|
||||
{0, 0x2A000001} // MIPI_CAL_DSIA_MIPI_CAL_CONFIG
|
||||
};
|
||||
|
||||
//Display A config.
|
||||
|
||||
@@ -21,6 +21,11 @@
|
||||
|
||||
#include "../../common/common_gfx.h"
|
||||
|
||||
#define EPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
|
||||
#define EPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
|
||||
#define WPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC)
|
||||
#define WPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC)
|
||||
|
||||
void gfx_init_ctxt(gfx_ctxt_t *ctxt, u32 *fb, u32 width, u32 height, u32 stride);
|
||||
void gfx_clear_grey(gfx_ctxt_t *ctxt, u8 color);
|
||||
void gfx_clear_partial_grey(gfx_ctxt_t *ctxt, u8 color, u32 pos_x, u32 height);
|
||||
@@ -43,4 +48,8 @@ void gfx_set_rect_rgb(gfx_ctxt_t *ctxt, const u8 *buf, u32 size_x, u32 size_y, u
|
||||
void gfx_set_rect_argb(gfx_ctxt_t *ctxt, const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
||||
void gfx_render_bmp_argb(gfx_ctxt_t *ctxt, const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
||||
|
||||
// Global gfx console and context.
|
||||
gfx_ctxt_t gfx_ctxt;
|
||||
gfx_con_t gfx_con;
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,13 +15,12 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "di.h"
|
||||
#include "tui.h"
|
||||
#include "../utils/btn.h"
|
||||
#include "../config/config.h"
|
||||
#include "../power/max17050.h"
|
||||
#include "../utils/util.h"
|
||||
#include "../config/config.h"
|
||||
#include "di.h"
|
||||
|
||||
#ifdef MENU_LOGO_ENABLE
|
||||
extern u8 *Kc_MENU_LOGO;
|
||||
@@ -206,8 +205,10 @@ void *tui_do_menu(gfx_con_t *con, menu_t *menu)
|
||||
return NULL;
|
||||
break;
|
||||
case MENT_HDLR_RE:
|
||||
ent->handler(ent->data);
|
||||
return NULL;
|
||||
ent->handler(ent);
|
||||
if (!ent->data)
|
||||
return NULL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
144
bootloader/hos/fss.c
Normal file
144
bootloader/hos/fss.c
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Atmosphère Fusée Secondary Storage parser.
|
||||
*
|
||||
* Copyright (c) 2019 CTCaer
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "fss.h"
|
||||
#include "hos.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../mem/heap.h"
|
||||
|
||||
#include "../gfx/gfx.h"
|
||||
#define DPRINTF(...)
|
||||
|
||||
#define FSS0_MAGIC 0x30535346
|
||||
#define CNT_TYPE_FSP 0
|
||||
#define CNT_TYPE_EXO 1
|
||||
#define CNT_TYPE_WBT 2
|
||||
#define CNT_TYPE_RBT 3
|
||||
#define CNT_TYPE_SP1 4
|
||||
#define CNT_TYPE_SP2 5
|
||||
#define CNT_TYPE_KIP 6
|
||||
#define CNT_TYPE_BMP 7
|
||||
|
||||
typedef struct _fss_t
|
||||
{
|
||||
u32 magic;
|
||||
u32 size;
|
||||
u32 crt0_off;
|
||||
u32 cnt_off;
|
||||
u32 cnt_count;
|
||||
u32 hos_ver;
|
||||
u32 version;
|
||||
u32 git_rev;
|
||||
} fss_t;
|
||||
|
||||
typedef struct _fss_content_t
|
||||
{
|
||||
u32 offset;
|
||||
u32 size;
|
||||
u32 type;
|
||||
u32 rsvd1;
|
||||
char name[0x10];
|
||||
} fss_content_t;
|
||||
|
||||
int parse_fss(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
FIL fp;
|
||||
|
||||
bool stock = false;
|
||||
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link)
|
||||
{
|
||||
if (!strcmp("stock", kv->key))
|
||||
if (kv->val[0] == '1')
|
||||
stock = true;
|
||||
}
|
||||
|
||||
if (stock && ctxt->pkg1_id->kb <= KB_FIRMWARE_VERSION_620)
|
||||
return 1;
|
||||
|
||||
if (f_open(&fp, value, FA_READ) != FR_OK)
|
||||
return 0;
|
||||
|
||||
ctxt->atmosphere = true;
|
||||
|
||||
void *fss = malloc(f_size(&fp));
|
||||
// Read header.
|
||||
f_read(&fp, fss, 0x400, NULL);
|
||||
|
||||
u32 fss_entry = *(u32 *)(fss + 4);
|
||||
fss_t *fss_meta = (fss_t *)(fss + fss_entry);
|
||||
|
||||
if (fss_meta->magic == FSS0_MAGIC)
|
||||
{
|
||||
gfx_printf(&gfx_con, "Found FSS0, Atmosphere %d.%d.%d-%08x\n"
|
||||
"Max HOS supported: %d.%d.%d\n"
|
||||
"Unpacking and loading components.. ",
|
||||
fss_meta->version >> 24, (fss_meta->version >> 16) & 0xFF, (fss_meta->version >> 8) & 0xFF, fss_meta->git_rev,
|
||||
fss_meta->hos_ver >> 24, (fss_meta->hos_ver >> 16) & 0xFF, (fss_meta->hos_ver >> 8) & 0xFF);
|
||||
|
||||
fss_content_t *curr_fss_cnt = (fss_content_t *)(fss + fss_meta->cnt_off);
|
||||
void *content;
|
||||
for (int i = 0; i < fss_meta->cnt_count; i++)
|
||||
{
|
||||
content = (void *)(fss + curr_fss_cnt[i].offset);
|
||||
if ((curr_fss_cnt[i].offset + curr_fss_cnt[i].size) > fss_meta->size)
|
||||
continue;
|
||||
|
||||
// Load content to launch context.
|
||||
switch (curr_fss_cnt[i].type)
|
||||
{
|
||||
case CNT_TYPE_KIP:
|
||||
if (stock)
|
||||
continue;
|
||||
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
|
||||
mkip1->kip1 = content;
|
||||
list_append(&ctxt->kip1_list, &mkip1->link);
|
||||
DPRINTF("Loaded %s.kip1 from FSS0 (size %08X)\n", curr_fss_cnt[i].name, curr_fss_cnt[i].size);
|
||||
break;
|
||||
case CNT_TYPE_EXO:
|
||||
ctxt->secmon_size = curr_fss_cnt[i].size;
|
||||
ctxt->secmon = content;
|
||||
break;
|
||||
case CNT_TYPE_WBT:
|
||||
ctxt->warmboot_size = curr_fss_cnt[i].size;
|
||||
ctxt->warmboot = content;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
// TODO: add more types?
|
||||
// case CNT_TYPE_SP1:
|
||||
// case CNT_TYPE_SP2:
|
||||
}
|
||||
|
||||
f_lseek(&fp, curr_fss_cnt[i].offset);
|
||||
f_read(&fp, content, curr_fss_cnt[i].size, NULL);
|
||||
}
|
||||
|
||||
gfx_printf(&gfx_con, "Done!\n");
|
||||
f_close(&fp);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
f_close(&fp);
|
||||
free(fss);
|
||||
|
||||
return 0;
|
||||
}
|
||||
24
bootloader/hos/fss.h
Normal file
24
bootloader/hos/fss.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2019 CTCaer
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _FSS_H_
|
||||
#define _FSS_H_
|
||||
|
||||
#include "hos.h"
|
||||
|
||||
int parse_fss(launch_ctxt_t *ctxt, const char *value);
|
||||
|
||||
#endif
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018 st4rk
|
||||
* Copyright (c) 2018 Ced2911
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
* Copyright (c) 2018 balika011
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -21,28 +21,26 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "hos.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
#include "../storage/nx_emmc.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "hos_config.h"
|
||||
#include "sept.h"
|
||||
#include "secmon_exo.h"
|
||||
#include "../config/config.h"
|
||||
#include "../gfx/di.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../mem/mc.h"
|
||||
#include "../sec/se.h"
|
||||
#include "../sec/se_t210.h"
|
||||
#include "../soc/pmc.h"
|
||||
#include "../soc/cluster.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../sec/tsec.h"
|
||||
#include "../utils/util.h"
|
||||
#include "pkg1.h"
|
||||
#include "pkg2.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../gfx/di.h"
|
||||
#include "../config/config.h"
|
||||
#include "../mem/mc.h"
|
||||
#include "../soc/cluster.h"
|
||||
#include "../soc/fuse.h"
|
||||
#include "../utils/dirlist.h"
|
||||
|
||||
#include "../soc/pmc.h"
|
||||
#include "../soc/smmu.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../storage/nx_emmc.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
#include "../utils/util.h"
|
||||
#include "../gfx/gfx.h"
|
||||
extern gfx_ctxt_t gfx_ctxt;
|
||||
extern gfx_con_t gfx_con;
|
||||
|
||||
extern hekate_config h_cfg;
|
||||
|
||||
extern void sd_unmount();
|
||||
@@ -50,48 +48,19 @@ extern void sd_unmount();
|
||||
//#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
|
||||
#define DPRINTF(...)
|
||||
|
||||
typedef struct _launch_ctxt_t
|
||||
#define PKG2_LOAD_ADDR 0xA9800000
|
||||
|
||||
// Secmon mailbox.
|
||||
#define SECMON_MB_ADDR 0x40002EF8
|
||||
#define SECMON7_MB_ADDR 0x400000F8
|
||||
typedef struct _secmon_mailbox_t
|
||||
{
|
||||
void *keyblob;
|
||||
|
||||
void *pkg1;
|
||||
const pkg1_id_t *pkg1_id;
|
||||
const pkg2_kernel_id_t *pkg2_kernel_id;
|
||||
|
||||
void *warmboot;
|
||||
u32 warmboot_size;
|
||||
void *secmon;
|
||||
u32 secmon_size;
|
||||
|
||||
void *pkg2;
|
||||
u32 pkg2_size;
|
||||
|
||||
void *kernel;
|
||||
u32 kernel_size;
|
||||
link_t kip1_list;
|
||||
char* kip1_patches;
|
||||
|
||||
bool svcperm;
|
||||
bool debugmode;
|
||||
bool atmosphere;
|
||||
} launch_ctxt_t;
|
||||
|
||||
typedef struct _merge_kip_t
|
||||
{
|
||||
void *kip1;
|
||||
link_t link;
|
||||
} merge_kip_t;
|
||||
|
||||
#define KB_FIRMWARE_VERSION_100_200 0
|
||||
#define KB_FIRMWARE_VERSION_300 1
|
||||
#define KB_FIRMWARE_VERSION_301 2
|
||||
#define KB_FIRMWARE_VERSION_400 3
|
||||
#define KB_FIRMWARE_VERSION_500 4
|
||||
#define KB_FIRMWARE_VERSION_600 5
|
||||
#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_600
|
||||
|
||||
// Exosphère magic "XBC0".
|
||||
#define MAGIC_EXOSPHERE 0x30434258
|
||||
// < 4.0.0 Signals - 0: Not ready, 1: BCT ready, 2: DRAM and pkg2 ready, 3: Continue boot.
|
||||
// >= 4.0.0 Signals - 0: Not ready, 1: BCT ready, 2: DRAM ready, 4: pkg2 ready and continue boot.
|
||||
u32 in;
|
||||
// Non-zero: Secmon ready.
|
||||
u32 out;
|
||||
} secmon_mailbox_t;
|
||||
|
||||
static const u8 keyblob_keyseeds[][0x10] = {
|
||||
{ 0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3 }, //1.0.0
|
||||
@@ -111,29 +80,35 @@ static const u8 master_keyseed_retail[0x10] =
|
||||
static const u8 console_keyseed[0x10] =
|
||||
{ 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78 };
|
||||
|
||||
static const u8 key8_keyseed[] =
|
||||
static const u8 package2_keyseed[] =
|
||||
{ 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7 };
|
||||
|
||||
static const u8 master_keyseed_4xx_5xx[0x10] =
|
||||
static const u8 master_keyseed_4xx_5xx_610[0x10] =
|
||||
{ 0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66 };
|
||||
|
||||
static const u8 master_keyseed_620[0x10] =
|
||||
{ 0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A };
|
||||
|
||||
static const u8 console_keyseed_4xx_5xx[0x10] =
|
||||
{ 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28 };
|
||||
|
||||
|
||||
static void _se_lock()
|
||||
static void _se_lock(bool lock_se)
|
||||
{
|
||||
for (u32 i = 0; i < 16; i++)
|
||||
if (lock_se)
|
||||
{
|
||||
for (u32 i = 0; i < 16; i++)
|
||||
se_key_acc_ctrl(i, 0x15);
|
||||
|
||||
for (u32 i = 0; i < 2; i++)
|
||||
se_rsa_acc_ctrl(i, 1);
|
||||
for (u32 i = 0; i < 2; i++)
|
||||
se_rsa_acc_ctrl(i, 1);
|
||||
SE(0x4) = 0; // Make this reg secure only.
|
||||
SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) = 0; // Make all key access regs secure only.
|
||||
SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) = 0; // Make all RSA access regs secure only.
|
||||
SE(SE_SECURITY_0) &= 0xFFFFFFFB; // Make access lock regs secure only.
|
||||
}
|
||||
|
||||
SE(0x4) = 0; // Make this reg secure only.
|
||||
SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) = 0; // Make all key access regs secure only.
|
||||
SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) = 0; // Make all RSA access regs secure only.
|
||||
SE(SE_SECURITY_0) &= 0xFFFFFFFB; // Make access lock regs secure only.
|
||||
memset((void *)IPATCH_BASE, 0, 13);
|
||||
memset((void *)IPATCH_BASE, 0, 14 * sizeof(u32));
|
||||
SB(SB_CSR) = 0x10; // Protected IROM enable.
|
||||
|
||||
// This is useful for documenting the bits in the SE config registers, so we can keep it around.
|
||||
@@ -166,9 +141,6 @@ void _pmc_scratch_lock(u32 kb)
|
||||
PMC(APBDEV_PMC_SEC_DISABLE7) = 0xFFFFFFFF;
|
||||
PMC(APBDEV_PMC_SEC_DISABLE8) = 0xFFAAFFFF;
|
||||
break;
|
||||
case KB_FIRMWARE_VERSION_400:
|
||||
case KB_FIRMWARE_VERSION_500:
|
||||
case KB_FIRMWARE_VERSION_600:
|
||||
default:
|
||||
PMC(APBDEV_PMC_SEC_DISABLE2) |= 0x3FCFFFF;
|
||||
PMC(APBDEV_PMC_SEC_DISABLE4) |= 0x3F3FFFFF;
|
||||
@@ -180,75 +152,140 @@ void _pmc_scratch_lock(u32 kb)
|
||||
}
|
||||
}
|
||||
|
||||
int keygen(u8 *keyblob, u32 kb, void *tsec_fw)
|
||||
void _sysctr0_reset()
|
||||
{
|
||||
u8 tmp[0x10];
|
||||
SYSCTR0(SYSCTR0_CNTFID0) = 19200000;
|
||||
SYSCTR0(SYSCTR0_CNTCR) = 0;
|
||||
SYSCTR0(SYSCTR0_COUNTERID0) = 0;
|
||||
SYSCTR0(SYSCTR0_COUNTERID1) = 0;
|
||||
SYSCTR0(SYSCTR0_COUNTERID2) = 0;
|
||||
SYSCTR0(SYSCTR0_COUNTERID3) = 0;
|
||||
SYSCTR0(SYSCTR0_COUNTERID4) = 0;
|
||||
SYSCTR0(SYSCTR0_COUNTERID5) = 0;
|
||||
SYSCTR0(SYSCTR0_COUNTERID6) = 0;
|
||||
SYSCTR0(SYSCTR0_COUNTERID7) = 0;
|
||||
SYSCTR0(SYSCTR0_COUNTERID8) = 0;
|
||||
SYSCTR0(SYSCTR0_COUNTERID9) = 0;
|
||||
SYSCTR0(SYSCTR0_COUNTERID10) = 0;
|
||||
SYSCTR0(SYSCTR0_COUNTERID11) = 0;
|
||||
}
|
||||
|
||||
int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
{
|
||||
u8 tmp[0x20];
|
||||
u32 retries = 0;
|
||||
|
||||
if (kb > KB_FIRMWARE_VERSION_MAX)
|
||||
return 0;
|
||||
|
||||
se_key_acc_ctrl(13, 0x15);
|
||||
se_key_acc_ctrl(14, 0x15);
|
||||
if (kb <= KB_FIRMWARE_VERSION_600)
|
||||
tsec_ctxt->size = 0xF00;
|
||||
else if (kb == KB_FIRMWARE_VERSION_620)
|
||||
tsec_ctxt->size = 0x2900;
|
||||
else
|
||||
tsec_ctxt->size = 0x3000;
|
||||
|
||||
// Get TSEC key.
|
||||
if (tsec_query(tmp, 1, tsec_fw) < 0)
|
||||
return 0;
|
||||
|
||||
se_aes_key_set(13, tmp, 0x10);
|
||||
|
||||
// Derive keyblob keys from TSEC+SBK.
|
||||
se_aes_crypt_block_ecb(13, 0, tmp, keyblob_keyseeds[0]);
|
||||
se_aes_unwrap_key(15, 14, tmp);
|
||||
se_aes_crypt_block_ecb(13, 0, tmp, keyblob_keyseeds[kb]);
|
||||
se_aes_unwrap_key(13, 14, tmp);
|
||||
|
||||
// Clear SBK.
|
||||
se_aes_key_clear(14);
|
||||
|
||||
//TODO: verify keyblob CMAC.
|
||||
//se_aes_unwrap_key(11, 13, cmac_keyseed);
|
||||
//se_aes_cmac(tmp, 0x10, 11, keyblob + 0x10, 0xA0);
|
||||
//if (!memcmp(keyblob, tmp, 0x10))
|
||||
// return 0;
|
||||
|
||||
se_aes_crypt_block_ecb(13, 0, tmp, cmac_keyseed);
|
||||
se_aes_unwrap_key(11, 13, cmac_keyseed);
|
||||
|
||||
// Decrypt keyblob and set keyslots.
|
||||
se_aes_crypt_ctr(13, keyblob + 0x20, 0x90, keyblob + 0x20, 0x90, keyblob + 0x10);
|
||||
se_aes_key_set(11, keyblob + 0x20 + 0x80, 0x10); // Package1 key.
|
||||
se_aes_key_set(12, keyblob + 0x20, 0x10);
|
||||
se_aes_key_set(13, keyblob + 0x20, 0x10);
|
||||
|
||||
se_aes_crypt_block_ecb(12, 0, tmp, master_keyseed_retail);
|
||||
|
||||
switch (kb)
|
||||
// Prepare smmu tsec page for 6.2.0.
|
||||
if (kb == KB_FIRMWARE_VERSION_620)
|
||||
{
|
||||
case KB_FIRMWARE_VERSION_100_200:
|
||||
case KB_FIRMWARE_VERSION_300:
|
||||
case KB_FIRMWARE_VERSION_301:
|
||||
se_aes_unwrap_key(13, 15, console_keyseed);
|
||||
se_aes_unwrap_key(12, 12, master_keyseed_retail);
|
||||
break;
|
||||
case KB_FIRMWARE_VERSION_400:
|
||||
se_aes_unwrap_key(13, 15, console_keyseed_4xx_5xx);
|
||||
se_aes_unwrap_key(15, 15, console_keyseed);
|
||||
se_aes_unwrap_key(14, 12, master_keyseed_4xx_5xx);
|
||||
se_aes_unwrap_key(12, 12, master_keyseed_retail);
|
||||
break;
|
||||
case KB_FIRMWARE_VERSION_500:
|
||||
case KB_FIRMWARE_VERSION_600:
|
||||
default:
|
||||
se_aes_unwrap_key(10, 15, console_keyseed_4xx_5xx);
|
||||
se_aes_unwrap_key(15, 15, console_keyseed);
|
||||
se_aes_unwrap_key(14, 12, master_keyseed_4xx_5xx);
|
||||
se_aes_unwrap_key(12, 12, master_keyseed_retail);
|
||||
break;
|
||||
u8 *tsec_paged = (u8 *)page_alloc(3);
|
||||
memcpy(tsec_paged, (void *)tsec_ctxt->fw, tsec_ctxt->size);
|
||||
tsec_ctxt->fw = tsec_paged;
|
||||
}
|
||||
|
||||
// Package2 key.
|
||||
se_key_acc_ctrl(8, 0x15);
|
||||
se_aes_unwrap_key(8, 12, key8_keyseed);
|
||||
// Get TSEC key.
|
||||
if (kb <= KB_FIRMWARE_VERSION_620)
|
||||
{
|
||||
while (tsec_query(tmp, kb, tsec_ctxt) < 0)
|
||||
{
|
||||
memset(tmp, 0x00, 0x20);
|
||||
retries++;
|
||||
|
||||
// We rely on racing conditions, make sure we cover even the unluckiest cases.
|
||||
if (retries > 15)
|
||||
{
|
||||
EPRINTF("\nFailed to get TSEC keys. Please try again.\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (kb >= KB_FIRMWARE_VERSION_700)
|
||||
se_aes_unwrap_key(8, 12, package2_keyseed);
|
||||
else if (kb == KB_FIRMWARE_VERSION_620)
|
||||
{
|
||||
// Set TSEC key.
|
||||
se_aes_key_set(12, tmp, 0x10);
|
||||
// Set TSEC root key.
|
||||
se_aes_key_set(13, tmp + 0x10, 0x10);
|
||||
|
||||
// Package2 key.
|
||||
se_aes_key_set(8, tmp + 0x10, 0x10);
|
||||
se_aes_unwrap_key(8, 8, master_keyseed_620);
|
||||
se_aes_unwrap_key(8, 8, master_keyseed_retail);
|
||||
se_aes_unwrap_key(8, 8, package2_keyseed);
|
||||
}
|
||||
else
|
||||
{
|
||||
se_key_acc_ctrl(13, 0x15);
|
||||
se_key_acc_ctrl(14, 0x15);
|
||||
|
||||
// Set TSEC key.
|
||||
se_aes_key_set(13, tmp, 0x10);
|
||||
|
||||
// Derive keyblob keys from TSEC+SBK.
|
||||
se_aes_crypt_block_ecb(13, 0, tmp, keyblob_keyseeds[0]);
|
||||
se_aes_unwrap_key(15, 14, tmp);
|
||||
se_aes_crypt_block_ecb(13, 0, tmp, keyblob_keyseeds[kb]);
|
||||
se_aes_unwrap_key(13, 14, tmp);
|
||||
|
||||
// Clear SBK.
|
||||
se_aes_key_clear(14);
|
||||
|
||||
//TODO: verify keyblob CMAC.
|
||||
//se_aes_unwrap_key(11, 13, cmac_keyseed);
|
||||
//se_aes_cmac(tmp, 0x10, 11, keyblob + 0x10, 0xA0);
|
||||
//if (!memcmp(keyblob, tmp, 0x10))
|
||||
// return 0;
|
||||
|
||||
se_aes_crypt_block_ecb(13, 0, tmp, cmac_keyseed);
|
||||
se_aes_unwrap_key(11, 13, cmac_keyseed);
|
||||
|
||||
// Decrypt keyblob and set keyslots.
|
||||
se_aes_crypt_ctr(13, keyblob + 0x20, 0x90, keyblob + 0x20, 0x90, keyblob + 0x10);
|
||||
se_aes_key_set(11, keyblob + 0x20 + 0x80, 0x10); // Package1 key.
|
||||
se_aes_key_set(12, keyblob + 0x20, 0x10);
|
||||
se_aes_key_set(13, keyblob + 0x20, 0x10);
|
||||
|
||||
se_aes_crypt_block_ecb(12, 0, tmp, master_keyseed_retail);
|
||||
|
||||
switch (kb)
|
||||
{
|
||||
case KB_FIRMWARE_VERSION_100_200:
|
||||
case KB_FIRMWARE_VERSION_300:
|
||||
case KB_FIRMWARE_VERSION_301:
|
||||
se_aes_unwrap_key(13, 15, console_keyseed);
|
||||
se_aes_unwrap_key(12, 12, master_keyseed_retail);
|
||||
break;
|
||||
case KB_FIRMWARE_VERSION_400:
|
||||
se_aes_unwrap_key(13, 15, console_keyseed_4xx_5xx);
|
||||
se_aes_unwrap_key(15, 15, console_keyseed);
|
||||
se_aes_unwrap_key(14, 12, master_keyseed_4xx_5xx_610);
|
||||
se_aes_unwrap_key(12, 12, master_keyseed_retail);
|
||||
break;
|
||||
case KB_FIRMWARE_VERSION_500:
|
||||
case KB_FIRMWARE_VERSION_600:
|
||||
se_aes_unwrap_key(10, 15, console_keyseed_4xx_5xx);
|
||||
se_aes_unwrap_key(15, 15, console_keyseed);
|
||||
se_aes_unwrap_key(14, 12, master_keyseed_4xx_5xx_610);
|
||||
se_aes_unwrap_key(12, 12, master_keyseed_retail);
|
||||
break;
|
||||
}
|
||||
|
||||
// Package2 key.
|
||||
se_key_acc_ctrl(8, 0x15);
|
||||
se_aes_unwrap_key(8, 12, package2_keyseed);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -262,16 +299,16 @@ static int _read_emmc_pkg1(launch_ctxt_t *ctxt)
|
||||
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4);
|
||||
|
||||
// Read package1.
|
||||
ctxt->pkg1 = (u8 *)malloc(0x40000);
|
||||
ctxt->pkg1 = (void *)malloc(0x40000);
|
||||
sdmmc_storage_set_mmc_partition(&storage, 1);
|
||||
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, ctxt->pkg1);
|
||||
ctxt->pkg1_id = pkg1_identify(ctxt->pkg1);
|
||||
if (!ctxt->pkg1_id)
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kUnknown package1,\nVersion (= '%s').%k\n", 0xFFFF0000, (char *)ctxt->pkg1 + 0x10, 0xFFCCCCCC);
|
||||
EPRINTF("Unknown pkg1 version.");
|
||||
goto out;
|
||||
}
|
||||
gfx_printf(&gfx_con, "Identified package1 ('%s'),\nKeyblob version %d\n\n", (char *)(ctxt->pkg1 + 0x10), ctxt->pkg1_id->kb);
|
||||
gfx_printf(&gfx_con, "Identified pkg1 and Keyblob %d\n\n", ctxt->pkg1_id->kb);
|
||||
|
||||
// Read the correct keyblob.
|
||||
ctxt->keyblob = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1);
|
||||
@@ -326,201 +363,13 @@ static u8 *_read_emmc_pkg2(launch_ctxt_t *ctxt)
|
||||
out:;
|
||||
nx_emmc_gpt_free(&gpt);
|
||||
sdmmc_storage_end(&storage);
|
||||
|
||||
return bctBuf;
|
||||
}
|
||||
|
||||
static int _config_warmboot(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
FIL fp;
|
||||
if (f_open(&fp, value, FA_READ) != FR_OK)
|
||||
return 0;
|
||||
ctxt->warmboot_size = f_size(&fp);
|
||||
ctxt->warmboot = malloc(ctxt->warmboot_size);
|
||||
f_read(&fp, ctxt->warmboot, ctxt->warmboot_size, NULL);
|
||||
f_close(&fp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_secmon(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
FIL fp;
|
||||
if (f_open(&fp, value, FA_READ) != FR_OK)
|
||||
return 0;
|
||||
ctxt->secmon_size = f_size(&fp);
|
||||
ctxt->secmon = malloc(ctxt->secmon_size);
|
||||
f_read(&fp, ctxt->secmon, ctxt->secmon_size, NULL);
|
||||
f_close(&fp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_kernel(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
FIL fp;
|
||||
if (f_open(&fp, value, FA_READ) != FR_OK)
|
||||
return 0;
|
||||
ctxt->kernel_size = f_size(&fp);
|
||||
ctxt->kernel = malloc(ctxt->kernel_size);
|
||||
f_read(&fp, ctxt->kernel, ctxt->kernel_size, NULL);
|
||||
f_close(&fp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
FIL fp;
|
||||
|
||||
if (!memcmp(value + strlen(value) - 1, "*", 1))
|
||||
{
|
||||
char *dir = (char *)malloc(256);
|
||||
memcpy(dir, value, strlen(value) + 1);
|
||||
|
||||
u32 dirlen = 0;
|
||||
dir[strlen(dir) - 2] = 0;
|
||||
char *filelist = dirlist(dir, "*.kip*");
|
||||
|
||||
memcpy(dir + strlen(dir), "/", 2);
|
||||
dirlen = strlen(dir);
|
||||
|
||||
u32 i = 0;
|
||||
if (filelist)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (!filelist[i * 256])
|
||||
break;
|
||||
|
||||
memcpy(dir + dirlen, &filelist[i * 256], strlen(&filelist[i * 256]) + 1);
|
||||
if (f_open(&fp, dir, FA_READ))
|
||||
{
|
||||
free(dir);
|
||||
free(filelist);
|
||||
|
||||
return 0;
|
||||
}
|
||||
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
|
||||
mkip1->kip1 = malloc(f_size(&fp));
|
||||
f_read(&fp, mkip1->kip1, f_size(&fp), NULL);
|
||||
DPRINTF("Loaded kip1 from SD (size %08X)\n", f_size(&fp));
|
||||
f_close(&fp);
|
||||
list_append(&ctxt->kip1_list, &mkip1->link);
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
free(dir);
|
||||
free(filelist);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (f_open(&fp, value, FA_READ))
|
||||
return 0;
|
||||
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
|
||||
mkip1->kip1 = malloc(f_size(&fp));
|
||||
f_read(&fp, mkip1->kip1, f_size(&fp), NULL);
|
||||
DPRINTF("Loaded kip1 from SD (size %08X)\n", f_size(&fp));
|
||||
f_close(&fp);
|
||||
list_append(&ctxt->kip1_list, &mkip1->link);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_svcperm(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
if (*value == '1')
|
||||
{
|
||||
DPRINTF("Disabled SVC verification\n");
|
||||
ctxt->svcperm = true;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_debugmode(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
if (*value == '1')
|
||||
{
|
||||
DPRINTF("Enabled Debug mode\n");
|
||||
ctxt->debugmode = true;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_atmosphere(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
if (*value == '1')
|
||||
{
|
||||
DPRINTF("Enabled atmosphere patching\n");
|
||||
ctxt->atmosphere = true;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_kip1patch(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
if (value == NULL)
|
||||
return 0;
|
||||
|
||||
int valueLen = strlen(value);
|
||||
if (!valueLen)
|
||||
return 0;
|
||||
|
||||
if (ctxt->kip1_patches == NULL)
|
||||
{
|
||||
ctxt->kip1_patches = malloc(valueLen + 1);
|
||||
memcpy(ctxt->kip1_patches, value, valueLen);
|
||||
ctxt->kip1_patches[valueLen] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
char *oldAlloc = ctxt->kip1_patches;
|
||||
int oldSize = strlen(oldAlloc);
|
||||
ctxt->kip1_patches = malloc(oldSize + 1 + valueLen + 1);
|
||||
memcpy(ctxt->kip1_patches, oldAlloc, oldSize);
|
||||
free(oldAlloc);
|
||||
oldAlloc = NULL;
|
||||
ctxt->kip1_patches[oldSize++] = ',';
|
||||
memcpy(&ctxt->kip1_patches[oldSize], value, valueLen);
|
||||
ctxt->kip1_patches[oldSize + valueLen] = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
typedef struct _cfg_handler_t
|
||||
{
|
||||
const char *key;
|
||||
int (*handler)(launch_ctxt_t *ctxt, const char *value);
|
||||
} cfg_handler_t;
|
||||
|
||||
static const cfg_handler_t _config_handlers[] = {
|
||||
{ "warmboot", _config_warmboot },
|
||||
{ "secmon", _config_secmon },
|
||||
{ "kernel", _config_kernel },
|
||||
{ "kip1", _config_kip1 },
|
||||
{ "kip1patch", _config_kip1patch },
|
||||
{ "fullsvcperm", _config_svcperm },
|
||||
{ "debugmode", _config_debugmode },
|
||||
{ "atmosphere", _config_atmosphere },
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
static int _config(launch_ctxt_t *ctxt, ini_sec_t *cfg)
|
||||
{
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)
|
||||
{
|
||||
for(u32 i = 0; _config_handlers[i].key; i++)
|
||||
{
|
||||
if (!strcmp(_config_handlers[i].key, kv->key))
|
||||
if (!_config_handlers[i].handler(ctxt, kv->val))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _free_launch_components(launch_ctxt_t *ctxt)
|
||||
{
|
||||
ini_free_section(ctxt->cfg);
|
||||
free(ctxt->keyblob);
|
||||
free(ctxt->pkg1);
|
||||
free(ctxt->pkg2);
|
||||
@@ -532,49 +381,94 @@ static void _free_launch_components(launch_ctxt_t *ctxt)
|
||||
|
||||
int hos_launch(ini_sec_t *cfg)
|
||||
{
|
||||
int bootStateDramPkg2 = 0;
|
||||
int bootStatePkg2Continue = 0;
|
||||
int exoFwNumber = 0;
|
||||
launch_ctxt_t ctxt;
|
||||
tsec_ctxt_t tsec_ctxt;
|
||||
volatile secmon_mailbox_t *secmon_mb;
|
||||
|
||||
memset(&ctxt, 0, sizeof(launch_ctxt_t));
|
||||
memset(&tsec_ctxt, 0, sizeof(tsec_ctxt_t));
|
||||
list_init(&ctxt.kip1_list);
|
||||
|
||||
ctxt.cfg = cfg;
|
||||
|
||||
if (!gfx_con.mute)
|
||||
gfx_clear_grey(&gfx_ctxt, 0x1B);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
// Try to parse config if present.
|
||||
if (cfg && !_config(&ctxt, cfg))
|
||||
return 0;
|
||||
|
||||
gfx_printf(&gfx_con, "Initializing...\n\n");
|
||||
|
||||
// Read package1 and the correct keyblob.
|
||||
if (!_read_emmc_pkg1(&ctxt))
|
||||
return 0;
|
||||
|
||||
gfx_printf(&gfx_con, "Loaded package1 and keyblob\n");
|
||||
// Try to parse config if present.
|
||||
if (ctxt.cfg && !parse_boot_config(&ctxt))
|
||||
{
|
||||
EPRINTF("Wrong ini cfg or missing files!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check if fuses lower than 4.0.0 and if yes apply NO Gamecard patch.
|
||||
if (h_cfg.autonogc && !(fuse_read_odm(7) & ~0xF) && ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_400)
|
||||
config_kip1patch(&ctxt, "nogc");
|
||||
|
||||
gfx_printf(&gfx_con, "Loaded pkg1 & keyblob\n");
|
||||
|
||||
// Generate keys.
|
||||
if (!h_cfg.se_keygen_done)
|
||||
if (!h_cfg.se_keygen_done || ctxt.pkg1_id->kb == KB_FIRMWARE_VERSION_620)
|
||||
{
|
||||
keygen(ctxt.keyblob, ctxt.pkg1_id->kb, (u8 *)ctxt.pkg1 + ctxt.pkg1_id->tsec_off);
|
||||
h_cfg.se_keygen_done = 1;
|
||||
tsec_ctxt.fw = (u8 *)ctxt.pkg1 + ctxt.pkg1_id->tsec_off;
|
||||
tsec_ctxt.pkg1 = ctxt.pkg1;
|
||||
tsec_ctxt.pkg11_off = ctxt.pkg1_id->pkg11_off;
|
||||
tsec_ctxt.secmon_base = ctxt.pkg1_id->secmon_base;
|
||||
|
||||
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run)
|
||||
{
|
||||
gfx_printf(&gfx_con, "Failed to run sept\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!keygen(ctxt.keyblob, ctxt.pkg1_id->kb, &tsec_ctxt))
|
||||
return 0;
|
||||
DPRINTF("Generated keys\n");
|
||||
|
||||
h_cfg.se_keygen_done = 1;
|
||||
}
|
||||
|
||||
// Decrypt and unpack package1 if we require parts of it.
|
||||
if (!ctxt.warmboot || !ctxt.secmon)
|
||||
{
|
||||
pkg1_decrypt(ctxt.pkg1_id, ctxt.pkg1);
|
||||
pkg1_unpack((void *)ctxt.pkg1_id->warmboot_base, (void *)ctxt.pkg1_id->secmon_base, NULL, ctxt.pkg1_id, ctxt.pkg1);
|
||||
gfx_printf(&gfx_con, "Decrypted and unpacked package1\n");
|
||||
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_600)
|
||||
pkg1_decrypt(ctxt.pkg1_id, ctxt.pkg1);
|
||||
|
||||
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_620)
|
||||
{
|
||||
pkg1_unpack((void *)ctxt.pkg1_id->warmboot_base, (void *)ctxt.pkg1_id->secmon_base, NULL, ctxt.pkg1_id, ctxt.pkg1);
|
||||
gfx_printf(&gfx_con, "Decrypted & unpacked pkg1\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
EPRINTF("No mandatory secmon or warmboot provided!");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Replace 'warmboot.bin' if requested.
|
||||
if (ctxt.warmboot)
|
||||
memcpy((void *)ctxt.pkg1_id->warmboot_base, ctxt.warmboot, ctxt.warmboot_size);
|
||||
else
|
||||
{
|
||||
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700)
|
||||
{
|
||||
EPRINTF("No warmboot provided!");
|
||||
return 0;
|
||||
}
|
||||
// Else we patch it to allow downgrading.
|
||||
patch_t *warmboot_patchset = ctxt.pkg1_id->warmboot_patchset;
|
||||
gfx_printf(&gfx_con, "%kPatching Warmboot%k\n", 0xFFFFBA00, 0xFFCCCCCC);
|
||||
for (u32 i = 0; warmboot_patchset[i].off != 0xFFFFFFFF; i++)
|
||||
*(vu32 *)(ctxt.pkg1_id->warmboot_base + warmboot_patchset[i].off) = warmboot_patchset[i].val;
|
||||
}
|
||||
// Set warmboot address in PMC if required.
|
||||
if (ctxt.pkg1_id->set_warmboot)
|
||||
PMC(APBDEV_PMC_SCRATCH1) = ctxt.pkg1_id->warmboot_base;
|
||||
@@ -582,7 +476,7 @@ int hos_launch(ini_sec_t *cfg)
|
||||
// Replace 'SecureMonitor' if requested.
|
||||
if (ctxt.secmon)
|
||||
memcpy((void *)ctxt.pkg1_id->secmon_base, ctxt.secmon, ctxt.secmon_size);
|
||||
else
|
||||
else if (ctxt.pkg1_id->secmon_patchset)
|
||||
{
|
||||
// Else we patch it to allow for an unsigned package2 and patched kernel.
|
||||
patch_t *secmon_patchset = ctxt.pkg1_id->secmon_patchset;
|
||||
@@ -591,17 +485,22 @@ int hos_launch(ini_sec_t *cfg)
|
||||
*(vu32 *)(ctxt.pkg1_id->secmon_base + secmon_patchset[i].off) = secmon_patchset[i].val;
|
||||
}
|
||||
|
||||
gfx_printf(&gfx_con, "Loaded warmboot.bin and secmon\n");
|
||||
gfx_printf(&gfx_con, "Loaded warmboot and secmon\n");
|
||||
|
||||
// Read package2.
|
||||
u8 *bootConfigBuf = _read_emmc_pkg2(&ctxt);
|
||||
if (!bootConfigBuf)
|
||||
return 0;
|
||||
|
||||
gfx_printf(&gfx_con, "Read package2\n");
|
||||
gfx_printf(&gfx_con, "Read pkg2\n");
|
||||
|
||||
// Decrypt package2 and parse KIP1 blobs in INI1 section.
|
||||
pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(ctxt.pkg2);
|
||||
if (!pkg2_hdr)
|
||||
{
|
||||
gfx_printf(&gfx_con, "Pkg2 decryption failed!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
LIST_INIT(kip1_info);
|
||||
pkg2_parse_kips(&kip1_info, pkg2_hdr);
|
||||
@@ -614,7 +513,7 @@ int hos_launch(ini_sec_t *cfg)
|
||||
ctxt.kernel = pkg2_hdr->data;
|
||||
ctxt.kernel_size = pkg2_hdr->sec_size[PKG2_SEC_KERNEL];
|
||||
|
||||
if (ctxt.svcperm || ctxt.debugmode || ctxt.atmosphere)
|
||||
if (!ctxt.stock && (ctxt.svcperm || ctxt.debugmode || ctxt.atmosphere))
|
||||
{
|
||||
u32 kernel_crc32 = crc32c(ctxt.kernel, ctxt.kernel_size);
|
||||
ctxt.pkg2_kernel_id = pkg2_identify(kernel_crc32);
|
||||
@@ -628,7 +527,7 @@ int hos_launch(ini_sec_t *cfg)
|
||||
for (u32 i = 0; kernel_patchset[i].id != 0xFFFFFFFF; i++)
|
||||
{
|
||||
if ((ctxt.svcperm && kernel_patchset[i].id == SVC_VERIFY_DS)
|
||||
|| (ctxt.debugmode && kernel_patchset[i].id == DEBUG_MODE_EN)
|
||||
|| (ctxt.debugmode && kernel_patchset[i].id == DEBUG_MODE_EN && !(ctxt.atmosphere && ctxt.secmon))
|
||||
|| (ctxt.atmosphere && kernel_patchset[i].id == ATM_GEN_PATCH))
|
||||
*(vu32 *)(ctxt.kernel + kernel_patchset[i].off) = kernel_patchset[i].val;
|
||||
else if (ctxt.atmosphere && kernel_patchset[i].id == ATM_ARR_PATCH)
|
||||
@@ -637,13 +536,15 @@ int hos_launch(ini_sec_t *cfg)
|
||||
for (u32 j = 0; j < kernel_patchset[i].val; j++)
|
||||
*(vu32 *)(ctxt.kernel + kernel_patchset[i].off + (j << 2)) = temp[j];
|
||||
}
|
||||
else if (kernel_patchset[i].id < SVC_VERIFY_DS)
|
||||
*(vu32 *)(ctxt.kernel + kernel_patchset[i].off) = kernel_patchset[i].val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Merge extra KIP1s into loaded ones.
|
||||
gfx_printf(&gfx_con, "%kPatching kernel initial processes%k\n", 0xFFFFBA00, 0xFFCCCCCC);
|
||||
gfx_printf(&gfx_con, "%kPatching kips%k\n", 0xFFFFBA00, 0xFFCCCCCC);
|
||||
LIST_FOREACH_ENTRY(merge_kip_t, mki, &ctxt.kip1_list, link)
|
||||
pkg2_merge_kip(&kip1_info, (pkg2_kip1_t *)mki->kip1);
|
||||
|
||||
@@ -651,34 +552,31 @@ int hos_launch(ini_sec_t *cfg)
|
||||
const char* unappliedPatch = pkg2_patch_kips(&kip1_info, ctxt.kip1_patches);
|
||||
if (unappliedPatch != NULL)
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kREQUESTED PATCH '%s' NOT APPLIED!%k\n", 0xFFFF0000, unappliedPatch, 0xFFCCCCCC);
|
||||
EPRINTFARGS("Failed to apply '%s'!", unappliedPatch);
|
||||
sd_unmount(); // Just exiting is not enough until pkg2_patch_kips stops modifying the string passed into it.
|
||||
while(1) {} // MUST stop here, because if user requests 'nogc' but it's not applied, their GC controller gets updated!
|
||||
|
||||
_free_launch_components(&ctxt);
|
||||
return 0; // MUST stop here, because if user requests 'nogc' but it's not applied, their GC controller gets updated!
|
||||
}
|
||||
|
||||
// Rebuild and encrypt package2.
|
||||
pkg2_build_encrypt((void *)0xA9800000, ctxt.kernel, ctxt.kernel_size, &kip1_info);
|
||||
gfx_printf(&gfx_con, "Rebuilt and loaded package2\n");
|
||||
pkg2_build_encrypt((void *)PKG2_LOAD_ADDR, ctxt.kernel, ctxt.kernel_size, &kip1_info);
|
||||
|
||||
// Unmount SD card.
|
||||
sd_unmount();
|
||||
gfx_printf(&gfx_con, "Rebuilt & loaded pkg2\n");
|
||||
|
||||
gfx_printf(&gfx_con, "\n%kBooting...%k\n", 0xFF96FF00, 0xFFCCCCCC);
|
||||
|
||||
// Clear pkg1/pkg2 keys.
|
||||
se_aes_key_clear(8);
|
||||
se_aes_key_clear(11);
|
||||
|
||||
// Final per firmware configuration.
|
||||
// Finalize per firmware keys.
|
||||
int bootStateDramPkg2 = 0;
|
||||
int bootStatePkg2Continue = 0;
|
||||
|
||||
switch (ctxt.pkg1_id->kb)
|
||||
{
|
||||
case KB_FIRMWARE_VERSION_100_200:
|
||||
if (!exoFwNumber)
|
||||
{
|
||||
if (!strcmp(ctxt.pkg1_id->id, "20161121183008"))
|
||||
exoFwNumber = 1;
|
||||
else
|
||||
exoFwNumber = 2;
|
||||
}
|
||||
case KB_FIRMWARE_VERSION_300:
|
||||
case KB_FIRMWARE_VERSION_301:
|
||||
if (ctxt.pkg1_id->kb == KB_FIRMWARE_VERSION_300)
|
||||
@@ -689,32 +587,20 @@ int hos_launch(ini_sec_t *cfg)
|
||||
se_key_acc_ctrl(13, 0xFF);
|
||||
bootStateDramPkg2 = 2;
|
||||
bootStatePkg2Continue = 3;
|
||||
if (!exoFwNumber)
|
||||
exoFwNumber = 3;
|
||||
break;
|
||||
case KB_FIRMWARE_VERSION_400:
|
||||
if (!exoFwNumber)
|
||||
exoFwNumber = 4;
|
||||
case KB_FIRMWARE_VERSION_500:
|
||||
if (!exoFwNumber)
|
||||
exoFwNumber = 5;
|
||||
case KB_FIRMWARE_VERSION_600:
|
||||
default:
|
||||
se_key_acc_ctrl(12, 0xFF);
|
||||
se_key_acc_ctrl(15, 0xFF);
|
||||
default:
|
||||
bootStateDramPkg2 = 2;
|
||||
bootStatePkg2Continue = 4;
|
||||
if (!exoFwNumber)
|
||||
exoFwNumber = 6;
|
||||
break;
|
||||
}
|
||||
|
||||
// Free allocated memory.
|
||||
ini_free_section(cfg);
|
||||
_free_launch_components(&ctxt);
|
||||
|
||||
// Clear BCT area for retail units and copy it over if dev unit.
|
||||
if (ctxt.pkg1_id->kb < KB_FIRMWARE_VERSION_600)
|
||||
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_500)
|
||||
{
|
||||
memset((void *)0x4003D000, 0, 0x3000);
|
||||
if ((fuse_read_odm(4) & 3) == 3)
|
||||
@@ -728,46 +614,59 @@ int hos_launch(ini_sec_t *cfg)
|
||||
}
|
||||
free(bootConfigBuf);
|
||||
|
||||
// Config Exosphère if booting Atmosphère.
|
||||
if (ctxt.atmosphere)
|
||||
{
|
||||
vu32 *mb_exo_magic = (vu32 *)0x40002E40;
|
||||
vu32 *mb_exo_fw_no = (vu32 *)0x40002E44;
|
||||
// Config Exosphère if booting full Atmosphère.
|
||||
if (ctxt.atmosphere && ctxt.secmon)
|
||||
config_exosphere(ctxt.pkg1_id->id, ctxt.pkg1_id->kb, (void *)ctxt.pkg1_id->warmboot_base, ctxt.pkg1, ctxt.stock);
|
||||
|
||||
*mb_exo_magic = MAGIC_EXOSPHERE;
|
||||
*mb_exo_fw_no = exoFwNumber;
|
||||
}
|
||||
// Unmount SD card.
|
||||
sd_unmount();
|
||||
|
||||
// Finalize MC carveout and lock SE before starting 'SecureMonitor'.
|
||||
mc_config_carveout_finalize();
|
||||
_se_lock();
|
||||
// Finalize MC carveout.
|
||||
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_301)
|
||||
mc_config_carveout();
|
||||
|
||||
//TODO: pkg1.1 locks PMC scratches, we can do that too at some point. For <4.0.0 after secmon?
|
||||
// Lock SE before starting 'SecureMonitor' if < 6.2.0, otherwise lock bootrom and ipatches.
|
||||
_se_lock(ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_600);
|
||||
|
||||
// Reset sysctr0 counters.
|
||||
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_620)
|
||||
_sysctr0_reset();
|
||||
|
||||
// < 4.0.0 pkg1.1 locks PMC scratches.
|
||||
//_pmc_scratch_lock(ctxt.pkg1_id->kb);
|
||||
|
||||
// < 4.0.0 Signals - 0: Nothing ready, 1: BCT ready, 2: DRAM and pkg2 ready, 3: Continue boot.
|
||||
// >= 4.0.0 Signals - 0: Nothing ready, 1: BCT ready, 2: DRAM ready, 4: pkg2 ready and continue boot.
|
||||
vu32 *mb_in = (vu32 *)0x40002EF8;
|
||||
// Non-zero: Secmon ready.
|
||||
vu32 *mb_out = (vu32 *)0x40002EFC;
|
||||
// Set secmon mailbox address.
|
||||
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700)
|
||||
secmon_mb = (secmon_mailbox_t *)SECMON7_MB_ADDR;
|
||||
else
|
||||
secmon_mb = (secmon_mailbox_t *)SECMON_MB_ADDR;
|
||||
|
||||
// Start from DRAM ready signal.
|
||||
*mb_in = bootStateDramPkg2;
|
||||
*mb_out = 0;
|
||||
// Start from DRAM ready signal and reset outgoing value.
|
||||
secmon_mb->in = bootStateDramPkg2;
|
||||
secmon_mb->out = 0;
|
||||
|
||||
// Free allocated memory.
|
||||
_free_launch_components(&ctxt);
|
||||
|
||||
// Disable display. This must be executed before secmon to provide support for all fw versions.
|
||||
display_end();
|
||||
|
||||
// Clear EMC_SCRATCH0.
|
||||
EMC(EMC_SCRATCH0) = 0;
|
||||
|
||||
// Wait for secmon to get ready.
|
||||
cluster_boot_cpu0(ctxt.pkg1_id->secmon_base);
|
||||
while (!*mb_out)
|
||||
if (smmu_is_used())
|
||||
smmu_exit();
|
||||
else
|
||||
cluster_boot_cpu0(ctxt.pkg1_id->secmon_base);
|
||||
while (!secmon_mb->out)
|
||||
usleep(1); // This only works when in IRAM or with a trained DRAM.
|
||||
|
||||
// Signal pkg2 ready and continue boot.
|
||||
*mb_in = bootStatePkg2Continue;
|
||||
secmon_mb->in = bootStatePkg2Continue;
|
||||
|
||||
// Halt ourselves in waitevent state and resume if there's JTAG activity.
|
||||
while (1)
|
||||
while (true)
|
||||
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = 0x50000000;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -17,10 +17,60 @@
|
||||
#ifndef _HOS_H_
|
||||
#define _HOS_H_
|
||||
|
||||
#include "pkg1.h"
|
||||
#include "pkg2.h"
|
||||
#include "../utils/types.h"
|
||||
#include "../config/ini.h"
|
||||
#include "../sec/tsec.h"
|
||||
|
||||
#define KB_FIRMWARE_VERSION_100_200 0
|
||||
#define KB_FIRMWARE_VERSION_300 1
|
||||
#define KB_FIRMWARE_VERSION_301 2
|
||||
#define KB_FIRMWARE_VERSION_400 3
|
||||
#define KB_FIRMWARE_VERSION_500 4
|
||||
#define KB_FIRMWARE_VERSION_600 5
|
||||
#define KB_FIRMWARE_VERSION_620 6
|
||||
#define KB_FIRMWARE_VERSION_700 7
|
||||
#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_700
|
||||
|
||||
#define HOS_PKG11_MAGIC 0x31314B50
|
||||
|
||||
typedef struct _launch_ctxt_t
|
||||
{
|
||||
void *keyblob;
|
||||
|
||||
void *pkg1;
|
||||
const pkg1_id_t *pkg1_id;
|
||||
const pkg2_kernel_id_t *pkg2_kernel_id;
|
||||
|
||||
void *warmboot;
|
||||
u32 warmboot_size;
|
||||
void *secmon;
|
||||
u32 secmon_size;
|
||||
|
||||
void *pkg2;
|
||||
u32 pkg2_size;
|
||||
|
||||
void *kernel;
|
||||
u32 kernel_size;
|
||||
link_t kip1_list;
|
||||
char* kip1_patches;
|
||||
|
||||
bool svcperm;
|
||||
bool debugmode;
|
||||
bool stock;
|
||||
bool atmosphere;
|
||||
|
||||
ini_sec_t *cfg;
|
||||
} launch_ctxt_t;
|
||||
|
||||
typedef struct _merge_kip_t
|
||||
{
|
||||
void *kip1;
|
||||
link_t link;
|
||||
} merge_kip_t;
|
||||
|
||||
int hos_launch(ini_sec_t *cfg);
|
||||
int keygen(u8 *keyblob, u32 kb, void *tsec_fw);
|
||||
int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt);
|
||||
|
||||
#endif
|
||||
|
||||
238
bootloader/hos/hos_config.c
Normal file
238
bootloader/hos/hos_config.c
Normal file
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "hos.h"
|
||||
#include "hos_config.h"
|
||||
#include "fss.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../utils/dirlist.h"
|
||||
|
||||
#include "../gfx/gfx.h"
|
||||
|
||||
//#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
|
||||
#define DPRINTF(...)
|
||||
|
||||
static int _config_warmboot(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
FIL fp;
|
||||
if (f_open(&fp, value, FA_READ) != FR_OK)
|
||||
return 0;
|
||||
ctxt->warmboot_size = f_size(&fp);
|
||||
ctxt->warmboot = malloc(ctxt->warmboot_size);
|
||||
f_read(&fp, ctxt->warmboot, ctxt->warmboot_size, NULL);
|
||||
f_close(&fp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_secmon(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
FIL fp;
|
||||
if (f_open(&fp, value, FA_READ) != FR_OK)
|
||||
return 0;
|
||||
ctxt->secmon_size = f_size(&fp);
|
||||
ctxt->secmon = malloc(ctxt->secmon_size);
|
||||
f_read(&fp, ctxt->secmon, ctxt->secmon_size, NULL);
|
||||
f_close(&fp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_kernel(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
FIL fp;
|
||||
if (f_open(&fp, value, FA_READ) != FR_OK)
|
||||
return 0;
|
||||
ctxt->kernel_size = f_size(&fp);
|
||||
ctxt->kernel = malloc(ctxt->kernel_size);
|
||||
f_read(&fp, ctxt->kernel, ctxt->kernel_size, NULL);
|
||||
f_close(&fp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
FIL fp;
|
||||
|
||||
if (!memcmp(value + strlen(value) - 1, "*", 1))
|
||||
{
|
||||
char *dir = (char *)malloc(256);
|
||||
memcpy(dir, value, strlen(value) + 1);
|
||||
|
||||
u32 dirlen = 0;
|
||||
dir[strlen(dir) - 2] = 0;
|
||||
char *filelist = dirlist(dir, "*.kip*", false);
|
||||
|
||||
memcpy(dir + strlen(dir), "/", 2);
|
||||
dirlen = strlen(dir);
|
||||
|
||||
u32 i = 0;
|
||||
if (filelist)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (!filelist[i * 256])
|
||||
break;
|
||||
|
||||
memcpy(dir + dirlen, &filelist[i * 256], strlen(&filelist[i * 256]) + 1);
|
||||
if (f_open(&fp, dir, FA_READ))
|
||||
{
|
||||
free(dir);
|
||||
free(filelist);
|
||||
|
||||
return 0;
|
||||
}
|
||||
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
|
||||
mkip1->kip1 = malloc(f_size(&fp));
|
||||
f_read(&fp, mkip1->kip1, f_size(&fp), NULL);
|
||||
DPRINTF("Loaded kip1 from SD (size %08X)\n", f_size(&fp));
|
||||
f_close(&fp);
|
||||
list_append(&ctxt->kip1_list, &mkip1->link);
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
free(dir);
|
||||
free(filelist);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (f_open(&fp, value, FA_READ))
|
||||
return 0;
|
||||
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
|
||||
mkip1->kip1 = malloc(f_size(&fp));
|
||||
f_read(&fp, mkip1->kip1, f_size(&fp), NULL);
|
||||
DPRINTF("Loaded kip1 from SD (size %08X)\n", f_size(&fp));
|
||||
f_close(&fp);
|
||||
list_append(&ctxt->kip1_list, &mkip1->link);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int config_kip1patch(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
if (value == NULL)
|
||||
return 0;
|
||||
|
||||
int valueLen = strlen(value);
|
||||
if (!valueLen)
|
||||
return 0;
|
||||
|
||||
if (ctxt->kip1_patches == NULL)
|
||||
{
|
||||
ctxt->kip1_patches = malloc(valueLen + 1);
|
||||
memcpy(ctxt->kip1_patches, value, valueLen);
|
||||
ctxt->kip1_patches[valueLen] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
char *oldAlloc = ctxt->kip1_patches;
|
||||
int oldSize = strlen(oldAlloc);
|
||||
ctxt->kip1_patches = malloc(oldSize + 1 + valueLen + 1);
|
||||
memcpy(ctxt->kip1_patches, oldAlloc, oldSize);
|
||||
free(oldAlloc);
|
||||
oldAlloc = NULL;
|
||||
ctxt->kip1_patches[oldSize++] = ',';
|
||||
memcpy(&ctxt->kip1_patches[oldSize], value, valueLen);
|
||||
ctxt->kip1_patches[oldSize + valueLen] = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_svcperm(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
if (*value == '1')
|
||||
{
|
||||
DPRINTF("Disabled SVC verification\n");
|
||||
ctxt->svcperm = true;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_debugmode(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
if (*value == '1')
|
||||
{
|
||||
DPRINTF("Enabled Debug mode\n");
|
||||
ctxt->debugmode = true;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_stock(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
if (*value == '1')
|
||||
{
|
||||
DPRINTF("Disabled all patching\n");
|
||||
ctxt->stock = true;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_atmosphere(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
if (*value == '1')
|
||||
{
|
||||
DPRINTF("Enabled atmosphere patching\n");
|
||||
ctxt->atmosphere = true;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_fss(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
return parse_fss(ctxt, value);
|
||||
}
|
||||
|
||||
typedef struct _cfg_handler_t
|
||||
{
|
||||
const char *key;
|
||||
int (*handler)(launch_ctxt_t *ctxt, const char *value);
|
||||
} cfg_handler_t;
|
||||
|
||||
static const cfg_handler_t _config_handlers[] = {
|
||||
{ "warmboot", _config_warmboot },
|
||||
{ "secmon", _config_secmon },
|
||||
{ "kernel", _config_kernel },
|
||||
{ "kip1", _config_kip1 },
|
||||
{ "kip1patch", config_kip1patch },
|
||||
{ "fullsvcperm", _config_svcperm },
|
||||
{ "debugmode", _config_debugmode },
|
||||
{ "stock", _config_stock },
|
||||
{ "atmosphere", _config_atmosphere },
|
||||
{ "fss0", _config_fss },
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
int parse_boot_config(launch_ctxt_t *ctxt)
|
||||
{
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link)
|
||||
{
|
||||
for(u32 i = 0; _config_handlers[i].key; i++)
|
||||
{
|
||||
if (!strcmp(_config_handlers[i].key, kv->key))
|
||||
if (!_config_handlers[i].handler(ctxt, kv->val))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
26
bootloader/hos/hos_config.h
Normal file
26
bootloader/hos/hos_config.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _HOS_CONFIG_H_
|
||||
#define _HOS_CONFIG_H_
|
||||
|
||||
#include "hos.h"
|
||||
|
||||
int parse_boot_config(launch_ctxt_t *ctxt);
|
||||
int config_kip1patch(launch_ctxt_t *ctxt, const char *value);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018 st4rk
|
||||
* Copyright (c) 2018 CTCaer
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
* Copyright (c) 2018 balika011
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -19,8 +20,11 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "pkg1.h"
|
||||
#include "../utils/aarch64_util.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../sec/se.h"
|
||||
#include "../utils/aarch64_util.h"
|
||||
|
||||
#define _NOPv7() 0xE320F000
|
||||
|
||||
#define SM_100_ADR 0x4002B020
|
||||
PATCHSET_DEF(_secmon_1_patchset,
|
||||
@@ -65,12 +69,55 @@ PATCHSET_DEF(_secmon_5_patchset,
|
||||
|
||||
PATCHSET_DEF(_secmon_6_patchset,
|
||||
// Patch package2 decryption and signature/hash checks.
|
||||
{ 0xDC8 + 0x820, _NOP() }, //package2 structure.
|
||||
{ 0xDC8 + 0x82C, _NOP() }, //Version.
|
||||
{ 0xDC8 + 0xE90, _NOP() }, //Header signature.
|
||||
{ 0xDC8 + 0x112C, _NOP() } //Sections SHA2.
|
||||
{ 0xDC8 + 0x820, _NOP() }, //package2 structure.
|
||||
{ 0xDC8 + 0x82C, _NOP() }, //Version.
|
||||
{ 0xDC8 + 0xE90, _NOP() }, //Header signature.
|
||||
{ 0xDC8 + 0x112C, _NOP() }, //Sections SHA2.
|
||||
// Fix sleep mode for debug.
|
||||
{ 0x1A68 + 0x3854, 0x94000E45 }, //gpio_config_for_uart.
|
||||
{ 0x1A68 + 0x3858, 0x97FFFC0F }, //clkrst_reboot_uarta.
|
||||
{ 0x1A68 + 0x385C, 0x52A00021 }, //MOV W1, #0x10000 ; baudrate.
|
||||
{ 0x1A68 + 0x3860, 0x2A1F03E0 }, //MOV W0, WZR ; uart_port -> A.
|
||||
{ 0x1A68 + 0x3864, 0x72984001 }, //MOVK W1, #0xC200 ; baudrate.
|
||||
{ 0x1A68 + 0x3868, 0x94000C8C }, //uart_configure.
|
||||
{ 0x1A68 + 0x3A6C, _NOP() } // warmboot UARTA cfg.
|
||||
);
|
||||
|
||||
PATCHSET_DEF(_secmon_620_patchset,
|
||||
// Patch package2 decryption and signature/hash checks.
|
||||
{ 0xDC8 + 0x604, _NOP() }, //package2 structure.
|
||||
{ 0xDC8 + 0x610, _NOP() }, //Version.
|
||||
{ 0xDC8 + 0xC74, _NOP() }, //Header signature.
|
||||
{ 0xDC8 + 0xF10, _NOP() }, //Sections SHA2.
|
||||
// Fix sleep mode for debug.
|
||||
{ 0x2AC8 + 0x3854, 0x94000F42 }, //gpio_config_for_uart.
|
||||
{ 0x2AC8 + 0x3858, 0x97FFFC0F }, //clkrst_reboot_uarta.
|
||||
{ 0x2AC8 + 0x385C, 0x52A00021 }, //MOV W1, #0x10000 ; baudrate.
|
||||
{ 0x2AC8 + 0x3860, 0x2A1F03E0 }, //MOV W0, WZR ; uart_port -> A.
|
||||
{ 0x2AC8 + 0x3864, 0x72984001 }, //MOVK W1, #0xC200 ; baudrate.
|
||||
{ 0x2AC8 + 0x3868, 0x94000D89 }, //uart_configure.
|
||||
{ 0x2AC8 + 0x3A6C, _NOP() } // warmboot UARTA cfg.
|
||||
);
|
||||
|
||||
PATCHSET_DEF(_warmboot_1_patchset,
|
||||
{ 0x4DC, _NOPv7() } // Fuse check.
|
||||
);
|
||||
|
||||
PATCHSET_DEF(_warmboot_2_patchset,
|
||||
{ 0x4DC, _NOPv7() } // Fuse check.
|
||||
);
|
||||
|
||||
PATCHSET_DEF(_warmboot_3_patchset,
|
||||
{ 0x4DC, _NOPv7() }, // Fuse check.
|
||||
{ 0x4F0, _NOPv7() } // Segment id check.
|
||||
);
|
||||
|
||||
PATCHSET_DEF(_warmboot_4_patchset,
|
||||
{ 0x544, _NOPv7() }, // Fuse check.
|
||||
{ 0x558, _NOPv7() } // Segment id check.
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* package1.1 header: <wb, ldr, sm>
|
||||
* package1.1 layout:
|
||||
@@ -81,22 +128,31 @@ PATCHSET_DEF(_secmon_6_patchset,
|
||||
* 4.0: {ldr, sm, wb} { 1, 2, 0 }
|
||||
* 5.0: {ldr, sm, wb} { 1, 2, 0 }
|
||||
* 6.0: {ldr, sm, wb} { 1, 2, 0 }
|
||||
* 6.2: {ldr, sm, wb} { 1, 2, 0 }
|
||||
* 7.0: {ldr, sm, wb} { 1, 2, 0 }
|
||||
*/
|
||||
|
||||
static const pkg1_id_t _pkg1_ids[] = {
|
||||
{ "20161121183008", 0, 0x1900, 0x3FE0, { 2, 1, 0 }, SM_100_ADR, 0x8000D000, true, _secmon_1_patchset }, //1.0.0 (Patched relocator)
|
||||
{ "20170210155124", 0, 0x1900, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_2_patchset }, //2.0.0 - 2.3.0
|
||||
{ "20170519101410", 1, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset }, //3.0.0
|
||||
{ "20170710161758", 2, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset }, //3.0.1 - 3.0.2
|
||||
{ "20170921172629", 3, 0x1800, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_4_patchset }, //4.0.0 - 4.1.0
|
||||
{ "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_5_patchset }, //5.0.0 - 5.1.0
|
||||
{ "20180802162753", 5, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_6_patchset }, //6.0.0 - 6.0.0
|
||||
{ "20161121183008", 0, 0x1900, 0x3FE0, { 2, 1, 0 }, SM_100_ADR, 0x8000D000, true, _secmon_1_patchset, _warmboot_1_patchset }, //1.0.0 (Patched relocator)
|
||||
{ "20170210155124", 0, 0x1900, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_2_patchset, _warmboot_2_patchset }, //2.0.0 - 2.3.0
|
||||
{ "20170519101410", 1, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset, _warmboot_3_patchset }, //3.0.0
|
||||
{ "20170710161758", 2, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset, _warmboot_3_patchset }, //3.0.1 - 3.0.2
|
||||
{ "20170921172629", 3, 0x1800, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_4_patchset, _warmboot_4_patchset }, //4.0.0 - 4.1.0
|
||||
{ "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_5_patchset, _warmboot_4_patchset }, //5.0.0 - 5.1.0
|
||||
{ "20180802162753", 5, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_6_patchset, _warmboot_4_patchset }, //6.0.0 - 6.1.0
|
||||
{ "20181107105733", 6, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_620_patchset, _warmboot_4_patchset }, //6.2.0
|
||||
{ "20181218175730", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, _warmboot_4_patchset }, //7.0.0
|
||||
{ "20190208150037", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, _warmboot_4_patchset }, //7.0.1
|
||||
{ NULL } //End.
|
||||
};
|
||||
|
||||
|
||||
const pkg1_id_t *pkg1_identify(u8 *pkg1)
|
||||
{
|
||||
char build_date[15];
|
||||
memcpy(build_date, (char *)(pkg1 + 0x10), 14);
|
||||
build_date[14] = 0;
|
||||
gfx_printf(&gfx_con, "Found pkg1 ('%s').\n\n", build_date);
|
||||
|
||||
for (u32 i = 0; _pkg1_ids[i].id; i++)
|
||||
if (!memcmp(pkg1 + 0x10, _pkg1_ids[i].id, 12))
|
||||
return &_pkg1_ids[i];
|
||||
|
||||
@@ -42,6 +42,7 @@ typedef struct _pkg1_id_t
|
||||
u32 warmboot_base;
|
||||
bool set_warmboot;
|
||||
patch_t *secmon_patchset;
|
||||
patch_t *warmboot_patchset;
|
||||
} pkg1_id_t;
|
||||
|
||||
typedef struct _pk11_hdr_t
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018 CTCaer
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
* Copyright (c) 2018 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -26,8 +26,6 @@
|
||||
|
||||
#include "../gfx/gfx.h"
|
||||
|
||||
extern gfx_con_t gfx_con;
|
||||
|
||||
/*#include "util.h"
|
||||
#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
|
||||
#define DEBUG_PRINTING*/
|
||||
@@ -44,6 +42,7 @@ extern gfx_con_t gfx_con;
|
||||
#define FREE_CODE_OFF_1ST_400 0x52890
|
||||
#define FREE_CODE_OFF_1ST_500 0x5C020
|
||||
#define FREE_CODE_OFF_1ST_600 0x5EE00
|
||||
#define FREE_CODE_OFF_1ST_700 0x5FEC0
|
||||
|
||||
#define ID_SND_OFF_100 0x23CC0
|
||||
#define ID_SND_OFF_200 0x3F134
|
||||
@@ -52,6 +51,7 @@ extern gfx_con_t gfx_con;
|
||||
#define ID_SND_OFF_400 0x2AF64
|
||||
#define ID_SND_OFF_500 0x2AD34
|
||||
#define ID_SND_OFF_600 0x2BB8C
|
||||
#define ID_SND_OFF_700 0x2D044
|
||||
|
||||
#define ID_RCV_OFF_100 0x219F0
|
||||
#define ID_RCV_OFF_200 0x3D1A8
|
||||
@@ -60,13 +60,14 @@ extern gfx_con_t gfx_con;
|
||||
#define ID_RCV_OFF_400 0x28F6C
|
||||
#define ID_RCV_OFF_500 0x28DAC
|
||||
#define ID_RCV_OFF_600 0x29B6C
|
||||
#define ID_RCV_OFF_700 0x2B23C
|
||||
|
||||
static u32 PRC_ID_SND_100[] =
|
||||
{
|
||||
0xA9BF2FEA, 0x2A0E03EB, 0xD37EF56B, 0xF86B6B8B, 0x92FFFFE9, 0x8A090168, 0xD2FFFFE9, 0x8A09016B,
|
||||
0xD2FFFFC9, 0xEB09017F, 0x54000040, 0xF9412948, 0xA8C12FEA
|
||||
};
|
||||
#define FREE_CODE_OFF_2ND_100 (FREE_CODE_OFF_1ST_100 + sizeof(PRC_ID_SND_100) + 4)
|
||||
#define FREE_CODE_OFF_2ND_100 (FREE_CODE_OFF_1ST_100 + sizeof(PRC_ID_SND_100) + sizeof(u32))
|
||||
static u32 PRC_ID_RCV_100[] =
|
||||
{
|
||||
0xA9BF2FEA, 0x2A1C03EA, 0xD37EF54A, 0xF86A69AA, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A,
|
||||
@@ -78,7 +79,7 @@ static u32 PRC_ID_SND_200[] =
|
||||
0xA9BF2FEA, 0x2A1803EB, 0xD37EF56B, 0xF86B6B8B, 0x92FFFFE9, 0x8A090168, 0xD2FFFFE9, 0x8A09016B,
|
||||
0xD2FFFFC9, 0xEB09017F, 0x54000040, 0xF9413148, 0xA8C12FEA
|
||||
};
|
||||
#define FREE_CODE_OFF_2ND_200 (FREE_CODE_OFF_1ST_200 + sizeof(PRC_ID_SND_200) + 4)
|
||||
#define FREE_CODE_OFF_2ND_200 (FREE_CODE_OFF_1ST_200 + sizeof(PRC_ID_SND_200) + sizeof(u32))
|
||||
static u32 PRC_ID_RCV_200[] =
|
||||
{
|
||||
0xA9BF2FEA, 0x2A0F03EA, 0xD37EF54A, 0xF9405FEB, 0xF86A696A, 0xF9407BEB, 0x92FFFFE9, 0x8A090148,
|
||||
@@ -90,7 +91,7 @@ static u32 PRC_ID_SND_300[] =
|
||||
0xA9BF2FEA, 0x2A1803EB, 0xD37EF56B, 0xF86B6B8B, 0x92FFFFE9, 0x8A090168, 0xD2FFFFE9, 0x8A09016B,
|
||||
0xD2FFFFC9, 0xEB09017F, 0x54000040, 0xF9415548, 0xA8C12FEA
|
||||
};
|
||||
#define FREE_CODE_OFF_2ND_300 (FREE_CODE_OFF_1ST_300 + sizeof(PRC_ID_SND_300) + 4)
|
||||
#define FREE_CODE_OFF_2ND_300 (FREE_CODE_OFF_1ST_300 + sizeof(PRC_ID_SND_300) + sizeof(u32))
|
||||
static u32 PRC_ID_RCV_300[] =
|
||||
{
|
||||
0xA9BF2FEA, 0x2A0F03EA, 0xD37EF54A, 0xF9405FEB, 0xF86A696A, 0xF9407BEB, 0x92FFFFE9, 0x8A090148,
|
||||
@@ -102,7 +103,7 @@ static u32 PRC_ID_SND_302[] =
|
||||
0xA9BF2FEA, 0x2A1803EB, 0xD37EF56B, 0xF86B6B8B, 0x92FFFFE9, 0x8A090168, 0xD2FFFFE9, 0x8A09016B,
|
||||
0xD2FFFFC9, 0xEB09017F, 0x54000040, 0xF9415548, 0xA8C12FEA
|
||||
};
|
||||
#define FREE_CODE_OFF_2ND_302 (FREE_CODE_OFF_1ST_302 + sizeof(PRC_ID_SND_302) + 4)
|
||||
#define FREE_CODE_OFF_2ND_302 (FREE_CODE_OFF_1ST_302 + sizeof(PRC_ID_SND_302) + sizeof(u32))
|
||||
static u32 PRC_ID_RCV_302[] =
|
||||
{
|
||||
0xA9BF2FEA, 0x2A0F03EA, 0xD37EF54A, 0xF9405FEB, 0xF86A696A, 0xF9407BEB, 0x92FFFFE9, 0x8A090148,
|
||||
@@ -114,7 +115,7 @@ static u32 PRC_ID_SND_400[] =
|
||||
0x2A1703EA, 0xD37EF54A, 0xF86A6B8A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9,
|
||||
0xEB09015F, 0x54000060, 0xF94053EA, 0xF9415948, 0xF94053EA
|
||||
};
|
||||
#define FREE_CODE_OFF_2ND_400 (FREE_CODE_OFF_1ST_400 + sizeof(PRC_ID_SND_400) + 4)
|
||||
#define FREE_CODE_OFF_2ND_400 (FREE_CODE_OFF_1ST_400 + sizeof(PRC_ID_SND_400) + sizeof(u32))
|
||||
static u32 PRC_ID_RCV_400[] =
|
||||
{
|
||||
0xF9403BED, 0x2A0E03EA, 0xD37EF54A, 0xF86A69AA, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A,
|
||||
@@ -126,7 +127,7 @@ static u32 PRC_ID_SND_500[] =
|
||||
0x2A1703EA, 0xD37EF54A, 0xF86A6B6A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9,
|
||||
0xEB09015F, 0x54000060, 0xF94043EA, 0xF9415948, 0xF94043EA
|
||||
};
|
||||
#define FREE_CODE_OFF_2ND_500 (FREE_CODE_OFF_1ST_500 + sizeof(PRC_ID_SND_500) + 4)
|
||||
#define FREE_CODE_OFF_2ND_500 (FREE_CODE_OFF_1ST_500 + sizeof(PRC_ID_SND_500) + sizeof(u32))
|
||||
static u32 PRC_ID_RCV_500[] =
|
||||
{
|
||||
0xF9403BED, 0x2A1503EA, 0xD37EF54A, 0xF86A69AA, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A,
|
||||
@@ -139,7 +140,7 @@ static u32 PRC_ID_SND_600[] =
|
||||
0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400308, 0xF9401D08, 0xAA1803E0,
|
||||
0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0
|
||||
};
|
||||
#define FREE_CODE_OFF_2ND_600 (FREE_CODE_OFF_1ST_600 + sizeof(PRC_ID_SND_600) + 4)
|
||||
#define FREE_CODE_OFF_2ND_600 (FREE_CODE_OFF_1ST_600 + sizeof(PRC_ID_SND_600) + sizeof(u32))
|
||||
static u32 PRC_ID_RCV_600[] =
|
||||
{
|
||||
0xA9BF2FEA, 0xF94043EB, 0x2A1503EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9,
|
||||
@@ -147,6 +148,20 @@ static u32 PRC_ID_RCV_600[] =
|
||||
0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0
|
||||
};
|
||||
|
||||
static u32 PRC_ID_SND_700[] =
|
||||
{
|
||||
0xA9BF2FEA, 0xF9403BEB, 0x2A1903EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9,
|
||||
0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF94002A8, 0xF9401D08, 0xAA1503E0,
|
||||
0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0
|
||||
};
|
||||
#define FREE_CODE_OFF_2ND_700 (FREE_CODE_OFF_1ST_700 + sizeof(PRC_ID_SND_700) + sizeof(u32))
|
||||
static u32 PRC_ID_RCV_700[] =
|
||||
{
|
||||
0xA9BF2FEA, 0xF9404FEB, 0x2A1603EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9,
|
||||
0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400368, 0xF9401D08, 0xAA1B03E0,
|
||||
0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0
|
||||
};
|
||||
|
||||
// Include kernel patches here, so we can utilize pkg1 id
|
||||
KERNEL_PATCHSET_DEF(_kernel_1_patchset,
|
||||
{ SVC_VERIFY_DS, 0x3764C, _NOP(), NULL }, // Disable SVC verifications
|
||||
@@ -155,11 +170,11 @@ KERNEL_PATCHSET_DEF(_kernel_1_patchset,
|
||||
{ ATM_GEN_PATCH, ID_SND_OFF_100, _B(ID_SND_OFF_100, FREE_CODE_OFF_1ST_100), NULL}, // Send process id branch.
|
||||
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_100, sizeof(PRC_ID_SND_100) >> 2, PRC_ID_SND_100}, // Send process id code.
|
||||
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_100 + sizeof(PRC_ID_SND_100), // Branch back and skip 1 instruction.
|
||||
_B(FREE_CODE_OFF_1ST_100 + sizeof(PRC_ID_SND_100), ID_SND_OFF_100 + 4), NULL},
|
||||
_B(FREE_CODE_OFF_1ST_100 + sizeof(PRC_ID_SND_100), ID_SND_OFF_100 + sizeof(u32)), NULL},
|
||||
{ ATM_GEN_PATCH, ID_RCV_OFF_100, _B(ID_RCV_OFF_100, FREE_CODE_OFF_2ND_100), NULL}, // Receive process id branch.
|
||||
{ ATM_ARR_PATCH, FREE_CODE_OFF_2ND_100, sizeof(PRC_ID_RCV_100) >> 2, PRC_ID_RCV_100}, // Receive process id code.
|
||||
{ ATM_GEN_PATCH, FREE_CODE_OFF_2ND_100 + sizeof(PRC_ID_RCV_100), // Branch back and skip 1 instruction.
|
||||
_B(FREE_CODE_OFF_2ND_100 + sizeof(PRC_ID_RCV_100), ID_RCV_OFF_100 + 4), NULL}
|
||||
_B(FREE_CODE_OFF_2ND_100 + sizeof(PRC_ID_RCV_100), ID_RCV_OFF_100 + sizeof(u32)), NULL}
|
||||
);
|
||||
|
||||
KERNEL_PATCHSET_DEF(_kernel_2_patchset,
|
||||
@@ -169,11 +184,11 @@ KERNEL_PATCHSET_DEF(_kernel_2_patchset,
|
||||
{ ATM_GEN_PATCH, ID_SND_OFF_200, _B(ID_SND_OFF_200, FREE_CODE_OFF_1ST_200), NULL}, // Send process id branch.
|
||||
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_200, sizeof(PRC_ID_SND_200) >> 2, PRC_ID_SND_200}, // Send process id code.
|
||||
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_200 + sizeof(PRC_ID_SND_200), // Branch back and skip 1 instruction.
|
||||
_B(FREE_CODE_OFF_1ST_200 + sizeof(PRC_ID_SND_200), ID_SND_OFF_200 + 4), NULL},
|
||||
_B(FREE_CODE_OFF_1ST_200 + sizeof(PRC_ID_SND_200), ID_SND_OFF_200 + sizeof(u32)), NULL},
|
||||
{ ATM_GEN_PATCH, ID_RCV_OFF_200, _B(ID_RCV_OFF_200, FREE_CODE_OFF_2ND_200), NULL}, // Receive process id branch.
|
||||
{ ATM_ARR_PATCH, FREE_CODE_OFF_2ND_200, sizeof(PRC_ID_RCV_200) >> 2, PRC_ID_RCV_200}, // Receive process id code.
|
||||
{ ATM_GEN_PATCH, FREE_CODE_OFF_2ND_200 + sizeof(PRC_ID_RCV_200), // Branch back and skip 1 instruction.
|
||||
_B(FREE_CODE_OFF_2ND_200 + sizeof(PRC_ID_RCV_200), ID_RCV_OFF_200 + 4), NULL}
|
||||
_B(FREE_CODE_OFF_2ND_200 + sizeof(PRC_ID_RCV_200), ID_RCV_OFF_200 + sizeof(u32)), NULL}
|
||||
);
|
||||
|
||||
KERNEL_PATCHSET_DEF(_kernel_3_patchset,
|
||||
@@ -183,11 +198,11 @@ KERNEL_PATCHSET_DEF(_kernel_3_patchset,
|
||||
{ ATM_GEN_PATCH, ID_SND_OFF_300, _B(ID_SND_OFF_300, FREE_CODE_OFF_1ST_300), NULL}, // Send process id branch.
|
||||
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_300, sizeof(PRC_ID_SND_300) >> 2, PRC_ID_SND_300}, // Send process id code.
|
||||
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_300 + sizeof(PRC_ID_SND_300), // Branch back and skip 1 instruction.
|
||||
_B(FREE_CODE_OFF_1ST_300 + sizeof(PRC_ID_SND_300), ID_SND_OFF_300 + 4), NULL},
|
||||
_B(FREE_CODE_OFF_1ST_300 + sizeof(PRC_ID_SND_300), ID_SND_OFF_300 + sizeof(u32)), NULL},
|
||||
{ ATM_GEN_PATCH, ID_RCV_OFF_300, _B(ID_RCV_OFF_300, FREE_CODE_OFF_2ND_300), NULL}, // Receive process id branch.
|
||||
{ ATM_ARR_PATCH, FREE_CODE_OFF_2ND_300, sizeof(PRC_ID_RCV_300) >> 2, PRC_ID_RCV_300}, // Receive process id code.
|
||||
{ ATM_GEN_PATCH, FREE_CODE_OFF_2ND_300 + sizeof(PRC_ID_RCV_300), // Branch back and skip 1 instruction.
|
||||
_B(FREE_CODE_OFF_2ND_300 + sizeof(PRC_ID_RCV_300), ID_RCV_OFF_300 + 4), NULL}
|
||||
_B(FREE_CODE_OFF_2ND_300 + sizeof(PRC_ID_RCV_300), ID_RCV_OFF_300 + sizeof(u32)), NULL}
|
||||
);
|
||||
|
||||
KERNEL_PATCHSET_DEF(_kernel_302_patchset,
|
||||
@@ -197,11 +212,11 @@ KERNEL_PATCHSET_DEF(_kernel_302_patchset,
|
||||
{ ATM_GEN_PATCH, ID_SND_OFF_302, _B(ID_SND_OFF_302, FREE_CODE_OFF_1ST_302), NULL}, // Send process id branch.
|
||||
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_302, sizeof(PRC_ID_SND_302) >> 2, PRC_ID_SND_302}, // Send process id code.
|
||||
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_302 + sizeof(PRC_ID_SND_302), // Branch back and skip 1 instruction.
|
||||
_B(FREE_CODE_OFF_1ST_302 + sizeof(PRC_ID_SND_302), ID_SND_OFF_302 + 4), NULL},
|
||||
_B(FREE_CODE_OFF_1ST_302 + sizeof(PRC_ID_SND_302), ID_SND_OFF_302 + sizeof(u32)), NULL},
|
||||
{ ATM_GEN_PATCH, ID_RCV_OFF_302, _B(ID_RCV_OFF_302, FREE_CODE_OFF_2ND_302), NULL}, // Receive process id branch.
|
||||
{ ATM_ARR_PATCH, FREE_CODE_OFF_2ND_302, sizeof(PRC_ID_RCV_302) >> 2, PRC_ID_RCV_302}, // Receive process id code.
|
||||
{ ATM_GEN_PATCH, FREE_CODE_OFF_2ND_302 + sizeof(PRC_ID_RCV_302), // Branch back and skip 1 instruction.
|
||||
_B(FREE_CODE_OFF_2ND_302 + sizeof(PRC_ID_RCV_302), ID_RCV_OFF_302 + 4), NULL}
|
||||
_B(FREE_CODE_OFF_2ND_302 + sizeof(PRC_ID_RCV_302), ID_RCV_OFF_302 + sizeof(u32)), NULL}
|
||||
);
|
||||
|
||||
KERNEL_PATCHSET_DEF(_kernel_4_patchset,
|
||||
@@ -211,39 +226,56 @@ KERNEL_PATCHSET_DEF(_kernel_4_patchset,
|
||||
{ ATM_GEN_PATCH, ID_SND_OFF_400, _B(ID_SND_OFF_400, FREE_CODE_OFF_1ST_400), NULL}, // Send process id branch.
|
||||
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_400, sizeof(PRC_ID_SND_400) >> 2, PRC_ID_SND_400}, // Send process id code.
|
||||
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_400 + sizeof(PRC_ID_SND_400), // Branch back and skip 2 instructions.
|
||||
_B(FREE_CODE_OFF_1ST_400 + sizeof(PRC_ID_SND_400), ID_SND_OFF_400 + 8), NULL},
|
||||
_B(FREE_CODE_OFF_1ST_400 + sizeof(PRC_ID_SND_400), ID_SND_OFF_400 + sizeof(u32) * 2), NULL},
|
||||
{ ATM_GEN_PATCH, ID_RCV_OFF_400, _B(ID_RCV_OFF_400, FREE_CODE_OFF_2ND_400), NULL}, // Receive process id branch.
|
||||
{ ATM_ARR_PATCH, FREE_CODE_OFF_2ND_400, sizeof(PRC_ID_RCV_400) >> 2, PRC_ID_RCV_400}, // Receive process id code.
|
||||
{ ATM_GEN_PATCH, FREE_CODE_OFF_2ND_400 + sizeof(PRC_ID_RCV_400), // Branch back and skip 1 instruction.
|
||||
_B(FREE_CODE_OFF_2ND_400 + sizeof(PRC_ID_RCV_400), ID_RCV_OFF_400 + 4), NULL}
|
||||
_B(FREE_CODE_OFF_2ND_400 + sizeof(PRC_ID_RCV_400), ID_RCV_OFF_400 + sizeof(u32)), NULL}
|
||||
);
|
||||
|
||||
KERNEL_PATCHSET_DEF(_kernel_5_patchset,
|
||||
{ SVC_GENERIC, 0x38C2C, _NOP(), NULL }, // Allow same process on svcControlCodeMemory.
|
||||
{ SVC_VERIFY_DS, 0x45E6C, _NOP(), NULL }, // Disable SVC verifications
|
||||
{ DEBUG_MODE_EN, 0x5513C, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch
|
||||
// Atmosphère kernel patches.
|
||||
{ ATM_GEN_PATCH, ID_SND_OFF_500, _B(ID_SND_OFF_500, FREE_CODE_OFF_1ST_500), NULL}, // Send process id branch.
|
||||
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_500, sizeof(PRC_ID_SND_500) >> 2, PRC_ID_SND_500}, // Send process id code.
|
||||
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_500 + sizeof(PRC_ID_SND_500), // Branch back and skip 2 instructions.
|
||||
_B(FREE_CODE_OFF_1ST_500 + sizeof(PRC_ID_SND_500), ID_SND_OFF_500 + 8), NULL},
|
||||
_B(FREE_CODE_OFF_1ST_500 + sizeof(PRC_ID_SND_500), ID_SND_OFF_500 + sizeof(u32) * 2), NULL},
|
||||
{ ATM_GEN_PATCH, ID_RCV_OFF_500, _B(ID_RCV_OFF_500, FREE_CODE_OFF_2ND_500), NULL}, // Receive process id branch.
|
||||
{ ATM_ARR_PATCH, FREE_CODE_OFF_2ND_500, sizeof(PRC_ID_RCV_500) >> 2, PRC_ID_RCV_500}, // Receive process id code.
|
||||
{ ATM_GEN_PATCH, FREE_CODE_OFF_2ND_500 + sizeof(PRC_ID_RCV_500), // Branch back and skip 2 instructions.
|
||||
_B(FREE_CODE_OFF_2ND_500 + sizeof(PRC_ID_RCV_500), ID_RCV_OFF_500 + 8), NULL}
|
||||
_B(FREE_CODE_OFF_2ND_500 + sizeof(PRC_ID_RCV_500), ID_RCV_OFF_500 + sizeof(u32) * 2), NULL}
|
||||
);
|
||||
|
||||
KERNEL_PATCHSET_DEF(_kernel_6_patchset,
|
||||
{ SVC_GENERIC, 0x3A8CC, _NOP(), NULL }, // Allow same process on svcControlCodeMemory.
|
||||
{ SVC_VERIFY_DS, 0x47EA0, _NOP(), NULL }, // Disable SVC verifications
|
||||
{ DEBUG_MODE_EN, 0x57548, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch
|
||||
// Atmosphère kernel patches.
|
||||
{ ATM_GEN_PATCH, ID_SND_OFF_600, _B(ID_SND_OFF_600, FREE_CODE_OFF_1ST_600), NULL}, // Send process id branch.
|
||||
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_600, sizeof(PRC_ID_SND_600) >> 2, PRC_ID_SND_600}, // Send process id code.
|
||||
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_600 + sizeof(PRC_ID_SND_600), // Branch back and skip 4 instructions.
|
||||
_B(FREE_CODE_OFF_1ST_600 + sizeof(PRC_ID_SND_600), ID_SND_OFF_600 + 0x10), NULL},
|
||||
_B(FREE_CODE_OFF_1ST_600 + sizeof(PRC_ID_SND_600), ID_SND_OFF_600 + sizeof(u32) * 4), NULL},
|
||||
{ ATM_GEN_PATCH, ID_RCV_OFF_600, _B(ID_RCV_OFF_600, FREE_CODE_OFF_2ND_600), NULL}, // Receive process id branch.
|
||||
{ ATM_ARR_PATCH, FREE_CODE_OFF_2ND_600, sizeof(PRC_ID_RCV_600) >> 2, PRC_ID_RCV_600}, // Receive process id code.
|
||||
{ ATM_GEN_PATCH, FREE_CODE_OFF_2ND_600 + sizeof(PRC_ID_RCV_600), // Branch back and skip 4 instructions.
|
||||
_B(FREE_CODE_OFF_2ND_600 + sizeof(PRC_ID_RCV_600), ID_RCV_OFF_600 + 0x10), NULL}
|
||||
_B(FREE_CODE_OFF_2ND_600 + sizeof(PRC_ID_RCV_600), ID_RCV_OFF_600 + sizeof(u32) * 4), NULL}
|
||||
);
|
||||
|
||||
KERNEL_PATCHSET_DEF(_kernel_7_patchset,
|
||||
{ SVC_GENERIC, 0x3C6E0, _NOP(), NULL }, // Allow same process on svcControlCodeMemory.
|
||||
{ SVC_VERIFY_DS, 0x49E5C, _NOP(), NULL }, // Disable SVC verifications
|
||||
{ DEBUG_MODE_EN, 0x581B0, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch
|
||||
// Atmosphère kernel patches.
|
||||
{ ATM_GEN_PATCH, ID_SND_OFF_700, _B(ID_SND_OFF_700, FREE_CODE_OFF_1ST_700), NULL}, // Send process id branch.
|
||||
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_700, sizeof(PRC_ID_SND_700) >> 2, PRC_ID_SND_700}, // Send process id code.
|
||||
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_700 + sizeof(PRC_ID_SND_700), // Branch back and skip 4 instructions.
|
||||
_B(FREE_CODE_OFF_1ST_700 + sizeof(PRC_ID_SND_700), ID_SND_OFF_700 + sizeof(u32) * 4), NULL},
|
||||
{ ATM_GEN_PATCH, ID_RCV_OFF_700, _B(ID_RCV_OFF_700, FREE_CODE_OFF_2ND_700), NULL}, // Receive process id branch.
|
||||
{ ATM_ARR_PATCH, FREE_CODE_OFF_2ND_700, sizeof(PRC_ID_RCV_700) >> 2, PRC_ID_RCV_700}, // Receive process id code.
|
||||
{ ATM_GEN_PATCH, FREE_CODE_OFF_2ND_700 + sizeof(PRC_ID_RCV_700), // Branch back and skip 4 instructions.
|
||||
_B(FREE_CODE_OFF_2ND_700 + sizeof(PRC_ID_RCV_700), ID_RCV_OFF_700 + sizeof(u32) * 4), NULL}
|
||||
);
|
||||
|
||||
static const pkg2_kernel_id_t _pkg2_kernel_ids[] =
|
||||
@@ -254,7 +286,8 @@ static const pkg2_kernel_id_t _pkg2_kernel_ids[] =
|
||||
{ 0xe0e8cdc4, _kernel_302_patchset }, //3.0.2
|
||||
{ 0x485d0157, _kernel_4_patchset }, //4.0.0 - 4.1.0
|
||||
{ 0xf3c363f2, _kernel_5_patchset }, //5.0.0 - 5.1.0
|
||||
{ 0x64ce1a44, _kernel_6_patchset }, //6.0.0
|
||||
{ 0x64ce1a44, _kernel_6_patchset }, //6.0.0 - 6.2.0
|
||||
{ 0x908175e1, _kernel_7_patchset }, //7.0.0
|
||||
{ 0, 0 } //End.
|
||||
};
|
||||
|
||||
@@ -275,195 +308,238 @@ enum kip_offset_section
|
||||
#define GET_KIP_PATCH_OFFSET(x) (x & KIP_PATCH_OFFSET_MASK)
|
||||
#define KPS(x) ((u32)(x) << KIP_PATCH_SECTION_SHIFT)
|
||||
|
||||
static kip1_patch_t _fs_nosigchk_100[] =
|
||||
static kip1_patch_t _fs_nosigchk_100[] =
|
||||
{
|
||||
{ KPS(KIP_TEXT) | 0x194A0, 4, "\xBA\x09\x00\x94", "\xE0\x03\x1F\x2A" },
|
||||
{ KPS(KIP_TEXT) | 0x3A79C, 4, "\xE0\x06\x00\x36", "\x1F\x20\x03\xD5" },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patchset_t _fs_patches_100[] =
|
||||
static kip1_patchset_t _fs_patches_100[] =
|
||||
{
|
||||
{ "nosigchk", _fs_nosigchk_100 },
|
||||
{ "nogc", NULL },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patch_t _fs_nosigchk_200[] =
|
||||
static kip1_patch_t _fs_nosigchk_200[] =
|
||||
{
|
||||
{ KPS(KIP_TEXT) | 0x15DF4, 4, "\xBC\x0A\x00\x94", "\xE0\x03\x1F\x2A" },
|
||||
{ KPS(KIP_TEXT) | 0x3F720, 4, "\x00\x06\x00\x36", "\x1F\x20\x03\xD5" },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patchset_t _fs_patches_200[] =
|
||||
static kip1_patchset_t _fs_patches_200[] =
|
||||
{
|
||||
{ "nosigchk", _fs_nosigchk_200 },
|
||||
{ "nogc", NULL },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patch_t _fs_nosigchk_210[] =
|
||||
static kip1_patch_t _fs_nosigchk_210[] =
|
||||
{
|
||||
{ KPS(KIP_TEXT) | 0x15F64, 4, "\xDF\x0A\x00\x94", "\xE0\x03\x1F\x2A" },
|
||||
{ KPS(KIP_TEXT) | 0x3FAF8, 4, "\x00\x06\x00\x36", "\x1F\x20\x03\xD5" },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patchset_t _fs_patches_210[] =
|
||||
static kip1_patchset_t _fs_patches_210[] =
|
||||
{
|
||||
{ "nosigchk", _fs_nosigchk_210 },
|
||||
{ "nogc", NULL },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patch_t _fs_nosigchk_300[] =
|
||||
static kip1_patch_t _fs_nosigchk_300[] =
|
||||
{
|
||||
{ KPS(KIP_TEXT) | 0x18E24, 4, "\x52\x0C\x00\x94", "\xE0\x03\x1F\x2A" },
|
||||
{ KPS(KIP_TEXT) | 0x49EC8, 4, "\x40\x04\x00\x36", "\x1F\x20\x03\xD5" },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patchset_t _fs_patches_300[] =
|
||||
static kip1_patchset_t _fs_patches_300[] =
|
||||
{
|
||||
{ "nosigchk", _fs_nosigchk_300 },
|
||||
{ "nogc", NULL },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patch_t _fs_nosigchk_30x[] =
|
||||
static kip1_patch_t _fs_nosigchk_30x[] =
|
||||
{
|
||||
{ KPS(KIP_TEXT) | 0x18E90, 4, "\x52\x0C\x00\x94", "\xE0\x03\x1F\x2A" },
|
||||
{ KPS(KIP_TEXT) | 0x49F34, 4, "\xE0\x03\x00\x36", "\x1F\x20\x03\xD5" },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patchset_t _fs_patches_30x[] =
|
||||
static kip1_patchset_t _fs_patches_30x[] =
|
||||
{
|
||||
{ "nosigchk", _fs_nosigchk_30x },
|
||||
{ "nogc", NULL },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patch_t _fs_nosigchk_4xx[] =
|
||||
static kip1_patch_t _fs_nosigchk_4xx[] =
|
||||
{
|
||||
{ KPS(KIP_TEXT) | 0x1C4FC, 4, "\x3C\x2F\x00\x94", "\xE0\x03\x1F\x2A" },
|
||||
{ KPS(KIP_TEXT) | 0x57934, 4, "\xE0\x02\x00\x36", "\x1F\x20\x03\xD5" },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patch_t _fs_nogc_40x[] =
|
||||
static kip1_patch_t _fs_nogc_40x[] =
|
||||
{
|
||||
{ KPS(KIP_TEXT) | 0xA3458, 4, "\x14\x40\x80\x72", "\x14\x80\x80\x72" },
|
||||
{ KPS(KIP_TEXT) | 0xAAB44, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patchset_t _fs_patches_40x[] =
|
||||
static kip1_patchset_t _fs_patches_40x[] =
|
||||
{
|
||||
{ "nosigchk", _fs_nosigchk_4xx },
|
||||
{ "nogc", _fs_nogc_40x },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patch_t _fs_nogc_410[] =
|
||||
static kip1_patch_t _fs_nogc_410[] =
|
||||
{
|
||||
{ KPS(KIP_TEXT) | 0xA34BC, 4, "\x14\x40\x80\x72", "\x14\x80\x80\x72" },
|
||||
{ KPS(KIP_TEXT) | 0xAABA8, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patchset_t _fs_patches_410[] =
|
||||
static kip1_patchset_t _fs_patches_410[] =
|
||||
{
|
||||
{ "nosigchk", _fs_nosigchk_4xx },
|
||||
{ "nogc", _fs_nogc_410 },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patch_t _fs_nosigchk_50x[] =
|
||||
static kip1_patch_t _fs_nosigchk_50x[] =
|
||||
{
|
||||
{ KPS(KIP_TEXT) | 0x22DDC, 4, "\x7D\x3E\x00\x94", "\xE0\x03\x1F\x2A" },
|
||||
{ KPS(KIP_TEXT) | 0x7D490, 4, "\x40\x03\x00\x36", "\x1F\x20\x03\xD5" },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patch_t _fs_nogc_50x[] =
|
||||
static kip1_patch_t _fs_nogc_50x[] =
|
||||
{
|
||||
{ KPS(KIP_TEXT) | 0xCF3C4, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" },
|
||||
{ KPS(KIP_TEXT) | 0xD73A0, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patchset_t _fs_patches_50x[] =
|
||||
static kip1_patchset_t _fs_patches_50x[] =
|
||||
{
|
||||
{ "nosigchk", _fs_nosigchk_50x },
|
||||
{ "nogc", _fs_nogc_50x },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patch_t _fs_nosigchk_510[] =
|
||||
static kip1_patch_t _fs_nosigchk_510[] =
|
||||
{
|
||||
{ KPS(KIP_TEXT) | 0x22E0C, 4, "\x85\x3E\x00\x94", "\xE0\x03\x1F\x2A" },
|
||||
{ KPS(KIP_TEXT) | 0x7D860, 4, "\x40\x03\x00\x36", "\x1F\x20\x03\xD5" },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patch_t _fs_nogc_510[] =
|
||||
static kip1_patch_t _fs_nogc_510[] =
|
||||
{
|
||||
{ KPS(KIP_TEXT) | 0xCF794, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" },
|
||||
{ KPS(KIP_TEXT) | 0xD7770, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patchset_t _fs_patches_510[] =
|
||||
static kip1_patchset_t _fs_patches_510[] =
|
||||
{
|
||||
{ "nosigchk", _fs_nosigchk_510 },
|
||||
{ "nogc", _fs_nogc_510 },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patch_t _fs_nosigchk_600[] =
|
||||
static kip1_patch_t _fs_nosigchk_600[] =
|
||||
{
|
||||
{ KPS(KIP_TEXT) | 0x712A8, 4, "\x8E\x3E\x00\x94", "\xE0\x03\x1F\x2A" },
|
||||
{ KPS(KIP_TEXT) | 0xEB08C, 4, "\xC0\x03\x00\x36", "\x1F\x20\x03\xD5" },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patch_t _fs_nosigchk_600_exfat[] =
|
||||
static kip1_patch_t _fs_nosigchk_600_exfat[] =
|
||||
{
|
||||
{ KPS(KIP_TEXT) | 0x7C9A8, 4, "\x8E\x3E\x00\x94", "\xE0\x03\x1F\x2A" },
|
||||
{ KPS(KIP_TEXT) | 0xF678C, 4, "\xC0\x03\x00\x36", "\x1F\x20\x03\xD5" },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patch_t _fs_nogc_600[] =
|
||||
static kip1_patch_t _fs_nogc_600[] =
|
||||
{
|
||||
{ KPS(KIP_TEXT) | 0x12CC20, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
|
||||
{ KPS(KIP_TEXT) | 0x1538F4, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patch_t _fs_nogc_600_exfat[] =
|
||||
static kip1_patch_t _fs_nogc_600_exfat[] =
|
||||
{
|
||||
{ KPS(KIP_TEXT) | 0x138320, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
|
||||
{ KPS(KIP_TEXT) | 0x15EFF4, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patchset_t _fs_patches_600[] =
|
||||
static kip1_patchset_t _fs_patches_600[] =
|
||||
{
|
||||
{ "nosigchk", _fs_nosigchk_600 },
|
||||
{ "nogc", _fs_nogc_600 },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patchset_t _fs_patches_600_exfat[] =
|
||||
static kip1_patchset_t _fs_patches_600_exfat[] =
|
||||
{
|
||||
{ "nosigchk", _fs_nosigchk_600_exfat },
|
||||
{ "nogc", _fs_nogc_600_exfat },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patch_t _fs_nosigchk_700[] =
|
||||
{
|
||||
{ KPS(KIP_TEXT) | 0x74A2C, 4, "\x31\x43\x00\x94", "\xE0\x03\x1F\x2A" },
|
||||
{ KPS(KIP_TEXT) | 0xF25E4, 4, "\xC0\x03\x00\x36", "\x1F\x20\x03\xD5" },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patch_t _fs_nosigchk_700_exfat[] =
|
||||
{
|
||||
{ KPS(KIP_TEXT) | 0x7FFDC, 4, "\x31\x43\x00\x94", "\xE0\x03\x1F\x2A" },
|
||||
{ KPS(KIP_TEXT) | 0xFDB94, 4, "\xC0\x03\x00\x36", "\x1F\x20\x03\xD5" },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patch_t _fs_nogc_700[] =
|
||||
{
|
||||
{ KPS(KIP_TEXT) | 0x134160, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
|
||||
{ KPS(KIP_TEXT) | 0x15BF04, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patch_t _fs_nogc_700_exfat[] =
|
||||
{
|
||||
{ KPS(KIP_TEXT) | 0x13F710, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
|
||||
{ KPS(KIP_TEXT) | 0x1674B4, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patchset_t _fs_patches_700[] =
|
||||
{
|
||||
{ "nosigchk", _fs_nosigchk_700 },
|
||||
{ "nogc", _fs_nogc_700 },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static kip1_patchset_t _fs_patches_700_exfat[] =
|
||||
{
|
||||
{ "nosigchk", _fs_nosigchk_700_exfat },
|
||||
{ "nogc", _fs_nogc_700_exfat },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
// SHA256 hashes.
|
||||
static kip1_id_t _kip_ids[] =
|
||||
{
|
||||
{ "FS", "\xde\x9f\xdd\xa4\x08\x5d\xd5\xfe\x68\xdc\xb2\x0b\x41\x09\x5b\xb4", _fs_patches_100 }, // FS 1.0.0
|
||||
@@ -487,7 +563,9 @@ static kip1_id_t _kip_ids[] =
|
||||
{ "FS", "\x1b\x82\xcb\x22\x18\x67\xcb\x52\xc4\x4a\x86\x9e\xa9\x1a\x1a\xdd", _fs_patches_600 }, // FS 6.0.0-4.0
|
||||
{ "FS", "\x96\x6a\xdd\x3d\x20\xb6\x27\x13\x2c\x5a\x8d\xa4\x9a\xc9\xd8\xdd", _fs_patches_600_exfat }, // FS 6.0.0-4.0 exfat
|
||||
{ "FS", "\x3a\x57\x4d\x43\x61\x86\x19\x1d\x17\x88\xeb\x2c\x0f\x07\x6b\x11", _fs_patches_600 }, // FS 6.0.0-5.0
|
||||
{ "FS", "\x33\x05\x53\xf6\xb5\xfb\x55\xc4\xc2\xd7\xb7\x36\x24\x02\x76\xb3", _fs_patches_600_exfat } // FS 6.0.0-5.0 exfat
|
||||
{ "FS", "\x33\x05\x53\xf6\xb5\xfb\x55\xc4\xc2\xd7\xb7\x36\x24\x02\x76\xb3", _fs_patches_600_exfat }, // FS 6.0.0-5.0 exfat
|
||||
{ "FS", "\x2A\xDB\xE9\x7E\x9B\x5F\x41\x77\x9E\xC9\x5F\xFE\x26\x99\xC9\x33", _fs_patches_700 }, // FS 7.0.0
|
||||
{ "FS", "\x2C\xCE\x65\x9C\xEC\x53\x6A\x8E\x4D\x91\xF3\xBE\x4B\x74\xBE\xD3", _fs_patches_700_exfat } // FS 7.0.0 exfat
|
||||
};
|
||||
|
||||
const pkg2_kernel_id_t *pkg2_identify(u32 id)
|
||||
@@ -571,7 +649,7 @@ int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp)
|
||||
memcpy(&hdr, ki->kip1, sizeof(hdr));
|
||||
|
||||
unsigned int newKipSize = sizeof(hdr);
|
||||
for (u32 sectIdx=0; sectIdx<KIP1_NUM_SECTIONS; sectIdx++)
|
||||
for (u32 sectIdx = 0; sectIdx < KIP1_NUM_SECTIONS; sectIdx++)
|
||||
{
|
||||
u32 sectCompBit = 1u << sectIdx;
|
||||
// For compressed, cant get actual decompressed size without doing it, so use safe "output size".
|
||||
@@ -584,7 +662,7 @@ int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp)
|
||||
pkg2_kip1_t* newKip = malloc(newKipSize);
|
||||
unsigned char* dstDataPtr = newKip->data;
|
||||
const unsigned char* srcDataPtr = ki->kip1->data;
|
||||
for (u32 sectIdx=0; sectIdx<KIP1_NUM_SECTIONS; sectIdx++)
|
||||
for (u32 sectIdx = 0; sectIdx < KIP1_NUM_SECTIONS; sectIdx++)
|
||||
{
|
||||
u32 sectCompBit = 1u << sectIdx;
|
||||
// Easy copy path for uncompressed or ones we dont want to uncompress.
|
||||
@@ -638,7 +716,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
|
||||
static const u32 MAX_NUM_PATCHES_REQUESTED = sizeof(u32)*8;
|
||||
char* patches[MAX_NUM_PATCHES_REQUESTED];
|
||||
|
||||
u32 numPatches=1;
|
||||
u32 numPatches = 1;
|
||||
patches[0] = patchNames;
|
||||
{
|
||||
for (char* p = patchNames; *p != 0; p++)
|
||||
@@ -646,7 +724,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
|
||||
if (*p == ',')
|
||||
{
|
||||
*p = 0;
|
||||
patches[numPatches++] = p+1;
|
||||
patches[numPatches++] = p + 1;
|
||||
if (numPatches >= MAX_NUM_PATCHES_REQUESTED)
|
||||
return "too_many_patches";
|
||||
}
|
||||
@@ -656,10 +734,10 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
|
||||
}
|
||||
|
||||
u32 patchesApplied = 0; // Bitset over patches.
|
||||
for (u32 i=0; i<numPatches; i++)
|
||||
for (u32 i = 0; i < numPatches; i++)
|
||||
{
|
||||
// Eliminate leading spaces.
|
||||
for (const char* p=patches[i]; *p!=0; p++)
|
||||
for (const char* p = patches[i]; *p != 0; p++)
|
||||
{
|
||||
if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
|
||||
patches[i]++;
|
||||
@@ -671,7 +749,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
|
||||
continue;
|
||||
|
||||
// Eliminate trailing spaces.
|
||||
for (int chIdx=valueLen-1; chIdx>=0; chIdx--)
|
||||
for (int chIdx=valueLen - 1; chIdx >= 0; chIdx--)
|
||||
{
|
||||
const char* p = patches[i] + chIdx;
|
||||
if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
|
||||
@@ -684,11 +762,11 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
|
||||
DPRINTF("Requested patch: '%s'\n", patches[i]);
|
||||
}
|
||||
|
||||
u32 shaBuf[32/sizeof(u32)];
|
||||
u32 shaBuf[32 / sizeof(u32)];
|
||||
LIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki, info, link)
|
||||
{
|
||||
shaBuf[0] = 0; // sha256 for this kip not yet calculated.
|
||||
for (u32 currKipIdx=0; currKipIdx<(sizeof(_kip_ids)/sizeof(_kip_ids[0])); currKipIdx++)
|
||||
for (u32 currKipIdx = 0; currKipIdx < (sizeof(_kip_ids) / sizeof(_kip_ids[0])); currKipIdx++)
|
||||
{
|
||||
if (strncmp((const char*)ki->kip1->name, _kip_ids[currKipIdx].name, sizeof(ki->kip1->name)) != 0)
|
||||
continue;
|
||||
@@ -697,7 +775,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
|
||||
kip1_patchset_t* currPatchset = _kip_ids[currKipIdx].patchset;
|
||||
while (currPatchset != NULL && currPatchset->name != NULL)
|
||||
{
|
||||
for (u32 i=0; i<numPatches; i++)
|
||||
for (u32 i = 0; i < numPatches; i++)
|
||||
{
|
||||
if (strcmp(currPatchset->name, patches[i]) != 0)
|
||||
{
|
||||
@@ -728,7 +806,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
|
||||
{
|
||||
if (currPatchset->patches != NULL)
|
||||
{
|
||||
for (u32 currEnabIdx=0; currEnabIdx<numPatches; currEnabIdx++)
|
||||
for (u32 currEnabIdx = 0; currEnabIdx < numPatches; currEnabIdx++)
|
||||
{
|
||||
if (strcmp(currPatchset->name, patches[currEnabIdx]))
|
||||
continue;
|
||||
@@ -752,13 +830,13 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
|
||||
if (!se_calc_sha256(shaBuf, ki->kip1, ki->size))
|
||||
memset(shaBuf, 0, sizeof(shaBuf));
|
||||
|
||||
DPRINTF("%dms %s KIP1 size %d hash %08X\n", (postDecompTime-preDecompTime)/1000, ki->kip1->name, (int)ki->size, __builtin_bswap32(shaBuf[0]));
|
||||
DPRINTF("%dms %s KIP1 size %d hash %08X\n", (postDecompTime-preDecompTime) / 1000, ki->kip1->name, (int)ki->size, __builtin_bswap32(shaBuf[0]));
|
||||
#endif
|
||||
|
||||
currPatchset = _kip_ids[currKipIdx].patchset;
|
||||
while (currPatchset != NULL && currPatchset->name != NULL)
|
||||
{
|
||||
for (u32 currEnabIdx=0; currEnabIdx<numPatches; currEnabIdx++)
|
||||
for (u32 currEnabIdx = 0; currEnabIdx < numPatches; currEnabIdx++)
|
||||
{
|
||||
if (strcmp(currPatchset->name, patches[currEnabIdx]))
|
||||
continue;
|
||||
@@ -772,7 +850,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
|
||||
}
|
||||
|
||||
unsigned char* kipSectData = ki->kip1->data;
|
||||
for (u32 currSectIdx=0; currSectIdx<KIP1_NUM_SECTIONS; currSectIdx++)
|
||||
for (u32 currSectIdx = 0; currSectIdx < KIP1_NUM_SECTIONS; currSectIdx++)
|
||||
{
|
||||
if (bitsAffected & (1u << currSectIdx))
|
||||
{
|
||||
@@ -806,7 +884,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
|
||||
}
|
||||
}
|
||||
|
||||
for (u32 i=0; i<numPatches; i++)
|
||||
for (u32 i = 0; i < numPatches; i++)
|
||||
{
|
||||
if ((patchesApplied & (1u << i)) == 0)
|
||||
return patches[i];
|
||||
@@ -899,4 +977,3 @@ DPRINTF("INI1 encrypted\n");
|
||||
memset(hdr->ctr, 0 , 0x10);
|
||||
*(u32 *)hdr->ctr = 0x100 + sizeof(pkg2_hdr_t) + kernel_size + ini1_size;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,8 +44,10 @@ typedef struct _kernel_patch_t
|
||||
|
||||
enum
|
||||
{
|
||||
// Generic instruction patches
|
||||
SVC_VERIFY_DS = 0x10, // 0x0-0xF are RESERVED.
|
||||
// Always applied.
|
||||
SVC_GENERIC = 0,
|
||||
// Generic instruction patches.
|
||||
SVC_VERIFY_DS = 0x10,
|
||||
DEBUG_MODE_EN,
|
||||
ATM_GEN_PATCH,
|
||||
// >4 bytes patches. Value is a pointer of a u32 array.
|
||||
@@ -115,16 +117,16 @@ typedef struct _pkg2_kernel_id_t
|
||||
|
||||
typedef struct _kip1_patch_t
|
||||
{
|
||||
u32 offset; //section+offset of patch to apply
|
||||
u32 length; //in bytes, 0 means last patch
|
||||
const char* srcData; //that must match
|
||||
const char* dstData; //that it gets replaced by
|
||||
u32 offset; // section+offset of patch to apply.
|
||||
u32 length; // In bytes, 0 means last patch.
|
||||
const char* srcData; // That must match.
|
||||
const char* dstData; // That it gets replaced by.
|
||||
} kip1_patch_t;
|
||||
|
||||
typedef struct _kip1_patchset_t
|
||||
{
|
||||
const char* name; //NULL means end
|
||||
kip1_patch_t* patches; //NULL means not necessary
|
||||
const char* name; // NULL means end.
|
||||
kip1_patch_t* patches; // NULL means not necessary.
|
||||
} kip1_patchset_t;
|
||||
|
||||
typedef struct _kip1_id_t
|
||||
|
||||
118
bootloader/hos/secmon_exo.c
Normal file
118
bootloader/hos/secmon_exo.c
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2019 CTCaer
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "hos.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../soc/fuse.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
#include "../utils/types.h"
|
||||
|
||||
typedef struct _exo_cfg_t
|
||||
{
|
||||
vu32 magic;
|
||||
vu32 fwno;
|
||||
vu32 flags;
|
||||
vu32 rsvd;
|
||||
} exo_cfg_t;
|
||||
|
||||
typedef struct _atm_meta_t
|
||||
{
|
||||
uint32_t magic;
|
||||
uint32_t fwno;
|
||||
} wb_cfg_t;
|
||||
|
||||
#define ATM_WB_HEADER_OFF 0x244
|
||||
#define ATM_WB_MAGIC 0x30544257
|
||||
|
||||
// Exosphère mailbox defines.
|
||||
#define EXO_CFG_DEPR_ADDR 0x40002E40 // Deprecated.
|
||||
#define EXO_CFG_ADDR 0x8000F000
|
||||
#define EXO_MAGIC_DEPR_VAL 0x31434258
|
||||
#define EXO_MAGIC_VAL 0x304F5845
|
||||
#define EXO_FLAG_620_KGN (1 << 0)
|
||||
#define EXO_FLAG_DBG_PRIV (1 << 1)
|
||||
#define EXO_FLAG_DBG_USER (1 << 2)
|
||||
|
||||
void config_exosphere(const char *id, u32 kb, void *warmboot, void *pkg1, bool stock)
|
||||
{
|
||||
u32 exoFwNo = 0;
|
||||
u32 exoFlags = 0;
|
||||
|
||||
volatile exo_cfg_t *exo_cfg_depr = (exo_cfg_t *)EXO_CFG_DEPR_ADDR;
|
||||
volatile exo_cfg_t *exo_cfg = (exo_cfg_t *)EXO_CFG_ADDR;
|
||||
|
||||
switch (kb)
|
||||
{
|
||||
case KB_FIRMWARE_VERSION_100_200:
|
||||
if (!strcmp(id, "20161121183008"))
|
||||
exoFwNo = 1;
|
||||
else
|
||||
exoFwNo = 2;
|
||||
break;
|
||||
case KB_FIRMWARE_VERSION_300:
|
||||
exoFwNo = 3;
|
||||
break;
|
||||
default:
|
||||
exoFwNo = kb + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (kb == KB_FIRMWARE_VERSION_620)
|
||||
exoFlags |= EXO_FLAG_620_KGN;
|
||||
|
||||
// To avoid problems, make private debug mode always on if not semi-stock.
|
||||
if (!stock)
|
||||
exoFlags |= EXO_FLAG_DBG_PRIV;
|
||||
|
||||
// Set mailbox values.
|
||||
exo_cfg_depr->magic = EXO_MAGIC_VAL;
|
||||
exo_cfg->magic = EXO_MAGIC_VAL;
|
||||
|
||||
exo_cfg_depr->fwno = exoFwNo;
|
||||
exo_cfg->fwno = exoFwNo;
|
||||
|
||||
exo_cfg_depr->flags = exoFlags;
|
||||
exo_cfg->flags = exoFlags;
|
||||
|
||||
// If warmboot is lp0fw, add in RSA modulus.
|
||||
volatile wb_cfg_t *wb_cfg = (wb_cfg_t *)(warmboot + ATM_WB_HEADER_OFF);
|
||||
|
||||
if (wb_cfg->magic == ATM_WB_MAGIC)
|
||||
{
|
||||
wb_cfg->fwno = exoFwNo;
|
||||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
|
||||
// Set warmboot binary rsa modulus.
|
||||
u8 *rsa_mod = (u8 *)malloc(512);
|
||||
|
||||
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4);
|
||||
sdmmc_storage_set_mmc_partition(&storage, 1);
|
||||
sdmmc_storage_read(&storage, 1, 1, rsa_mod);
|
||||
sdmmc_storage_end(&storage);
|
||||
|
||||
// Patch AutoRCM out.
|
||||
if ((fuse_read_odm(4) & 3) != 3)
|
||||
rsa_mod[0x10] = 0xF7;
|
||||
else
|
||||
rsa_mod[0x10] = 0x37;
|
||||
|
||||
memcpy(warmboot + 0x10, rsa_mod + 0x10, 0x100);
|
||||
}
|
||||
}
|
||||
24
bootloader/hos/secmon_exo.h
Normal file
24
bootloader/hos/secmon_exo.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2019 CTCaer
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _SECMON_EXO_H_
|
||||
#define _SECMON_EXO_H_
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
void config_exosphere(const char *id, u32 kb, void *warmboot, void *pkg1, bool stock);
|
||||
|
||||
#endif
|
||||
206
bootloader/hos/sept.c
Normal file
206
bootloader/hos/sept.c
Normal file
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright (c) 2019 CTCaer
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "hos.h"
|
||||
#include "sept.h"
|
||||
#include "../config/config.h"
|
||||
#include "../gfx/di.h"
|
||||
#include "../ianos/ianos.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../soc/pmc.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../storage/nx_emmc.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
#include "../utils/btn.h"
|
||||
#include "../utils/types.h"
|
||||
|
||||
#include "../gfx/gfx.h"
|
||||
|
||||
#define RELOC_META_OFF 0x7C
|
||||
#define PATCHED_RELOC_SZ 0x94
|
||||
|
||||
#define WB_RST_ADDR 0x40010ED0
|
||||
#define WB_RST_SIZE 0x30
|
||||
|
||||
u8 warmboot_reboot[] = {
|
||||
0x14, 0x00, 0x9F, 0xE5, // LDR R0, =0x7000E450
|
||||
0x01, 0x10, 0xB0, 0xE3, // MOVS R1, #1
|
||||
0x00, 0x10, 0x80, 0xE5, // STR R1, [R0]
|
||||
0x0C, 0x00, 0x9F, 0xE5, // LDR R0, =0x7000E400
|
||||
0x10, 0x10, 0xB0, 0xE3, // MOVS R1, #0x10
|
||||
0x00, 0x10, 0x80, 0xE5, // STR R1, [R0]
|
||||
0xFE, 0xFF, 0xFF, 0xEA, // LOOP
|
||||
0x50, 0xE4, 0x00, 0x70, // #0x7000E450
|
||||
0x00, 0xE4, 0x00, 0x70 // #0x7000E400
|
||||
};
|
||||
|
||||
#define SEPT_PRI_ADDR 0x4003F000
|
||||
|
||||
#define SEPT_PK1T_ADDR 0xC0400000
|
||||
#define SEPT_TCSZ_ADDR (SEPT_PK1T_ADDR - 0x4)
|
||||
#define SEPT_STG1_ADDR (SEPT_PK1T_ADDR + 0x2E100)
|
||||
#define SEPT_STG2_ADDR (SEPT_PK1T_ADDR + 0x60E0)
|
||||
#define SEPT_PKG_SZ (0x2F100 + WB_RST_SIZE)
|
||||
|
||||
extern boot_cfg_t b_cfg;
|
||||
extern hekate_config h_cfg;
|
||||
extern const volatile ipl_ver_meta_t ipl_ver;
|
||||
|
||||
extern void *sd_file_read(char *path);
|
||||
extern void sd_mount();
|
||||
extern void sd_unmount();
|
||||
extern bool is_ipl_updated(void *buf);
|
||||
extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size);
|
||||
|
||||
void check_sept()
|
||||
{
|
||||
// Check if non-hekate payload is used for sept and restore it.
|
||||
if (h_cfg.sept_run && !f_stat("sept/payload.bak", NULL))
|
||||
{
|
||||
f_unlink("sept/payload.bin");
|
||||
f_rename("sept/payload.bak", "sept/payload.bin");
|
||||
return;
|
||||
}
|
||||
|
||||
u8 *pkg1 = (u8 *)calloc(1, 0x40000);
|
||||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
{
|
||||
EPRINTF("Failed to init eMMC.");
|
||||
goto out_free;
|
||||
}
|
||||
sdmmc_storage_set_mmc_partition(&storage, 1);
|
||||
|
||||
// Read package1.
|
||||
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
|
||||
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
|
||||
if (!pkg1_id)
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTF("Unknown pkg1 version.");
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run)
|
||||
{
|
||||
sdmmc_storage_end(&storage);
|
||||
reboot_to_sept((u8 *)pkg1 + pkg1_id->tsec_off);
|
||||
}
|
||||
|
||||
out_free:
|
||||
free(pkg1);
|
||||
sdmmc_storage_end(&storage);
|
||||
}
|
||||
|
||||
int reboot_to_sept(const u8 *tsec_fw)
|
||||
{
|
||||
FIL fp;
|
||||
|
||||
// Copy warmboot reboot code and TSEC fw.
|
||||
memcpy((u8 *)(SEPT_PK1T_ADDR - WB_RST_SIZE), (u8 *)warmboot_reboot, sizeof(warmboot_reboot));
|
||||
memcpy((void *)SEPT_PK1T_ADDR, tsec_fw, 0x3000);
|
||||
*(vu32 *)SEPT_TCSZ_ADDR = 0x3000;
|
||||
|
||||
// Copy sept-primary.
|
||||
if (f_open(&fp, "sept/sept-primary.bin", FA_READ))
|
||||
goto error;
|
||||
|
||||
if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL))
|
||||
{
|
||||
f_close(&fp);
|
||||
goto error;
|
||||
}
|
||||
f_close(&fp);
|
||||
|
||||
// Copy sept-secondary.
|
||||
if (f_open(&fp, "sept/sept-secondary.enc", FA_READ))
|
||||
goto error;
|
||||
|
||||
if (f_read(&fp, (u8 *)SEPT_STG2_ADDR, f_size(&fp), NULL))
|
||||
{
|
||||
f_close(&fp);
|
||||
goto error;
|
||||
}
|
||||
f_close(&fp);
|
||||
|
||||
b_cfg.boot_cfg |= (BOOT_CFG_AUTOBOOT_EN | BOOT_CFG_SEPT_RUN);
|
||||
|
||||
bool update_sept_payload = true;
|
||||
if (!f_open(&fp, "sept/payload.bin", FA_READ | FA_WRITE))
|
||||
{
|
||||
ipl_ver_meta_t tmp_ver;
|
||||
f_lseek(&fp, PATCHED_RELOC_SZ + sizeof(boot_cfg_t));
|
||||
f_read(&fp, &tmp_ver, sizeof(ipl_ver_meta_t), NULL);
|
||||
|
||||
if (tmp_ver.magic == ipl_ver.magic)
|
||||
{
|
||||
if (tmp_ver.version == ipl_ver.version)
|
||||
{
|
||||
// Save auto boot config to sept payload, if any.
|
||||
boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t));
|
||||
memcpy(tmp_cfg, &b_cfg, sizeof(boot_cfg_t));
|
||||
f_lseek(&fp, PATCHED_RELOC_SZ);
|
||||
f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL);
|
||||
f_close(&fp);
|
||||
update_sept_payload = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
f_rename("sept/payload.bin", "sept/payload.bak"); // Backup foreign payload.
|
||||
|
||||
f_close(&fp);
|
||||
}
|
||||
|
||||
if (update_sept_payload)
|
||||
{
|
||||
volatile reloc_meta_t *reloc = (reloc_meta_t *)(IPL_LOAD_ADDR + RELOC_META_OFF);
|
||||
f_open(&fp, "sept/payload.bin", FA_WRITE | FA_CREATE_ALWAYS);
|
||||
f_write(&fp, (u8 *)reloc->start, reloc->end - reloc->start, NULL);
|
||||
f_close(&fp);
|
||||
}
|
||||
|
||||
sd_unmount();
|
||||
|
||||
u32 pk1t_sept = SEPT_PK1T_ADDR - (ALIGN(PATCHED_RELOC_SZ, 0x10) + WB_RST_SIZE);
|
||||
|
||||
void (*sept)() = (void *)pk1t_sept;
|
||||
|
||||
reloc_patcher(WB_RST_ADDR, pk1t_sept, SEPT_PKG_SZ);
|
||||
|
||||
// Patch SDRAM init to perform an SVC immediately after second write.
|
||||
PMC(APBDEV_PMC_SCRATCH45) = 0x2E38DFFF;
|
||||
PMC(APBDEV_PMC_SCRATCH46) = 0x6001DC28;
|
||||
// Set SVC handler to jump to sept-primary in IRAM.
|
||||
PMC(APBDEV_PMC_SCRATCH33) = SEPT_PRI_ADDR;
|
||||
PMC(APBDEV_PMC_SCRATCH40) = 0x6000F208;
|
||||
|
||||
display_end();
|
||||
|
||||
(*sept)();
|
||||
|
||||
error:
|
||||
EPRINTF("Failed to run sept\n");
|
||||
display_backlight_brightness(h_cfg.backlight, 1000);
|
||||
|
||||
btn_wait();
|
||||
|
||||
return 0;
|
||||
}
|
||||
25
bootloader/hos/sept.h
Normal file
25
bootloader/hos/sept.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2019 CTCaer
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _SEPT_H_
|
||||
#define _SEPT_H_
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
void check_sept();
|
||||
int reboot_to_sept(const u8 *tsec_fw);
|
||||
|
||||
#endif
|
||||
@@ -27,8 +27,6 @@
|
||||
#define IRAM_LIB_ADDR 0x4002B000
|
||||
#define DRAM_LIB_ADDR 0xE0000000
|
||||
|
||||
extern gfx_ctxt_t gfx_ctxt;
|
||||
extern gfx_con_t gfx_con;
|
||||
extern heap_t _heap;
|
||||
|
||||
extern void *sd_file_read(char *path);
|
||||
@@ -84,7 +82,7 @@ void ianos_print_error(int errorno)
|
||||
gfx_printf(&gfx_con, "Error loading ELF!\n");
|
||||
break;
|
||||
case 5:
|
||||
gfx_printf(&gfx_con, "Error relcating ELF!\n");
|
||||
gfx_printf(&gfx_con, "Error relocating ELF!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
|
||||
#ifdef DEBUG
|
||||
#include "../../gfx/gfx.h"
|
||||
extern gfx_con_t gfx_con;
|
||||
#define EL_DEBUG(format, ...) \
|
||||
gfx_printf(&gfx_con, format __VA_OPT__(, ) __VA_ARGS__)
|
||||
#else
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#include "diskio.h" /* FatFs lower layer API */
|
||||
#include "../../storage/sdmmc.h"
|
||||
|
||||
#define SDMMC_UPPER_BUFFER 0xB8000000
|
||||
|
||||
extern sdmmc_storage_t sd_storage;
|
||||
|
||||
DSTATUS disk_status (
|
||||
@@ -36,7 +38,7 @@ DRESULT disk_read (
|
||||
{
|
||||
if ((u32)buff >= 0x90000000)
|
||||
return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR;
|
||||
u8 *buf = (u8 *)0x98000000; //TODO: define this somewhere.
|
||||
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; //TODO: define this somewhere.
|
||||
if (sdmmc_storage_read(&sd_storage, sector, count, buf))
|
||||
{
|
||||
memcpy(buff, buf, 512 * count);
|
||||
@@ -54,7 +56,7 @@ DRESULT disk_write (
|
||||
{
|
||||
if ((u32)buff >= 0x90000000)
|
||||
return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR;
|
||||
u8 *buf = (u8 *)0x98000000; //TODO: define this somewhere.
|
||||
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; //TODO: define this somewhere.
|
||||
memcpy(buf, buff, 512 * count);
|
||||
if (sdmmc_storage_write(&sd_storage, sector, count, buf))
|
||||
return RES_OK;
|
||||
|
||||
@@ -23,10 +23,8 @@
|
||||
|
||||
#include "ff.h" /* Declarations of FatFs API */
|
||||
#include "diskio.h" /* Declarations of device I/O functions */
|
||||
|
||||
#include "../../gfx/gfx.h"
|
||||
extern gfx_ctxt_t gfx_ctxt;
|
||||
extern gfx_con_t gfx_con;
|
||||
|
||||
#define EFSPRINTF(text, ...) print_error(); gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF);
|
||||
//#define EFSPRINTF(...)
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS {
|
||||
PROVIDE(__ipl_start = 0x40008000);
|
||||
PROVIDE(__ipl_start = IPL_LOAD_ADDR);
|
||||
. = __ipl_start;
|
||||
.text : {
|
||||
*(.text._start);
|
||||
*(._boot_cfg);
|
||||
*(._ipl_version);
|
||||
*(.text*);
|
||||
}
|
||||
.data : {
|
||||
|
||||
2665
bootloader/main.c
2665
bootloader/main.c
File diff suppressed because it is too large
Load Diff
@@ -124,6 +124,6 @@ void *calloc(u32 num, u32 size)
|
||||
|
||||
void free(void *buf)
|
||||
{
|
||||
if ((buf != NULL) || ((u32)buf > (_heap.start - 1)))
|
||||
if ((u32)buf >= _heap.start)
|
||||
_heap_free(&_heap, (u32)buf);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ void mc_config_carveout()
|
||||
MC(MC_MTS_CARVEOUT_SIZE_MB) = 0;
|
||||
MC(MC_MTS_CARVEOUT_ADR_HI) = 0;
|
||||
MC(MC_MTS_CARVEOUT_REG_CTRL) = 1;
|
||||
|
||||
MC(MC_SECURITY_CARVEOUT1_BOM) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT1_BOM_HI) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT1_SIZE_128KB) = 0;
|
||||
@@ -43,6 +44,21 @@ void mc_config_carveout()
|
||||
MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT1_CFG0) = 0x4000006;
|
||||
|
||||
MC(MC_SECURITY_CARVEOUT2_BOM) = 0x80020000;
|
||||
MC(MC_SECURITY_CARVEOUT2_BOM_HI) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_SIZE_128KB) = 2;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2) = 0x3100000;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4) = 0x300;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CFG0) = 0x440167E;
|
||||
|
||||
MC(MC_SECURITY_CARVEOUT3_BOM) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT3_BOM_HI) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT3_SIZE_128KB) = 0;
|
||||
@@ -57,6 +73,7 @@ void mc_config_carveout()
|
||||
MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT3_CFG0) = 0x4401E7E;
|
||||
|
||||
MC(MC_SECURITY_CARVEOUT4_BOM) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT4_BOM_HI) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT4_SIZE_128KB) = 0;
|
||||
@@ -71,6 +88,7 @@ void mc_config_carveout()
|
||||
MC(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT4_CFG0) = 0x8F;
|
||||
|
||||
MC(MC_SECURITY_CARVEOUT5_BOM) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT5_BOM_HI) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT5_SIZE_128KB) = 0;
|
||||
@@ -87,26 +105,9 @@ void mc_config_carveout()
|
||||
MC(MC_SECURITY_CARVEOUT5_CFG0) = 0x8F;
|
||||
}
|
||||
|
||||
void mc_config_carveout_finalize()
|
||||
{
|
||||
MC(MC_SECURITY_CARVEOUT2_BOM) = 0x80020000;
|
||||
MC(MC_SECURITY_CARVEOUT2_BOM_HI) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_SIZE_128KB) = 2;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2) = 0x3000000;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4) = 0x300;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CFG0) = 0x440167E;
|
||||
}
|
||||
|
||||
void mc_enable_ahb_redirect()
|
||||
{
|
||||
// Enable ARC_CLK_OVR_ON.
|
||||
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) = (CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) & 0xFFF7FFFF) | 0x80000;
|
||||
//MC(MC_IRAM_REG_CTRL) &= 0xFFFFFFFE;
|
||||
MC(MC_IRAM_BOM) = 0x40000000;
|
||||
@@ -119,7 +120,8 @@ void mc_disable_ahb_redirect()
|
||||
MC(MC_IRAM_TOM) = 0;
|
||||
// Disable IRAM_CFG_WRITE_ACCESS (sticky).
|
||||
//MC(MC_IRAM_REG_CTRL) = MC(MC_IRAM_REG_CTRL) & 0xFFFFFFFE | 1;
|
||||
CLOCK(0x3A4) &= 0xFFF7FFFF;
|
||||
// Disable ARC_CLK_OVR_ON.
|
||||
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) &= 0xFFF7FFFF;
|
||||
}
|
||||
|
||||
void mc_enable()
|
||||
@@ -131,7 +133,7 @@ void mc_enable()
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFFFFFFFE) | 1;
|
||||
// Enable EMC DLL clock.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) & 0xFFFFBFFF) | 0x4000;
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = 0x2000001; //Clear EMC and MC reset.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x2000001; //Clear EMC and MC reset.
|
||||
usleep(5);
|
||||
|
||||
//#ifdef CONFIG_ENABLE_AHB_REDIRECT
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018 balika011
|
||||
* Copyright (c) 2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -18,11 +20,12 @@
|
||||
#include "../soc/t210.h"
|
||||
#include "mc.h"
|
||||
#include "emc.h"
|
||||
#include "sdram_param_t210.h"
|
||||
#include "../soc/pmc.h"
|
||||
#include "../utils/util.h"
|
||||
#include "../soc/fuse.h"
|
||||
#include "../power/max77620.h"
|
||||
#include "../mem/sdram_param_t210.h"
|
||||
#include "../power/max7762x.h"
|
||||
#include "../soc/clock.h"
|
||||
|
||||
#define CONFIG_SDRAM_COMPRESS_CFG
|
||||
@@ -41,7 +44,7 @@ static u32 _get_sdram_id()
|
||||
|
||||
static void _sdram_config(const sdram_params_t *params)
|
||||
{
|
||||
PMC(0x45C) = (((4 * params->emc_pmc_scratch1 >> 2) + 0x80000000) ^ 0xFFFF) & 0xC000FFFF;
|
||||
PMC(APBDEV_PMC_IO_DPD3_REQ) = (((4 * params->emc_pmc_scratch1 >> 2) + 0x80000000) ^ 0xFFFF) & 0xC000FFFF;
|
||||
usleep(params->pmc_io_dpd3_req_wait);
|
||||
|
||||
u32 req = (4 * params->emc_pmc_scratch2 >> 2) + 0x80000000;
|
||||
@@ -388,12 +391,12 @@ break_nosleep:
|
||||
EMC(EMC_ACPD_CONTROL) = params->emc_acpd_control;
|
||||
EMC(EMC_TXDSRVTTGEN) = params->emc_txdsrvttgen;
|
||||
EMC(EMC_CFG) = (params->emc_cfg & 0xE) | 0x3C00000;
|
||||
if (params->boot_rom_patch_control & 0x80000000)
|
||||
if (params->boot_rom_patch_control & (1 << 31))
|
||||
{
|
||||
*(vu32 *)(4 * (params->boot_rom_patch_control + 0x1C000000)) = params->boot_rom_patch_data;
|
||||
*(vu32 *)(APB_MISC_BASE + params->boot_rom_patch_control * 4) = params->boot_rom_patch_data;
|
||||
MC(MC_TIMING_CONTROL) = 1;
|
||||
}
|
||||
PMC(0x45C) = ((4 * params->emc_pmc_scratch1 >> 2) + 0x40000000) & 0xCFFF0000;
|
||||
PMC(APBDEV_PMC_IO_DPD3_REQ) = ((4 * params->emc_pmc_scratch1 >> 2) + 0x40000000) & 0xCFFF0000;
|
||||
usleep(params->pmc_io_dpd3_req_wait);
|
||||
if (!params->emc_auto_cal_interval)
|
||||
EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config | 0x200;
|
||||
@@ -410,7 +413,7 @@ break_nosleep:
|
||||
}
|
||||
EMC(EMC_TIMING_CONTROL) = 1;
|
||||
usleep(params->emc_timing_control_wait);
|
||||
PMC(0x4E4) &= 0xFFF8007F;
|
||||
PMC(APBDEV_PMC_DDR_CNTRL) &= 0xFFF8007F;
|
||||
usleep(params->pmc_ddr_ctrl_wait);
|
||||
if (params->memory_type == 2)
|
||||
{
|
||||
@@ -459,7 +462,7 @@ break_nosleep:
|
||||
}
|
||||
}
|
||||
}
|
||||
PMC(0x1D0) = params->pmc_ddr_cfg;
|
||||
PMC(APBDEV_PMC_DDR_CFG) = params->pmc_ddr_cfg;
|
||||
if (params->memory_type - 1 <= 2)
|
||||
{
|
||||
EMC(EMC_ZCAL_INTERVAL) = params->emc_zcal_interval;
|
||||
@@ -486,29 +489,57 @@ break_nosleep:
|
||||
MC(MC_VIDEO_PROTECT_REG_CTRL) = params->mc_video_protect_write_access;
|
||||
MC(MC_SEC_CARVEOUT_REG_CTRL) = params->mc_sec_carveout_protect_write_access;
|
||||
MC(MC_MTS_CARVEOUT_REG_CTRL) = params->mc_mts_carveout_reg_ctrl;
|
||||
MC(MC_EMEM_CFG_ACCESS_CTRL) = 1; //Disable write access to a bunch of MC registers.
|
||||
MC(MC_EMEM_CFG_ACCESS_CTRL) = 1; //Disable write access to a bunch of EMC registers.
|
||||
}
|
||||
|
||||
const void *sdram_get_params()
|
||||
sdram_params_t *sdram_get_params()
|
||||
{
|
||||
//TODO: sdram_id should be in [0, 7].
|
||||
|
||||
#ifdef CONFIG_SDRAM_COMPRESS_CFG
|
||||
u8 *buf = (u8 *)0x40030000;
|
||||
LZ_Uncompress(_dram_cfg_lz, buf, sizeof(_dram_cfg_lz));
|
||||
return (const void *)&buf[sizeof(sdram_params_t) * _get_sdram_id()];
|
||||
return (sdram_params_t *)&buf[sizeof(sdram_params_t) * _get_sdram_id()];
|
||||
#else
|
||||
return _dram_cfgs[_get_sdram_id()];
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Function: sdram_get_params_patched
|
||||
*
|
||||
* This code implements a warmboot exploit. Warmboot, that is actually so hot, it burns Nvidia once again.
|
||||
* If the boot_rom_patch_control's MSB is set, it uses it as an index to
|
||||
* APB_MISC_BASE (u32 array) and sets it to the value of boot_rom_patch_data.
|
||||
* (The MSB falls out when it gets multiplied by sizeof(u32)).
|
||||
* Because the bootrom does not do any boundary checks, it lets us write anywhere and anything.
|
||||
* Ipatch hardware let us apply 12 changes to the bootrom and can be changed any time.
|
||||
* The first patch is not needed any more when the exploit is triggered, so we overwrite that.
|
||||
* 0x10459E is the address where it returns an error when the signature is not valid.
|
||||
* We change that to MOV R0, #0, so we pass the check.
|
||||
*
|
||||
* Note: The modulus in the header must match and validated.
|
||||
*/
|
||||
|
||||
sdram_params_t *sdram_get_params_patched()
|
||||
{
|
||||
#define IPATCH_CONFIG(addr, data) (((addr - 0x100000) / 2) << 16 | (data & 0xffff))
|
||||
sdram_params_t *sdram_params = sdram_get_params();
|
||||
|
||||
// Disable Warmboot signature check.
|
||||
sdram_params->boot_rom_patch_control = (1 << 31) | (((IPATCH_BASE + 4) - APB_MISC_BASE) / 4);
|
||||
sdram_params->boot_rom_patch_data = IPATCH_CONFIG(0x10459E, 0x2000);
|
||||
|
||||
return sdram_params;
|
||||
}
|
||||
|
||||
void sdram_init()
|
||||
{
|
||||
//TODO: sdram_id should be in [0,4].
|
||||
const sdram_params_t *params = (const sdram_params_t *)sdram_get_params();
|
||||
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, 0x05);
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD1, 40); //40 = (1000 * 1100 - 600000) / 12500 -> 1.1V
|
||||
max77620_regulator_set_voltage(REGULATOR_SD1, 1100000);
|
||||
|
||||
PMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel;
|
||||
usleep(params->pmc_vddp_sel_wait);
|
||||
|
||||
@@ -17,8 +17,11 @@
|
||||
#ifndef _SDRAM_H_
|
||||
#define _SDRAM_H_
|
||||
|
||||
#include "sdram_param_t210.h"
|
||||
|
||||
void sdram_init();
|
||||
const void *sdram_get_params();
|
||||
sdram_params_t *sdram_get_params();
|
||||
sdram_params_t *sdram_get_params_patched();
|
||||
void sdram_lp0_save_params(const void *params);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright 2014 Google Inc.
|
||||
* Copyright (C) 2018 naehrwert
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
||||
@@ -148,7 +148,7 @@ int bq24193_get_property(enum BQ24193_reg_prop prop, int *value)
|
||||
|
||||
void bq24193_fake_battery_removal()
|
||||
{
|
||||
u8 value;
|
||||
u8 value;
|
||||
|
||||
// Disable watchdog to keep BATFET disabled.
|
||||
value = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgTermTimer);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Defining registers address and its bit definitions of MAX77620 and MAX20024
|
||||
*
|
||||
* Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -14,275 +15,277 @@
|
||||
#define MAX77620_I2C_ADDR 0x3C
|
||||
|
||||
/* GLOBAL, PMIC, GPIO, FPS, ONOFFC, CID Registers */
|
||||
#define MAX77620_REG_CNFGGLBL1 0x00
|
||||
#define MAX77620_REG_CNFGGLBL2 0x01
|
||||
#define MAX77620_REG_CNFGGLBL3 0x02
|
||||
#define MAX77620_REG_CNFG1_32K 0x03
|
||||
#define MAX77620_REG_CNFGBBC 0x04
|
||||
#define MAX77620_REG_IRQTOP 0x05
|
||||
#define MAX77620_REG_INTLBT 0x06
|
||||
#define MAX77620_REG_IRQSD 0x07
|
||||
#define MAX77620_REG_IRQ_LVL2_L0_7 0x08
|
||||
#define MAX77620_REG_IRQ_LVL2_L8 0x09
|
||||
#define MAX77620_REG_IRQ_LVL2_GPIO 0x0A
|
||||
#define MAX77620_REG_ONOFFIRQ 0x0B
|
||||
#define MAX77620_REG_NVERC 0x0C
|
||||
#define MAX77620_REG_IRQTOPM 0x0D
|
||||
#define MAX77620_REG_INTENLBT 0x0E
|
||||
#define MAX77620_REG_IRQMASKSD 0x0F
|
||||
#define MAX77620_REG_IRQ_MSK_L0_7 0x10
|
||||
#define MAX77620_REG_IRQ_MSK_L8 0x11
|
||||
#define MAX77620_REG_ONOFFIRQM 0x12
|
||||
#define MAX77620_REG_STATLBT 0x13
|
||||
#define MAX77620_REG_STATSD 0x14
|
||||
#define MAX77620_REG_ONOFFSTAT 0x15
|
||||
#define MAX77620_REG_CNFGGLBL1 0x00
|
||||
#define MAX77620_CNFGGLBL1_LBDAC_EN (1 << 7)
|
||||
#define MAX77620_CNFGGLBL1_MPPLD (1 << 6)
|
||||
#define MAX77620_CNFGGLBL1_LBHYST ((1 << 5) | (1 << 4))
|
||||
#define MAX77620_CNFGGLBL1_LBHYST_N (1 << 4)
|
||||
#define MAX77620_CNFGGLBL1_LBDAC 0x0E
|
||||
#define MAX77620_CNFGGLBL1_LBDAC_N (1 << 1)
|
||||
#define MAX77620_CNFGGLBL1_LBRSTEN (1 << 0)
|
||||
|
||||
#define MAX77620_REG_CNFGGLBL2 0x01
|
||||
#define MAX77620_REG_CNFGGLBL3 0x02
|
||||
#define MAX77620_WDTC_MASK 0x3
|
||||
#define MAX77620_WDTOFFC (1 << 4)
|
||||
#define MAX77620_WDTSLPC (1 << 3)
|
||||
#define MAX77620_WDTEN (1 << 2)
|
||||
#define MAX77620_TWD_MASK 0x3
|
||||
#define MAX77620_TWD_2s 0x0
|
||||
#define MAX77620_TWD_16s 0x1
|
||||
#define MAX77620_TWD_64s 0x2
|
||||
#define MAX77620_TWD_128s 0x3
|
||||
|
||||
#define MAX77620_REG_CNFG1_32K 0x03
|
||||
#define MAX77620_CNFG1_32K_OUT0_EN (1 << 2)
|
||||
|
||||
#define MAX77620_REG_CNFGBBC 0x04
|
||||
#define MAX77620_CNFGBBC_ENABLE (1 << 0)
|
||||
#define MAX77620_CNFGBBC_CURRENT_MASK 0x06
|
||||
#define MAX77620_CNFGBBC_CURRENT_SHIFT 1
|
||||
#define MAX77620_CNFGBBC_VOLTAGE_MASK 0x18
|
||||
#define MAX77620_CNFGBBC_VOLTAGE_SHIFT 3
|
||||
#define MAX77620_CNFGBBC_LOW_CURRENT_DISABLE (1 << 5)
|
||||
#define MAX77620_CNFGBBC_RESISTOR_MASK 0xC0
|
||||
#define MAX77620_CNFGBBC_RESISTOR_SHIFT 6
|
||||
#define MAX77620_CNFGBBC_RESISTOR_100 (0 << MAX77620_CNFGBBC_RESISTOR_SHIFT)
|
||||
#define MAX77620_CNFGBBC_RESISTOR_1K (1 << MAX77620_CNFGBBC_RESISTOR_SHIFT)
|
||||
#define MAX77620_CNFGBBC_RESISTOR_3K (2 << MAX77620_CNFGBBC_RESISTOR_SHIFT)
|
||||
#define MAX77620_CNFGBBC_RESISTOR_6K (3 << MAX77620_CNFGBBC_RESISTOR_SHIFT)
|
||||
|
||||
#define MAX77620_REG_IRQTOP 0x05
|
||||
#define MAX77620_IRQ_TOP_GLBL_MASK (1 << 7)
|
||||
#define MAX77620_IRQ_TOP_SD_MASK (1 << 6)
|
||||
#define MAX77620_IRQ_TOP_LDO_MASK (1 << 5)
|
||||
#define MAX77620_IRQ_TOP_GPIO_MASK (1 << 4)
|
||||
#define MAX77620_IRQ_TOP_RTC_MASK (1 << 3)
|
||||
#define MAX77620_IRQ_TOP_32K_MASK (1 << 2)
|
||||
#define MAX77620_IRQ_TOP_ONOFF_MASK (1 << 1)
|
||||
|
||||
#define MAX77620_REG_INTLBT 0x06
|
||||
#define MAX77620_REG_IRQTOPM 0x0D
|
||||
#define MAX77620_IRQ_LBM_MASK (1 << 3)
|
||||
#define MAX77620_IRQ_TJALRM1_MASK (1 << 2)
|
||||
#define MAX77620_IRQ_TJALRM2_MASK (1 << 1)
|
||||
|
||||
#define MAX77620_REG_IRQSD 0x07
|
||||
#define MAX77620_REG_IRQ_LVL2_L0_7 0x08
|
||||
#define MAX77620_REG_IRQ_LVL2_L8 0x09
|
||||
#define MAX77620_REG_IRQ_LVL2_GPIO 0x0A
|
||||
#define MAX77620_REG_ONOFFIRQ 0x0B
|
||||
#define MAX77620_REG_NVERC 0x0C
|
||||
|
||||
#define MAX77620_REG_INTENLBT 0x0E
|
||||
#define MAX77620_GLBLM_MASK (1 << 0)
|
||||
|
||||
#define MAX77620_REG_IRQMASKSD 0x0F
|
||||
#define MAX77620_REG_IRQ_MSK_L0_7 0x10
|
||||
#define MAX77620_REG_IRQ_MSK_L8 0x11
|
||||
#define MAX77620_REG_ONOFFIRQM 0x12
|
||||
#define MAX77620_REG_STATLBT 0x13
|
||||
#define MAX77620_REG_STATSD 0x14
|
||||
#define MAX77620_REG_ONOFFSTAT 0x15
|
||||
|
||||
/* SD and LDO Registers */
|
||||
#define MAX77620_REG_SD0 0x16
|
||||
#define MAX77620_REG_SD1 0x17
|
||||
#define MAX77620_REG_SD2 0x18
|
||||
#define MAX77620_REG_SD3 0x19
|
||||
#define MAX77620_REG_SD4 0x1A
|
||||
#define MAX77620_REG_DVSSD0 0x1B
|
||||
#define MAX77620_REG_DVSSD1 0x1C
|
||||
#define MAX77620_REG_SD0_CFG 0x1D
|
||||
#define MAX77620_REG_SD1_CFG 0x1E
|
||||
#define MAX77620_REG_SD2_CFG 0x1F
|
||||
#define MAX77620_REG_SD3_CFG 0x20
|
||||
#define MAX77620_REG_SD4_CFG 0x21
|
||||
#define MAX77620_REG_SD_CFG2 0x22
|
||||
#define MAX77620_REG_LDO0_CFG 0x23
|
||||
#define MAX77620_REG_LDO0_CFG2 0x24
|
||||
#define MAX77620_REG_LDO1_CFG 0x25
|
||||
#define MAX77620_REG_LDO1_CFG2 0x26
|
||||
#define MAX77620_REG_LDO2_CFG 0x27
|
||||
#define MAX77620_REG_LDO2_CFG2 0x28
|
||||
#define MAX77620_REG_LDO3_CFG 0x29
|
||||
#define MAX77620_REG_LDO3_CFG2 0x2A
|
||||
#define MAX77620_REG_LDO4_CFG 0x2B
|
||||
#define MAX77620_REG_LDO4_CFG2 0x2C
|
||||
#define MAX77620_REG_LDO5_CFG 0x2D
|
||||
#define MAX77620_REG_LDO5_CFG2 0x2E
|
||||
#define MAX77620_REG_LDO6_CFG 0x2F
|
||||
#define MAX77620_REG_LDO6_CFG2 0x30
|
||||
#define MAX77620_REG_LDO7_CFG 0x31
|
||||
#define MAX77620_REG_LDO7_CFG2 0x32
|
||||
#define MAX77620_REG_LDO8_CFG 0x33
|
||||
#define MAX77620_REG_LDO8_CFG2 0x34
|
||||
#define MAX77620_REG_LDO_CFG3 0x35
|
||||
#define MAX77620_REG_SD0 0x16
|
||||
#define MAX77620_REG_SD1 0x17
|
||||
#define MAX77620_REG_SD2 0x18
|
||||
#define MAX77620_REG_SD3 0x19
|
||||
#define MAX77620_REG_SD4 0x1A
|
||||
#define MAX77620_SDX_VOLT_MASK 0xFF
|
||||
#define MAX77620_SD0_VOLT_MASK 0x3F
|
||||
#define MAX77620_SD1_VOLT_MASK 0x7F
|
||||
#define MAX77620_LDO_VOLT_MASK 0x3F
|
||||
#define MAX77620_REG_DVSSD0 0x1B
|
||||
#define MAX77620_REG_DVSSD1 0x1C
|
||||
#define MAX77620_REG_SD0_CFG 0x1D
|
||||
#define MAX77620_REG_SD1_CFG 0x1E
|
||||
#define MAX77620_REG_SD2_CFG 0x1F
|
||||
#define MAX77620_REG_SD3_CFG 0x20
|
||||
#define MAX77620_REG_SD4_CFG 0x21
|
||||
#define MAX77620_REG_SD_CFG2 0x22
|
||||
#define MAX77620_REG_LDO0_CFG 0x23
|
||||
#define MAX77620_REG_LDO0_CFG2 0x24
|
||||
#define MAX77620_REG_LDO1_CFG 0x25
|
||||
#define MAX77620_REG_LDO1_CFG2 0x26
|
||||
#define MAX77620_REG_LDO2_CFG 0x27
|
||||
#define MAX77620_REG_LDO2_CFG2 0x28
|
||||
#define MAX77620_REG_LDO3_CFG 0x29
|
||||
#define MAX77620_REG_LDO3_CFG2 0x2A
|
||||
#define MAX77620_REG_LDO4_CFG 0x2B
|
||||
#define MAX77620_REG_LDO4_CFG2 0x2C
|
||||
#define MAX77620_REG_LDO5_CFG 0x2D
|
||||
#define MAX77620_REG_LDO5_CFG2 0x2E
|
||||
#define MAX77620_REG_LDO6_CFG 0x2F
|
||||
#define MAX77620_REG_LDO6_CFG2 0x30
|
||||
#define MAX77620_REG_LDO7_CFG 0x31
|
||||
#define MAX77620_REG_LDO7_CFG2 0x32
|
||||
#define MAX77620_REG_LDO8_CFG 0x33
|
||||
#define MAX77620_REG_LDO8_CFG2 0x34
|
||||
#define MAX77620_LDO_POWER_MODE_MASK 0xC0
|
||||
#define MAX77620_LDO_POWER_MODE_SHIFT 6
|
||||
#define MAX77620_POWER_MODE_NORMAL 3
|
||||
#define MAX77620_POWER_MODE_LPM 2
|
||||
#define MAX77620_POWER_MODE_GLPM 1
|
||||
#define MAX77620_POWER_MODE_DISABLE 0
|
||||
#define MAX20024_LDO_CFG2_MPOK_MASK (1 << 2)
|
||||
#define MAX77620_LDO_CFG2_ADE_MASK (1 << 1)
|
||||
#define MAX77620_LDO_CFG2_ADE_DISABLE 0
|
||||
#define MAX77620_LDO_CFG2_ADE_ENABLE (1 << 1)
|
||||
#define MAX77620_LDO_CFG2_SS_MASK (1 << 0)
|
||||
#define MAX77620_LDO_CFG2_SS_FAST (1 << 0)
|
||||
#define MAX77620_LDO_CFG2_SS_SLOW 0
|
||||
|
||||
#define MAX77620_LDO_SLEW_RATE_MASK 0x1
|
||||
#define MAX77620_REG_LDO_CFG3 0x35
|
||||
#define MAX77620_TRACK4_MASK (1 << 5)
|
||||
#define MAX77620_TRACK4_SHIFT 5
|
||||
|
||||
/* LDO Configuration 3 */
|
||||
#define MAX77620_TRACK4_MASK (1 << 5)
|
||||
#define MAX77620_TRACK4_SHIFT 5
|
||||
#define MAX77620_LDO_SLEW_RATE_MASK 0x1
|
||||
|
||||
/* Voltage */
|
||||
#define MAX77620_SDX_VOLT_MASK 0xFF
|
||||
#define MAX77620_SD0_VOLT_MASK 0x3F
|
||||
#define MAX77620_SD1_VOLT_MASK 0x7F
|
||||
#define MAX77620_LDO_VOLT_MASK 0x3F
|
||||
#define MAX77620_REG_GPIO0 0x36
|
||||
#define MAX77620_REG_GPIO1 0x37
|
||||
#define MAX77620_REG_GPIO2 0x38
|
||||
#define MAX77620_REG_GPIO3 0x39
|
||||
#define MAX77620_REG_GPIO4 0x3A
|
||||
#define MAX77620_REG_GPIO5 0x3B
|
||||
#define MAX77620_REG_GPIO6 0x3C
|
||||
#define MAX77620_REG_GPIO7 0x3D
|
||||
#define MAX77620_REG_PUE_GPIO 0x3E
|
||||
#define MAX77620_REG_PDE_GPIO 0x3F
|
||||
#define MAX77620_REG_AME_GPIO 0x40
|
||||
|
||||
#define MAX77620_REG_GPIO0 0x36
|
||||
#define MAX77620_REG_GPIO1 0x37
|
||||
#define MAX77620_REG_GPIO2 0x38
|
||||
#define MAX77620_REG_GPIO3 0x39
|
||||
#define MAX77620_REG_GPIO4 0x3A
|
||||
#define MAX77620_REG_GPIO5 0x3B
|
||||
#define MAX77620_REG_GPIO6 0x3C
|
||||
#define MAX77620_REG_GPIO7 0x3D
|
||||
#define MAX77620_REG_PUE_GPIO 0x3E
|
||||
#define MAX77620_REG_PDE_GPIO 0x3F
|
||||
#define MAX77620_REG_AME_GPIO 0x40
|
||||
#define MAX77620_REG_ONOFFCNFG1 0x41
|
||||
#define MAX77620_REG_ONOFFCNFG2 0x42
|
||||
#define MAX77620_REG_ONOFFCNFG1 0x41
|
||||
#define MAX77620_ONOFFCNFG1_SFT_RST (1 << 7)
|
||||
#define MAX77620_ONOFFCNFG1_MRT_MASK 0x38
|
||||
#define MAX77620_ONOFFCNFG1_MRT_SHIFT 0x3
|
||||
#define MAX77620_ONOFFCNFG1_SLPEN (1 << 2)
|
||||
#define MAX77620_ONOFFCNFG1_PWR_OFF (1 << 1)
|
||||
#define MAX20024_ONOFFCNFG1_CLRSE 0x18
|
||||
|
||||
#define MAX77620_REG_ONOFFCNFG2 0x42
|
||||
#define MAX77620_ONOFFCNFG2_SFT_RST_WK (1 << 7)
|
||||
#define MAX77620_ONOFFCNFG2_WD_RST_WK (1 << 6)
|
||||
#define MAX77620_ONOFFCNFG2_SLP_LPM_MSK (1 << 5)
|
||||
#define MAX77620_ONOFFCNFG2_WK_ALARM1 (1 << 2)
|
||||
#define MAX77620_ONOFFCNFG2_WK_EN0 (1 << 0)
|
||||
|
||||
/* FPS Registers */
|
||||
#define MAX77620_REG_FPS_CFG0 0x43
|
||||
#define MAX77620_REG_FPS_CFG1 0x44
|
||||
#define MAX77620_REG_FPS_CFG2 0x45
|
||||
#define MAX77620_REG_FPS_LDO0 0x46
|
||||
#define MAX77620_REG_FPS_LDO1 0x47
|
||||
#define MAX77620_REG_FPS_LDO2 0x48
|
||||
#define MAX77620_REG_FPS_LDO3 0x49
|
||||
#define MAX77620_REG_FPS_LDO4 0x4A
|
||||
#define MAX77620_REG_FPS_LDO5 0x4B
|
||||
#define MAX77620_REG_FPS_LDO6 0x4C
|
||||
#define MAX77620_REG_FPS_LDO7 0x4D
|
||||
#define MAX77620_REG_FPS_LDO8 0x4E
|
||||
#define MAX77620_REG_FPS_SD0 0x4F
|
||||
#define MAX77620_REG_FPS_SD1 0x50
|
||||
#define MAX77620_REG_FPS_SD2 0x51
|
||||
#define MAX77620_REG_FPS_SD3 0x52
|
||||
#define MAX77620_REG_FPS_SD4 0x53
|
||||
#define MAX77620_REG_FPS_NONE 0
|
||||
|
||||
#define MAX77620_FPS_SRC_MASK 0xC0
|
||||
#define MAX77620_FPS_SRC_SHIFT 6
|
||||
#define MAX77620_FPS_PU_PERIOD_MASK 0x38
|
||||
#define MAX77620_FPS_PU_PERIOD_SHIFT 3
|
||||
#define MAX77620_FPS_PD_PERIOD_MASK 0x07
|
||||
#define MAX77620_FPS_PD_PERIOD_SHIFT 0
|
||||
#define MAX77620_FPS_TIME_PERIOD_MASK 0x38
|
||||
#define MAX77620_FPS_TIME_PERIOD_SHIFT 3
|
||||
#define MAX77620_FPS_EN_SRC_MASK 0x06
|
||||
#define MAX77620_FPS_EN_SRC_SHIFT 1
|
||||
#define MAX77620_FPS_ENFPS_SW_MASK 0x01
|
||||
#define MAX77620_FPS_ENFPS_SW 0x01
|
||||
#define MAX77620_REG_FPS_CFG0 0x43
|
||||
#define MAX77620_REG_FPS_CFG1 0x44
|
||||
#define MAX77620_REG_FPS_CFG2 0x45
|
||||
#define MAX77620_REG_FPS_LDO0 0x46
|
||||
#define MAX77620_REG_FPS_LDO1 0x47
|
||||
#define MAX77620_REG_FPS_LDO2 0x48
|
||||
#define MAX77620_REG_FPS_LDO3 0x49
|
||||
#define MAX77620_REG_FPS_LDO4 0x4A
|
||||
#define MAX77620_REG_FPS_LDO5 0x4B
|
||||
#define MAX77620_REG_FPS_LDO6 0x4C
|
||||
#define MAX77620_REG_FPS_LDO7 0x4D
|
||||
#define MAX77620_REG_FPS_LDO8 0x4E
|
||||
#define MAX77620_REG_FPS_SD0 0x4F
|
||||
#define MAX77620_REG_FPS_SD1 0x50
|
||||
#define MAX77620_REG_FPS_SD2 0x51
|
||||
#define MAX77620_REG_FPS_SD3 0x52
|
||||
#define MAX77620_REG_FPS_SD4 0x53
|
||||
#define MAX77620_REG_FPS_NONE 0
|
||||
#define MAX77620_FPS_SRC_MASK 0xC0
|
||||
#define MAX77620_FPS_SRC_SHIFT 6
|
||||
#define MAX77620_FPS_PU_PERIOD_MASK 0x38
|
||||
#define MAX77620_FPS_PU_PERIOD_SHIFT 3
|
||||
#define MAX77620_FPS_PD_PERIOD_MASK 0x07
|
||||
#define MAX77620_FPS_PD_PERIOD_SHIFT 0
|
||||
|
||||
/* Minimum and maximum FPS period time (in microseconds) are
|
||||
* different for MAX77620 and Max20024.
|
||||
*/
|
||||
#define MAX77620_FPS_PERIOD_MIN_US 40
|
||||
#define MAX20024_FPS_PERIOD_MIN_US 20
|
||||
#define MAX77620_FPS_COUNT 3
|
||||
|
||||
#define MAX77620_FPS_PERIOD_MAX_US 2560
|
||||
#define MAX20024_FPS_PERIOD_MAX_US 5120
|
||||
#define MAX77620_FPS_PERIOD_MIN_US 40
|
||||
#define MAX20024_FPS_PERIOD_MIN_US 20
|
||||
|
||||
#define MAX77620_REG_FPS_GPIO1 0x54
|
||||
#define MAX77620_REG_FPS_GPIO2 0x55
|
||||
#define MAX77620_REG_FPS_GPIO3 0x56
|
||||
#define MAX77620_REG_FPS_RSO 0x57
|
||||
#define MAX77620_REG_CID0 0x58
|
||||
#define MAX77620_REG_CID1 0x59
|
||||
#define MAX77620_REG_CID2 0x5A
|
||||
#define MAX77620_REG_CID3 0x5B
|
||||
#define MAX77620_REG_CID4 0x5C
|
||||
#define MAX77620_REG_CID5 0x5D
|
||||
#define MAX77620_FPS_PERIOD_MAX_US 2560
|
||||
#define MAX20024_FPS_PERIOD_MAX_US 5120
|
||||
|
||||
#define MAX77620_REG_DVSSD4 0x5E
|
||||
#define MAX20024_REG_MAX_ADD 0x70
|
||||
#define MAX77620_REG_FPS_GPIO1 0x54
|
||||
#define MAX77620_REG_FPS_GPIO2 0x55
|
||||
#define MAX77620_REG_FPS_GPIO3 0x56
|
||||
#define MAX77620_FPS_TIME_PERIOD_MASK 0x38
|
||||
#define MAX77620_FPS_TIME_PERIOD_SHIFT 3
|
||||
#define MAX77620_FPS_EN_SRC_MASK 0x06
|
||||
#define MAX77620_FPS_EN_SRC_SHIFT 1
|
||||
#define MAX77620_FPS_ENFPS_SW_MASK 0x01
|
||||
#define MAX77620_FPS_ENFPS_SW 0x01
|
||||
|
||||
#define MAX77620_CID_DIDM_MASK 0xF0
|
||||
#define MAX77620_CID_DIDM_SHIFT 4
|
||||
#define MAX77620_REG_FPS_RSO 0x57
|
||||
#define MAX77620_REG_CID0 0x58
|
||||
#define MAX77620_REG_CID1 0x59
|
||||
#define MAX77620_REG_CID2 0x5A
|
||||
#define MAX77620_REG_CID3 0x5B
|
||||
#define MAX77620_REG_CID4 0x5C
|
||||
#define MAX77620_REG_CID5 0x5D
|
||||
|
||||
#define MAX77620_REG_DVSSD4 0x5E
|
||||
#define MAX20024_REG_MAX_ADD 0x70
|
||||
|
||||
#define MAX77620_CID_DIDM_MASK 0xF0
|
||||
#define MAX77620_CID_DIDM_SHIFT 4
|
||||
|
||||
/* CNCG2SD */
|
||||
#define MAX77620_SD_CNF2_ROVS_EN_SD1 (1 << 1)
|
||||
#define MAX77620_SD_CNF2_ROVS_EN_SD0 (1 << 2)
|
||||
#define MAX77620_SD_CNF2_ROVS_EN_SD1 (1 << 1)
|
||||
#define MAX77620_SD_CNF2_ROVS_EN_SD0 (1 << 2)
|
||||
|
||||
/* Device Identification Metal */
|
||||
#define MAX77620_CID5_DIDM(n) (((n) >> 4) & 0xF)
|
||||
#define MAX77620_CID5_DIDM(n) (((n) >> 4) & 0xF)
|
||||
/* Device Indentification OTP */
|
||||
#define MAX77620_CID5_DIDO(n) ((n) & 0xF)
|
||||
#define MAX77620_CID5_DIDO(n) ((n) & 0xF)
|
||||
|
||||
/* SD CNFG1 */
|
||||
#define MAX77620_SD_SR_MASK 0xC0
|
||||
#define MAX77620_SD_SR_SHIFT 6
|
||||
#define MAX77620_SD_POWER_MODE_MASK 0x30
|
||||
#define MAX77620_SD_POWER_MODE_SHIFT 4
|
||||
#define MAX77620_SD_CFG1_ADE_MASK (1 << 3)
|
||||
#define MAX77620_SD_CFG1_ADE_DISABLE 0
|
||||
#define MAX77620_SD_CFG1_ADE_ENABLE (1 << 3)
|
||||
#define MAX77620_SD_FPWM_MASK 0x04
|
||||
#define MAX77620_SD_FPWM_SHIFT 2
|
||||
#define MAX77620_SD_FSRADE_MASK 0x01
|
||||
#define MAX77620_SD_FSRADE_SHIFT 0
|
||||
#define MAX77620_SD_CFG1_FPWM_SD_MASK (1 << 2)
|
||||
#define MAX77620_SD_CFG1_FPWM_SD_SKIP 0
|
||||
#define MAX77620_SD_CFG1_FPWM_SD_FPWM (1 << 2)
|
||||
#define MAX20024_SD_CFG1_MPOK_MASK (1 << 1)
|
||||
#define MAX77620_SD_CFG1_FSRADE_SD_MASK (1 << 0)
|
||||
#define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0
|
||||
#define MAX77620_SD_CFG1_FSRADE_SD_ENABLE (1 << 0)
|
||||
#define MAX77620_SD_SR_MASK 0xC0
|
||||
#define MAX77620_SD_SR_SHIFT 6
|
||||
#define MAX77620_SD_POWER_MODE_MASK 0x30
|
||||
#define MAX77620_SD_POWER_MODE_SHIFT 4
|
||||
#define MAX77620_SD_CFG1_ADE_MASK (1 << 3)
|
||||
#define MAX77620_SD_CFG1_ADE_DISABLE 0
|
||||
#define MAX77620_SD_CFG1_ADE_ENABLE (1 << 3)
|
||||
#define MAX77620_SD_FPWM_MASK 0x04
|
||||
#define MAX77620_SD_FPWM_SHIFT 2
|
||||
#define MAX77620_SD_FSRADE_MASK 0x01
|
||||
#define MAX77620_SD_FSRADE_SHIFT 0
|
||||
#define MAX77620_SD_CFG1_FPWM_SD_MASK (1 << 2)
|
||||
#define MAX77620_SD_CFG1_FPWM_SD_SKIP 0
|
||||
#define MAX77620_SD_CFG1_FPWM_SD_FPWM (1 << 2)
|
||||
#define MAX20024_SD_CFG1_MPOK_MASK (1 << 1)
|
||||
#define MAX77620_SD_CFG1_FSRADE_SD_MASK (1 << 0)
|
||||
#define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0
|
||||
#define MAX77620_SD_CFG1_FSRADE_SD_ENABLE (1 << 0)
|
||||
|
||||
/* LDO_CNFG2 */
|
||||
#define MAX77620_LDO_POWER_MODE_MASK 0xC0
|
||||
#define MAX77620_LDO_POWER_MODE_SHIFT 6
|
||||
#define MAX20024_LDO_CFG2_MPOK_MASK (1 << 2)
|
||||
#define MAX77620_LDO_CFG2_ADE_MASK (1 << 1)
|
||||
#define MAX77620_LDO_CFG2_ADE_DISABLE 0
|
||||
#define MAX77620_LDO_CFG2_ADE_ENABLE (1 << 1)
|
||||
#define MAX77620_LDO_CFG2_SS_MASK (1 << 0)
|
||||
#define MAX77620_LDO_CFG2_SS_FAST (1 << 0)
|
||||
#define MAX77620_LDO_CFG2_SS_SLOW 0
|
||||
#define MAX77620_CNFG_GPIO_DRV_MASK (1 << 0)
|
||||
#define MAX77620_CNFG_GPIO_DRV_PUSHPULL (1 << 0)
|
||||
#define MAX77620_CNFG_GPIO_DRV_OPENDRAIN 0
|
||||
#define MAX77620_CNFG_GPIO_DIR_MASK (1 << 1)
|
||||
#define MAX77620_CNFG_GPIO_DIR_INPUT (1 << 1)
|
||||
#define MAX77620_CNFG_GPIO_DIR_OUTPUT 0
|
||||
#define MAX77620_CNFG_GPIO_INPUT_VAL_MASK (1 << 2)
|
||||
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK (1 << 3)
|
||||
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH (1 << 3)
|
||||
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW 0
|
||||
#define MAX77620_CNFG_GPIO_INT_MASK (0x3 << 4)
|
||||
#define MAX77620_CNFG_GPIO_INT_FALLING (1 << 4)
|
||||
#define MAX77620_CNFG_GPIO_INT_RISING (1 << 5)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_MASK (0x3 << 6)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_None (0x0 << 6)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_8ms (0x1 << 6)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_16ms (0x2 << 6)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_32ms (0x3 << 6)
|
||||
|
||||
#define MAX77620_IRQ_TOP_GLBL_MASK (1 << 7)
|
||||
#define MAX77620_IRQ_TOP_SD_MASK (1 << 6)
|
||||
#define MAX77620_IRQ_TOP_LDO_MASK (1 << 5)
|
||||
#define MAX77620_IRQ_TOP_GPIO_MASK (1 << 4)
|
||||
#define MAX77620_IRQ_TOP_RTC_MASK (1 << 3)
|
||||
#define MAX77620_IRQ_TOP_32K_MASK (1 << 2)
|
||||
#define MAX77620_IRQ_TOP_ONOFF_MASK (1 << 1)
|
||||
|
||||
#define MAX77620_IRQ_LBM_MASK (1 << 3)
|
||||
#define MAX77620_IRQ_TJALRM1_MASK (1 << 2)
|
||||
#define MAX77620_IRQ_TJALRM2_MASK (1 << 1)
|
||||
|
||||
#define MAX77620_CNFG_GPIO_DRV_MASK (1 << 0)
|
||||
#define MAX77620_CNFG_GPIO_DRV_PUSHPULL (1 << 0)
|
||||
#define MAX77620_CNFG_GPIO_DRV_OPENDRAIN 0
|
||||
#define MAX77620_CNFG_GPIO_DIR_MASK (1 << 1)
|
||||
#define MAX77620_CNFG_GPIO_DIR_INPUT (1 << 1)
|
||||
#define MAX77620_CNFG_GPIO_DIR_OUTPUT 0
|
||||
#define MAX77620_CNFG_GPIO_INPUT_VAL_MASK (1 << 2)
|
||||
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK (1 << 3)
|
||||
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH (1 << 3)
|
||||
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW 0
|
||||
#define MAX77620_CNFG_GPIO_INT_MASK (0x3 << 4)
|
||||
#define MAX77620_CNFG_GPIO_INT_FALLING (1 << 4)
|
||||
#define MAX77620_CNFG_GPIO_INT_RISING (1 << 5)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_MASK (0x3 << 6)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_None (0x0 << 6)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_8ms (0x1 << 6)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_16ms (0x2 << 6)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_32ms (0x3 << 6)
|
||||
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE0 (1 << 0)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE1 (1 << 1)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE2 (1 << 2)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE3 (1 << 3)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE4 (1 << 4)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE5 (1 << 5)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE6 (1 << 6)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE7 (1 << 7)
|
||||
|
||||
#define MAX77620_CNFG1_32K_OUT0_EN (1 << 2)
|
||||
|
||||
#define MAX77620_ONOFFCNFG1_SFT_RST (1 << 7)
|
||||
#define MAX77620_ONOFFCNFG1_MRT_MASK 0x38
|
||||
#define MAX77620_ONOFFCNFG1_MRT_SHIFT 0x3
|
||||
#define MAX77620_ONOFFCNFG1_SLPEN (1 << 2)
|
||||
#define MAX77620_ONOFFCNFG1_PWR_OFF (1 << 1)
|
||||
#define MAX20024_ONOFFCNFG1_CLRSE 0x18
|
||||
|
||||
#define MAX77620_ONOFFCNFG2_SFT_RST_WK (1 << 7)
|
||||
#define MAX77620_ONOFFCNFG2_WD_RST_WK (1 << 6)
|
||||
#define MAX77620_ONOFFCNFG2_SLP_LPM_MSK (1 << 5)
|
||||
#define MAX77620_ONOFFCNFG2_WK_ALARM1 (1 << 2)
|
||||
#define MAX77620_ONOFFCNFG2_WK_EN0 (1 << 0)
|
||||
|
||||
#define MAX77620_GLBLM_MASK (1 << 0)
|
||||
|
||||
#define MAX77620_WDTC_MASK 0x3
|
||||
#define MAX77620_WDTOFFC (1 << 4)
|
||||
#define MAX77620_WDTSLPC (1 << 3)
|
||||
#define MAX77620_WDTEN (1 << 2)
|
||||
|
||||
#define MAX77620_TWD_MASK 0x3
|
||||
#define MAX77620_TWD_2s 0x0
|
||||
#define MAX77620_TWD_16s 0x1
|
||||
#define MAX77620_TWD_64s 0x2
|
||||
#define MAX77620_TWD_128s 0x3
|
||||
|
||||
#define MAX77620_CNFGGLBL1_LBDAC_EN (1 << 7)
|
||||
#define MAX77620_CNFGGLBL1_MPPLD (1 << 6)
|
||||
#define MAX77620_CNFGGLBL1_LBHYST ((1 << 5) | (1 << 4))
|
||||
#define MAX77620_CNFGGLBL1_LBHYST_N (1 << 4)
|
||||
#define MAX77620_CNFGGLBL1_LBDAC 0x0E
|
||||
#define MAX77620_CNFGGLBL1_LBDAC_N (1 << 1)
|
||||
#define MAX77620_CNFGGLBL1_LBRSTEN (1 << 0)
|
||||
|
||||
/* CNFG BBC registers */
|
||||
#define MAX77620_CNFGBBC_ENABLE (1 << 0)
|
||||
#define MAX77620_CNFGBBC_CURRENT_MASK 0x06
|
||||
#define MAX77620_CNFGBBC_CURRENT_SHIFT 1
|
||||
#define MAX77620_CNFGBBC_VOLTAGE_MASK 0x18
|
||||
#define MAX77620_CNFGBBC_VOLTAGE_SHIFT 3
|
||||
#define MAX77620_CNFGBBC_LOW_CURRENT_DISABLE (1 << 5)
|
||||
#define MAX77620_CNFGBBC_RESISTOR_MASK 0xC0
|
||||
#define MAX77620_CNFGBBC_RESISTOR_SHIFT 6
|
||||
|
||||
#define MAX77620_FPS_COUNT 3
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE0 (1 << 0)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE1 (1 << 1)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE2 (1 << 2)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE3 (1 << 3)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE4 (1 << 4)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE5 (1 << 5)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE6 (1 << 6)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE7 (1 << 7)
|
||||
|
||||
/* Interrupts */
|
||||
enum {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -27,12 +28,15 @@ typedef struct _max77620_regulator_t
|
||||
u8 type;
|
||||
const char *name;
|
||||
u8 reg_sd;
|
||||
|
||||
u32 mv_step;
|
||||
u32 mv_min;
|
||||
u32 mv_default;
|
||||
u32 mv_max;
|
||||
|
||||
u8 volt_addr;
|
||||
u8 cfg_addr;
|
||||
|
||||
u8 volt_mask;
|
||||
u8 enable_mask;
|
||||
u8 enable_shift;
|
||||
@@ -45,19 +49,19 @@ typedef struct _max77620_regulator_t
|
||||
} max77620_regulator_t;
|
||||
|
||||
static const max77620_regulator_t _pmic_regulators[] = {
|
||||
{ REGULATOR_SD, "sd0", 0x16, 12500, 600000, 625000, 1400000, MAX77620_REG_SD0, MAX77620_REG_SD0_CFG, 0x3F, 0x30, 4, 0x80, 0x4F, 1, 7, 1 },
|
||||
{ REGULATOR_SD, "sd1", 0x17, 12500, 600000, 1125000, 1125000, MAX77620_REG_SD1, MAX77620_REG_SD1_CFG, 0x3F, 0x30, 4, 0x40, 0x50, 0, 1, 5 },
|
||||
{ REGULATOR_SD, "sd2", 0x18, 12500, 600000, 1325000, 1350000, MAX77620_REG_SD2, MAX77620_REG_SD2_CFG, 0xFF, 0x30, 4, 0x20, 0x51, 1, 5, 2 },
|
||||
{ REGULATOR_SD, "sd3", 0x19, 12500, 600000, 1800000, 1800000, MAX77620_REG_SD3, MAX77620_REG_SD3_CFG, 0xFF, 0x30, 4, 0x10, 0x52, 0, 3, 3 },
|
||||
{ REGULATOR_LDO, "ldo0", 0x00, 25000, 800000, 1200000, 1200000, MAX77620_REG_LDO0_CFG, MAX77620_REG_LDO0_CFG2, 0x3F, 0xC0, 6, 0x00, 0x46, 3, 7, 0 },
|
||||
{ REGULATOR_LDO, "ldo1", 0x00, 25000, 800000, 1050000, 1050000, MAX77620_REG_LDO1_CFG, MAX77620_REG_LDO1_CFG2, 0x3F, 0xC0, 6, 0x00, 0x47, 3, 7, 0 },
|
||||
{ REGULATOR_LDO, "ldo2", 0x00, 50000, 800000, 1800000, 3300000, MAX77620_REG_LDO2_CFG, MAX77620_REG_LDO2_CFG2, 0x3F, 0xC0, 6, 0x00, 0x48, 3, 7, 0 },
|
||||
{ REGULATOR_LDO, "ldo3", 0x00, 50000, 800000, 3100000, 3100000, MAX77620_REG_LDO3_CFG, MAX77620_REG_LDO3_CFG2, 0x3F, 0xC0, 6, 0x00, 0x49, 3, 7, 0 },
|
||||
{ REGULATOR_LDO, "ldo4", 0x00, 12500, 800000, 850000, 850000, MAX77620_REG_LDO4_CFG, MAX77620_REG_LDO4_CFG2, 0x3F, 0xC0, 6, 0x00, 0x4A, 0, 7, 1 },
|
||||
{ REGULATOR_LDO, "ldo5", 0x00, 50000, 800000, 1800000, 1800000, MAX77620_REG_LDO5_CFG, MAX77620_REG_LDO5_CFG2, 0x3F, 0xC0, 6, 0x00, 0x4B, 3, 7, 0 },
|
||||
{ REGULATOR_LDO, "ldo6", 0x00, 50000, 800000, 2900000, 2900000, MAX77620_REG_LDO6_CFG, MAX77620_REG_LDO6_CFG2, 0x3F, 0xC0, 6, 0x00, 0x4C, 3, 7, 0 },
|
||||
{ REGULATOR_LDO, "ldo7", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO7_CFG, MAX77620_REG_LDO7_CFG2, 0x3F, 0xC0, 6, 0x00, 0x4D, 1, 4, 3 },
|
||||
{ REGULATOR_LDO, "ldo8", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO8_CFG, MAX77620_REG_LDO8_CFG2, 0x3F, 0xC0, 6, 0x00, 0x4E, 3, 7, 0 }
|
||||
{ REGULATOR_SD, "sd0", 0x16, 12500, 600000, 625000, 1400000, MAX77620_REG_SD0, MAX77620_REG_SD0_CFG, MAX77620_SD0_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x80, MAX77620_REG_FPS_SD0, 1, 7, 1 },
|
||||
{ REGULATOR_SD, "sd1", 0x17, 12500, 600000, 1125000, 1125000, MAX77620_REG_SD1, MAX77620_REG_SD1_CFG, MAX77620_SD1_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x40, MAX77620_REG_FPS_SD1, 0, 1, 5 },
|
||||
{ REGULATOR_SD, "sd2", 0x18, 12500, 600000, 1325000, 1350000, MAX77620_REG_SD2, MAX77620_REG_SD2_CFG, MAX77620_SDX_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x20, MAX77620_REG_FPS_SD2, 1, 5, 2 },
|
||||
{ REGULATOR_SD, "sd3", 0x19, 12500, 600000, 1800000, 1800000, MAX77620_REG_SD3, MAX77620_REG_SD3_CFG, MAX77620_SDX_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x10, MAX77620_REG_FPS_SD3, 0, 3, 3 },
|
||||
{ REGULATOR_LDO, "ldo0", 0x00, 25000, 800000, 1200000, 1200000, MAX77620_REG_LDO0_CFG, MAX77620_REG_LDO0_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO0, 3, 7, 0 },
|
||||
{ REGULATOR_LDO, "ldo1", 0x00, 25000, 800000, 1050000, 1050000, MAX77620_REG_LDO1_CFG, MAX77620_REG_LDO1_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO1, 3, 7, 0 },
|
||||
{ REGULATOR_LDO, "ldo2", 0x00, 50000, 800000, 1800000, 3300000, MAX77620_REG_LDO2_CFG, MAX77620_REG_LDO2_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO2, 3, 7, 0 },
|
||||
{ REGULATOR_LDO, "ldo3", 0x00, 50000, 800000, 3100000, 3100000, MAX77620_REG_LDO3_CFG, MAX77620_REG_LDO3_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO3, 3, 7, 0 },
|
||||
{ REGULATOR_LDO, "ldo4", 0x00, 12500, 800000, 850000, 850000, MAX77620_REG_LDO4_CFG, MAX77620_REG_LDO4_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO4, 0, 7, 1 },
|
||||
{ REGULATOR_LDO, "ldo5", 0x00, 50000, 800000, 1800000, 1800000, MAX77620_REG_LDO5_CFG, MAX77620_REG_LDO5_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO5, 3, 7, 0 },
|
||||
{ REGULATOR_LDO, "ldo6", 0x00, 50000, 800000, 2900000, 2900000, MAX77620_REG_LDO6_CFG, MAX77620_REG_LDO6_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO6, 3, 7, 0 },
|
||||
{ REGULATOR_LDO, "ldo7", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO7_CFG, MAX77620_REG_LDO7_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO7, 1, 4, 3 },
|
||||
{ REGULATOR_LDO, "ldo8", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO8_CFG, MAX77620_REG_LDO8_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO8, 3, 7, 0 }
|
||||
};
|
||||
|
||||
int max77620_regulator_get_status(u32 id)
|
||||
@@ -79,7 +83,8 @@ int max77620_regulator_config_fps(u32 id)
|
||||
|
||||
const max77620_regulator_t *reg = &_pmic_regulators[id];
|
||||
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->fps_addr, (reg->fps_src << 6) | (reg->pu_period << 3) | (reg->pd_period));
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->fps_addr,
|
||||
(reg->fps_src << MAX77620_FPS_SRC_SHIFT) | (reg->pu_period << MAX77620_FPS_PU_PERIOD_SHIFT) | (reg->pd_period));
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -91,7 +96,7 @@ int max77620_regulator_set_voltage(u32 id, u32 mv)
|
||||
|
||||
const max77620_regulator_t *reg = &_pmic_regulators[id];
|
||||
|
||||
if (mv < reg->mv_default || mv > reg->mv_max)
|
||||
if (mv < reg->mv_min || mv > reg->mv_max)
|
||||
return 0;
|
||||
|
||||
u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step;
|
||||
@@ -113,7 +118,7 @@ int max77620_regulator_enable(u32 id, int enable)
|
||||
u32 addr = reg->type == REGULATOR_SD ? reg->cfg_addr : reg->volt_addr;
|
||||
u8 val = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, addr);
|
||||
if (enable)
|
||||
val = (val & ~reg->enable_mask) | ((3 << reg->enable_shift) & reg->enable_mask);
|
||||
val = (val & ~reg->enable_mask) | ((MAX77620_POWER_MODE_NORMAL << reg->enable_shift) & reg->enable_mask);
|
||||
else
|
||||
val &= ~reg->enable_mask;
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, addr, val);
|
||||
@@ -122,6 +127,24 @@ int max77620_regulator_enable(u32 id, int enable)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags)
|
||||
{
|
||||
if (id > REGULATOR_MAX)
|
||||
return 0;
|
||||
|
||||
const max77620_regulator_t *reg = &_pmic_regulators[id];
|
||||
|
||||
if (mv < reg->mv_min || mv > reg->mv_max)
|
||||
return 0;
|
||||
|
||||
u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step;
|
||||
u8 val = ((flags << reg->enable_shift) & ~reg->volt_mask) | (mult & reg->volt_mask);
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->volt_addr, val);
|
||||
usleep(1000);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void max77620_config_default()
|
||||
{
|
||||
for (u32 i = 1; i <= REGULATOR_MAX; i++)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -30,10 +31,10 @@
|
||||
* ldo0 | Display Panel | 25000 | 800000 | 1200000 | 1200000 | 1.2V (pkg1.1)
|
||||
* ldo1 | XUSB, PCIE | 25000 | 800000 | 1050000 | 1050000 | 1.05V (pcv)
|
||||
* ldo2 | SDMMC1 | 50000 | 800000 | 1800000 | 3300000 |
|
||||
* ldo3 | | 50000 | 800000 | 3100000 | 3100000 |
|
||||
* ldo3 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv)
|
||||
* ldo4 | RTC | 12500 | 800000 | 850000 | 850000 |
|
||||
* ldo5 | | 50000 | 800000 | 1800000 | 1800000 |
|
||||
* ldo6 | | 50000 | 800000 | 2900000 | 2900000 |
|
||||
* ldo5 | GC ASIC | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv)
|
||||
* ldo6 | Touch, ALS | 50000 | 800000 | 2900000 | 2900000 | 2.9V
|
||||
* ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 |
|
||||
* ldo8 | XUSB, DC | 50000 | 800000 | 1050000 | 1050000 |
|
||||
*/
|
||||
@@ -108,6 +109,7 @@ int max77620_regulator_get_status(u32 id);
|
||||
int max77620_regulator_config_fps(u32 id);
|
||||
int max77620_regulator_set_voltage(u32 id, u32 mv);
|
||||
int max77620_regulator_enable(u32 id, int enable);
|
||||
int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags);
|
||||
void max77620_config_default();
|
||||
void max77620_low_battery_monitor_config();
|
||||
|
||||
|
||||
77
bootloader/rtc/max77620-rtc.c
Normal file
77
bootloader/rtc/max77620-rtc.c
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC
|
||||
*
|
||||
* Copyright (c) 2018 CTCaer
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "max77620-rtc.h"
|
||||
#include "../soc/i2c.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
void max77620_rtc_get_time(rtc_time_t *time)
|
||||
{
|
||||
u8 val = 0;
|
||||
|
||||
// Update RTC regs from RTC clock.
|
||||
i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_READ_UPDATE);
|
||||
|
||||
// Get control reg config.
|
||||
val = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_CONTROL_REG);
|
||||
// TODO: Check for binary format also?
|
||||
|
||||
// Get time.
|
||||
time->sec = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_SEC_REG) & 0x7F;
|
||||
time->min = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MIN_REG) & 0x7F;
|
||||
|
||||
time->hour = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_HOUR_REG) & 0x1F;
|
||||
|
||||
if (!(val & MAX77620_RTC_24H) && time->hour & MAX77620_RTC_HOUR_PM_MASK)
|
||||
time->hour = (time->hour & 0xF) + 12;
|
||||
|
||||
// Get day of week. 1: Monday to 7: Sunday.
|
||||
time->weekday = 0;
|
||||
val = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_WEEKDAY_REG);
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
time->weekday++;
|
||||
if (val & 1)
|
||||
break;
|
||||
val >>= 1;
|
||||
}
|
||||
|
||||
// Get date.
|
||||
time->date = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_DATE_REG) & 0x1f;
|
||||
time->month = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MONTH_REG) & 0xF) - 1;
|
||||
time->year = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_YEAR_REG) & 0x7F) + 2000;
|
||||
}
|
||||
|
||||
void max77620_rtc_stop_alarm()
|
||||
{
|
||||
u8 val = 0;
|
||||
|
||||
// Update RTC regs from RTC clock.
|
||||
i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_READ_UPDATE);
|
||||
|
||||
// Stop alarm for both ALARM1 and ALARM2. Horizon uses ALARM2.
|
||||
for (int i = 0; i < (MAX77620_RTC_NR_TIME_REGS * 2); i++)
|
||||
{
|
||||
val = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM1_SEC_REG + i);
|
||||
val &= ~MAX77620_RTC_ALARM_EN_MASK;
|
||||
i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM1_SEC_REG + i, val);
|
||||
}
|
||||
|
||||
// Update RTC clock from RTC regs.
|
||||
i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_WRITE_UPDATE);
|
||||
}
|
||||
75
bootloader/rtc/max77620-rtc.h
Normal file
75
bootloader/rtc/max77620-rtc.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC
|
||||
*
|
||||
* Copyright (c) 2018 CTCaer
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _MFD_MAX77620_RTC_H_
|
||||
#define _MFD_MAX77620_RTC_H_
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
#define MAX77620_RTC_I2C_ADDR 0x68
|
||||
|
||||
#define MAX77620_RTC_NR_TIME_REGS 7
|
||||
|
||||
#define MAX77620_RTC_CONTROLM_REG 0x02
|
||||
#define MAX77620_RTC_CONTROL_REG 0x03
|
||||
#define MAX77620_RTC_BIN_FORMAT (1 << 0)
|
||||
#define MAX77620_RTC_24H (1 << 1)
|
||||
|
||||
#define MAX77620_RTC_UPDATE0_REG 0x04
|
||||
#define MAX77620_RTC_WRITE_UPDATE (1 << 0)
|
||||
#define MAX77620_RTC_READ_UPDATE (1 << 4)
|
||||
|
||||
#define MAX77620_RTC_SEC_REG 0x07
|
||||
#define MAX77620_RTC_MIN_REG 0x08
|
||||
#define MAX77620_RTC_HOUR_REG 0x09
|
||||
#define MAX77620_RTC_HOUR_PM_MASK (1 << 6)
|
||||
#define MAX77620_RTC_WEEKDAY_REG 0x0A
|
||||
#define MAX77620_RTC_MONTH_REG 0x0B
|
||||
#define MAX77620_RTC_YEAR_REG 0x0C
|
||||
#define MAX77620_RTC_DATE_REG 0x0D
|
||||
|
||||
#define MAX77620_ALARM1_SEC_REG 0x0E
|
||||
#define MAX77620_ALARM1_MIN_REG 0x0F
|
||||
#define MAX77620_ALARM1_HOUR_REG 0x10
|
||||
#define MAX77620_ALARM1_WEEKDAY_REG 0x11
|
||||
#define MAX77620_ALARM1_MONTH_REG 0x12
|
||||
#define MAX77620_ALARM1_YEAR_REG 0x13
|
||||
#define MAX77620_ALARM1_DATE_REG 0x14
|
||||
#define MAX77620_ALARM2_SEC_REG 0x15
|
||||
#define MAX77620_ALARM2_MIN_REG 0x16
|
||||
#define MAX77620_ALARM2_HOUR_REG 0x17
|
||||
#define MAX77620_ALARM2_WEEKDAY_REG 0x18
|
||||
#define MAX77620_ALARM2_MONTH_REG 0x19
|
||||
#define MAX77620_ALARM2_YEAR_REG 0x1A
|
||||
#define MAX77620_ALARM2_DATE_REG 0x1B
|
||||
#define MAX77620_RTC_ALARM_EN_MASK (1 << 7)
|
||||
|
||||
typedef struct _rtc_time_t {
|
||||
u8 weekday;
|
||||
u8 sec;
|
||||
u8 min;
|
||||
u8 hour;
|
||||
u8 date;
|
||||
u8 month;
|
||||
u16 year;
|
||||
} rtc_time_t;
|
||||
|
||||
void max77620_rtc_get_time(rtc_time_t *time);
|
||||
void max77620_rtc_stop_alarm();
|
||||
|
||||
#endif /* _MFD_MAX77620_RTC_H_ */
|
||||
@@ -270,15 +270,15 @@ int se_calc_sha256(void *dst, const void *src, u32 src_size)
|
||||
int res;
|
||||
// Setup config for SHA256, size = BITS(src_size).
|
||||
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_SHA256) | SE_CONFIG_ENC_ALG(ALG_SHA) | SE_CONFIG_DST(DST_HASHREG);
|
||||
SE(SE_SHA_CONFIG_REG_OFFSET) = 1;
|
||||
SE(SE_SHA_CONFIG_REG_OFFSET) = SHA_ENABLE;
|
||||
SE(SE_SHA_MSG_LENGTH_REG_OFFSET) = (u32)(src_size << 3);
|
||||
SE(0x208) = 0;
|
||||
SE(0x20C) = 0;
|
||||
SE(0x210) = 0;
|
||||
SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 1) = 0;
|
||||
SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 2) = 0;
|
||||
SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 3) = 0;
|
||||
SE(SE_SHA_MSG_LEFT_REG_OFFSET) = (u32)(src_size << 3);
|
||||
SE(0x218) = 0;
|
||||
SE(0x21C) = 0;
|
||||
SE(0x220) = 0;
|
||||
SE(SE_SHA_MSG_LEFT_REG_OFFSET + 4 * 1) = 0;
|
||||
SE(SE_SHA_MSG_LEFT_REG_OFFSET + 4 * 2) = 0;
|
||||
SE(SE_SHA_MSG_LEFT_REG_OFFSET + 4 * 3) = 0;
|
||||
|
||||
// Trigger the operation.
|
||||
res = _se_execute(OP_START, NULL, 0, src, src_size);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
* Copyright (c) 2018 balika011
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -17,16 +19,23 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "../sec/tsec.h"
|
||||
#include "../sec/tsec_t210.h"
|
||||
#include "../sec/se_t210.h"
|
||||
#include "../soc/clock.h"
|
||||
#include "../soc/smmu.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../mem/mc.h"
|
||||
#include "../utils/util.h"
|
||||
#include "../hos/hos.h"
|
||||
|
||||
// #include "../gfx/gfx.h"
|
||||
|
||||
static int _tsec_dma_wait_idle()
|
||||
{
|
||||
u32 timeout = get_tmr_ms() + 10000;
|
||||
|
||||
while (!(TSEC(0x1118) & 2))
|
||||
while (!(TSEC(TSEC_DMATRFCMD) & TSEC_DMATRFCMD_IDLE))
|
||||
if (get_tmr_ms() > timeout)
|
||||
return 0;
|
||||
|
||||
@@ -38,20 +47,23 @@ static int _tsec_dma_pa_to_internal_100(int not_imem, int i_offset, int pa_offse
|
||||
u32 cmd;
|
||||
|
||||
if (not_imem)
|
||||
cmd = 0x600; // DMA 0x100 bytes
|
||||
cmd = TSEC_DMATRFCMD_SIZE_256B; // DMA 256 bytes
|
||||
else
|
||||
cmd = 0x10; // dma imem
|
||||
cmd = TSEC_DMATRFCMD_IMEM; // DMA IMEM (Instruction memmory)
|
||||
|
||||
TSEC(0x1114) = i_offset; // tsec_dmatrfmoffs_r
|
||||
TSEC(0x111C) = pa_offset; // tsec_dmatrffboffs_r
|
||||
TSEC(0x1118) = cmd; // tsec_dmatrfcmd_r
|
||||
TSEC(TSEC_DMATRFMOFFS) = i_offset;
|
||||
TSEC(TSEC_DMATRFFBOFFS) = pa_offset;
|
||||
TSEC(TSEC_DMATRFCMD) = cmd;
|
||||
|
||||
return _tsec_dma_wait_idle();
|
||||
}
|
||||
|
||||
int tsec_query(u8 *dst, u32 rev, void *fw)
|
||||
int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
{
|
||||
int res = 0;
|
||||
u8 *fwbuf = NULL;
|
||||
u32 *pdir, *car, *fuse, *pmc, *flowctrl, *se, *mc, *iram, *evec;
|
||||
u32 *pkg11_magic_off;
|
||||
|
||||
//Enable clocks.
|
||||
clock_enable_host1x();
|
||||
@@ -62,64 +74,192 @@ int tsec_query(u8 *dst, u32 rev, void *fw)
|
||||
clock_enable_kfuse();
|
||||
|
||||
//Configure Falcon.
|
||||
TSEC(0x110C) = 0; // tsec_dmactl_r
|
||||
TSEC(0x1010) = 0xFFF2; // tsec_irqmset_r
|
||||
TSEC(0x101C) = 0xFFF0; // tsec_irqdest_r
|
||||
TSEC(0x1048) = 3; // tsec_itfen_r
|
||||
TSEC(TSEC_DMACTL) = 0;
|
||||
TSEC(TSEC_IRQMSET) =
|
||||
TSEC_IRQMSET_EXT(0xFF) |
|
||||
TSEC_IRQMSET_WDTMR |
|
||||
TSEC_IRQMSET_HALT |
|
||||
TSEC_IRQMSET_EXTERR |
|
||||
TSEC_IRQMSET_SWGEN0 |
|
||||
TSEC_IRQMSET_SWGEN1;
|
||||
TSEC(TSEC_IRQDEST) =
|
||||
TSEC_IRQDEST_EXT(0xFF) |
|
||||
TSEC_IRQDEST_HALT |
|
||||
TSEC_IRQDEST_EXTERR |
|
||||
TSEC_IRQDEST_SWGEN0 |
|
||||
TSEC_IRQDEST_SWGEN1;
|
||||
TSEC(TSEC_ITFEN) = TSEC_ITFEN_CTXEN | TSEC_ITFEN_MTHDEN;
|
||||
if (!_tsec_dma_wait_idle())
|
||||
{
|
||||
res = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
//Load firmware.
|
||||
u8 *fwbuf = (u8 *)malloc(0x2000);
|
||||
u8 *fwbuf_aligned = (u8 *)ALIGN((u32)fwbuf + 0x1000, 0x100);
|
||||
memcpy(fwbuf_aligned, fw, 0xF00);
|
||||
TSEC(0x1110) = (u32)fwbuf_aligned >> 8;// tsec_dmatrfbase_r
|
||||
for (u32 addr = 0; addr < 0xF00; addr += 0x100)
|
||||
if (!_tsec_dma_pa_to_internal_100(0, addr, addr))
|
||||
//Load firmware or emulate memio environment for newer TSEC fw.
|
||||
if (kb == KB_FIRMWARE_VERSION_620)
|
||||
TSEC(TSEC_DMATRFBASE) = (u32)tsec_ctxt->fw >> 8;
|
||||
else
|
||||
{
|
||||
fwbuf = (u8 *)malloc(0x4000);
|
||||
u8 *fwbuf_aligned = (u8 *)ALIGN((u32)fwbuf, 0x100);
|
||||
memcpy(fwbuf_aligned, tsec_ctxt->fw, tsec_ctxt->size);
|
||||
TSEC(TSEC_DMATRFBASE) = (u32)fwbuf_aligned >> 8;
|
||||
}
|
||||
|
||||
for (u32 addr = 0; addr < tsec_ctxt->size; addr += 0x100)
|
||||
{
|
||||
if (!_tsec_dma_pa_to_internal_100(false, addr, addr))
|
||||
{
|
||||
res = -2;
|
||||
goto out_free;
|
||||
}
|
||||
}
|
||||
|
||||
if (kb == KB_FIRMWARE_VERSION_620)
|
||||
{
|
||||
// Init SMMU translation for TSEC.
|
||||
pdir = smmu_init_for_tsec();
|
||||
smmu_init(tsec_ctxt->secmon_base);
|
||||
// Enable SMMU
|
||||
if (!smmu_is_used())
|
||||
smmu_enable();
|
||||
|
||||
// Clock reset controller.
|
||||
car = page_alloc(1);
|
||||
memcpy(car, (void *)CLOCK_BASE, 0x1000);
|
||||
car[CLK_RST_CONTROLLER_CLK_SOURCE_TSEC / 4] = 2;
|
||||
smmu_map(pdir, CLOCK_BASE, (u32)car, 1, _WRITABLE | _READABLE | _NONSECURE);
|
||||
|
||||
// Fuse driver.
|
||||
fuse = page_alloc(1);
|
||||
memcpy((void *)&fuse[0x800/4], (void *)FUSE_BASE, 0x400);
|
||||
fuse[0x82C / 4] = 0;
|
||||
fuse[0x9E0 / 4] = (1 << (kb + 2)) - 1;
|
||||
fuse[0x9E4 / 4] = (1 << (kb + 2)) - 1;
|
||||
smmu_map(pdir, (FUSE_BASE - 0x800), (u32)fuse, 1, _READABLE | _NONSECURE);
|
||||
|
||||
// Power management controller.
|
||||
pmc = page_alloc(1);
|
||||
smmu_map(pdir, RTC_BASE, (u32)pmc, 1, _READABLE | _NONSECURE);
|
||||
|
||||
// Flow control.
|
||||
flowctrl = page_alloc(1);
|
||||
smmu_map(pdir, FLOW_CTLR_BASE, (u32)flowctrl, 1, _WRITABLE | _NONSECURE);
|
||||
|
||||
// Security engine.
|
||||
se = page_alloc(1);
|
||||
memcpy(se, (void *)SE_BASE, 0x1000);
|
||||
smmu_map(pdir, SE_BASE, (u32)se, 1, _READABLE | _WRITABLE | _NONSECURE);
|
||||
|
||||
// Memory controller.
|
||||
mc = page_alloc(1);
|
||||
memcpy(mc, (void *)MC_BASE, 0x1000);
|
||||
mc[MC_IRAM_BOM / 4] = 0;
|
||||
mc[MC_IRAM_TOM / 4] = 0x80000000;
|
||||
smmu_map(pdir, MC_BASE, (u32)mc, 1, _READABLE | _NONSECURE);
|
||||
|
||||
// IRAM
|
||||
iram = page_alloc(0x30);
|
||||
memcpy(iram, tsec_ctxt->pkg1, 0x30000);
|
||||
// PKG1.1 magic offset.
|
||||
pkg11_magic_off = (u32 *)(iram + ((tsec_ctxt->pkg11_off + 0x20) / 4));
|
||||
smmu_map(pdir, 0x40010000, (u32)iram, 0x30, _READABLE | _WRITABLE | _NONSECURE);
|
||||
|
||||
// Exception vectors
|
||||
evec = page_alloc(1);
|
||||
smmu_map(pdir, EXCP_VEC_BASE, (u32)evec, 1, _READABLE | _WRITABLE | _NONSECURE);
|
||||
}
|
||||
|
||||
//Execute firmware.
|
||||
HOST1X(0x3300) = 0x34C2E1DA;
|
||||
TSEC(0x1044) = 0;
|
||||
TSEC(0x1040) = rev;
|
||||
TSEC(0x1104) = 0; // tsec_bootvec_r
|
||||
TSEC(0x1100) = 2; // tsec_cpuctl_r
|
||||
if (!_tsec_dma_wait_idle())
|
||||
TSEC(TSEC_STATUS) = 0;
|
||||
TSEC(TSEC_BOOTKEYVER) = 1; // HOS uses key version 1.
|
||||
TSEC(TSEC_BOOTVEC) = 0;
|
||||
TSEC(TSEC_CPUCTL) = TSEC_CPUCTL_STARTCPU;
|
||||
|
||||
if (kb == KB_FIRMWARE_VERSION_620)
|
||||
{
|
||||
res = -3;
|
||||
goto out_free;
|
||||
}
|
||||
u32 timeout = get_tmr_ms() + 2000;
|
||||
while (!TSEC(0x1044))
|
||||
if (get_tmr_ms() > timeout)
|
||||
u32 start = get_tmr_us();
|
||||
u32 k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4];
|
||||
u32 key[16] = {0};
|
||||
u32 kidx = 0;
|
||||
|
||||
while (*pkg11_magic_off != HOS_PKG11_MAGIC)
|
||||
{
|
||||
res = -4;
|
||||
smmu_flush_all();
|
||||
|
||||
if (k == se[SE_KEYTABLE_DATA0_REG_OFFSET / 4])
|
||||
continue;
|
||||
k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4];
|
||||
key[kidx++] = k;
|
||||
|
||||
// Failsafe.
|
||||
if ((u32)get_tmr_us() - start > 125000)
|
||||
break;
|
||||
}
|
||||
|
||||
if (kidx != 8)
|
||||
{
|
||||
res = -6;
|
||||
smmu_deinit_for_tsec();
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Give some extra time to make sure PKG1.1 is decrypted.
|
||||
msleep(50);
|
||||
|
||||
memcpy(tsec_keys, &key, 0x20);
|
||||
memcpy(tsec_ctxt->pkg1, iram, 0x30000);
|
||||
|
||||
smmu_deinit_for_tsec();
|
||||
|
||||
// for (int i = 0; i < kidx; i++)
|
||||
// gfx_printf(&gfx_con, "key %08X\n", key[i]);
|
||||
|
||||
// gfx_printf(&gfx_con, "cpuctl (%08X) mbox (%08X)\n", TSEC(TSEC_CPUCTL), TSEC(TSEC_STATUS));
|
||||
|
||||
// u32 errst = MC(MC_ERR_STATUS);
|
||||
// gfx_printf(&gfx_con, " MC %08X %08X %08X\n", MC(MC_INTSTATUS), errst, MC(MC_ERR_ADR));
|
||||
// gfx_printf(&gfx_con, " type: %02X\n", errst >> 28);
|
||||
// gfx_printf(&gfx_con, " smmu: %02X\n", (errst >> 25) & 3);
|
||||
// gfx_printf(&gfx_con, " dir: %s\n", (errst >> 16) & 1 ? "W" : "R");
|
||||
// gfx_printf(&gfx_con, " cid: %02x\n", errst & 0xFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_tsec_dma_wait_idle())
|
||||
{
|
||||
res = -3;
|
||||
goto out_free;
|
||||
}
|
||||
u32 timeout = get_tmr_ms() + 2000;
|
||||
while (!TSEC(TSEC_STATUS))
|
||||
if (get_tmr_ms() > timeout)
|
||||
{
|
||||
res = -4;
|
||||
goto out_free;
|
||||
}
|
||||
if (TSEC(TSEC_STATUS) != 0xB0B0B0B0)
|
||||
{
|
||||
res = -5;
|
||||
goto out_free;
|
||||
}
|
||||
if (TSEC(0x1044) != 0xB0B0B0B0)
|
||||
{
|
||||
res = -5;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
//Fetch result.
|
||||
HOST1X(0x3300) = 0;
|
||||
u32 buf[4];
|
||||
buf[0] = SOR1(0x1E8);
|
||||
buf[1] = SOR1(0x21C);
|
||||
buf[2] = SOR1(0x208);
|
||||
buf[3] = SOR1(0x20C);
|
||||
SOR1(0x1E8) = 0;
|
||||
SOR1(0x21C) = 0;
|
||||
SOR1(0x208) = 0;
|
||||
SOR1(0x20C) = 0;
|
||||
memcpy(dst, &buf, 0x10);
|
||||
//Fetch result.
|
||||
HOST1X(0x3300) = 0;
|
||||
u32 buf[4];
|
||||
buf[0] = SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB);
|
||||
buf[1] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB);
|
||||
buf[2] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB);
|
||||
buf[3] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB);
|
||||
SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB) = 0;
|
||||
SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB) = 0;
|
||||
SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB) = 0;
|
||||
SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB) = 0;
|
||||
|
||||
memcpy(tsec_keys, &buf, 0x10);
|
||||
}
|
||||
|
||||
out_free:;
|
||||
free(fwbuf);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -19,6 +20,15 @@
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
int tsec_query(u8 *dst, u32 rev, void *fw);
|
||||
typedef struct _tsec_ctxt_t
|
||||
{
|
||||
void *fw;
|
||||
u32 size;
|
||||
void *pkg1;
|
||||
u32 pkg11_off;
|
||||
u32 secmon_base;
|
||||
} tsec_ctxt_t;
|
||||
|
||||
int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt);
|
||||
|
||||
#endif
|
||||
|
||||
50
bootloader/sec/tsec_t210.h
Normal file
50
bootloader/sec/tsec_t210.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2018 CTCaer
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _TSEC_T210_H_
|
||||
#define _TSEC_T210_H_
|
||||
|
||||
#define TSEC_BOOTKEYVER 0x1040
|
||||
#define TSEC_STATUS 0x1044
|
||||
#define TSEC_ITFEN 0x1048
|
||||
#define TSEC_ITFEN_CTXEN (1 << 0)
|
||||
#define TSEC_ITFEN_MTHDEN (1 << 1)
|
||||
#define TSEC_IRQMSET 0x1010
|
||||
#define TSEC_IRQMSET_WDTMR (1 << 1)
|
||||
#define TSEC_IRQMSET_HALT (1 << 4)
|
||||
#define TSEC_IRQMSET_EXTERR (1 << 5)
|
||||
#define TSEC_IRQMSET_SWGEN0 (1 << 6)
|
||||
#define TSEC_IRQMSET_SWGEN1 (1 << 7)
|
||||
#define TSEC_IRQMSET_EXT(val) (((val) & 0xFF) << 8)
|
||||
#define TSEC_IRQDEST 0x101C
|
||||
#define TSEC_IRQDEST_HALT (1 << 4)
|
||||
#define TSEC_IRQDEST_EXTERR (1 << 5)
|
||||
#define TSEC_IRQDEST_SWGEN0 (1 << 6)
|
||||
#define TSEC_IRQDEST_SWGEN1 (1 << 7)
|
||||
#define TSEC_IRQDEST_EXT(val) (((val) & 0xFF) << 8)
|
||||
#define TSEC_CPUCTL 0x1100
|
||||
#define TSEC_CPUCTL_STARTCPU (1 << 1)
|
||||
#define TSEC_BOOTVEC 0x1104
|
||||
#define TSEC_DMACTL 0x110C
|
||||
#define TSEC_DMATRFBASE 0x1110
|
||||
#define TSEC_DMATRFMOFFS 0x1114
|
||||
#define TSEC_DMATRFCMD 0x1118
|
||||
#define TSEC_DMATRFCMD_IDLE (1 << 1)
|
||||
#define TSEC_DMATRFCMD_IMEM (1 << 4)
|
||||
#define TSEC_DMATRFCMD_SIZE_256B (6 << 8)
|
||||
#define TSEC_DMATRFFBOFFS 0x111C
|
||||
|
||||
#endif
|
||||
@@ -19,37 +19,61 @@
|
||||
#include "../utils/util.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
|
||||
/* clock_t: reset, enable, source, index, clk_src, clk_div */
|
||||
|
||||
static const clock_t _clock_uart[] = {
|
||||
/* UART A */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, 6, 0, 0 },
|
||||
/* UART B */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, 7, 0, 0 },
|
||||
/* UART C */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, 0x17, 0, 0 },
|
||||
/* UART D */ { 0 },
|
||||
/* UART E */ { 0 }
|
||||
/* UART A */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, 6, 0, 0 },
|
||||
/* UART B */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, 7, 0, 0 },
|
||||
/* UART C */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, 0x17, 0, 0 },
|
||||
/* UART D */ { 0 },
|
||||
/* UART E */ { 0 }
|
||||
};
|
||||
|
||||
static const clock_t _clock_i2c[] = {
|
||||
/* I2C1 */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, 0xC, 6, 0 },
|
||||
/* I2C2 */ { 0 },
|
||||
/* I2C3 */ { 0 },
|
||||
/* I2C4 */ { 0 },
|
||||
/* I2C5 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, 0xF, 6, 0 },
|
||||
/* I2C6 */ { 0 }
|
||||
/* I2C1 */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, 0xC, 6, 0 },
|
||||
/* I2C2 */ { 0 },
|
||||
/* I2C3 */ { 0 },
|
||||
/* I2C4 */ { 0 },
|
||||
/* I2C5 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, 0xF, 6, 0 },
|
||||
/* I2C6 */ { 0 }
|
||||
};
|
||||
|
||||
static clock_t _clock_se = { CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_SE, 0x1F, 0, 0 };
|
||||
static clock_t _clock_unk2 = { CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_RST_SOURCE, 0x1E, 0, 0 };
|
||||
static clock_t _clock_se = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_SE, 0x1F, 0, 0
|
||||
};
|
||||
static clock_t _clock_unk2 = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_NO_SOURCE, 0x1E, 0, 0
|
||||
};
|
||||
|
||||
static clock_t _clock_host1x = { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, 0x1C, 4, 3 };
|
||||
static clock_t _clock_tsec = { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_TSEC, 0x13, 0, 2 };
|
||||
static clock_t _clock_sor_safe = { CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_RST_SOURCE, 0x1E, 0, 0 };
|
||||
static clock_t _clock_sor0 = { CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_RST_SOURCE, 0x16, 0, 0 };
|
||||
static clock_t _clock_sor1 = { CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, 0x17, 0, 2 };
|
||||
static clock_t _clock_kfuse = { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_RST_SOURCE, 8, 0, 0 };
|
||||
static clock_t _clock_host1x = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, 0x1C, 4, 3
|
||||
};
|
||||
static clock_t _clock_tsec = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_TSEC, 0x13, 0, 2
|
||||
};
|
||||
static clock_t _clock_sor_safe = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_NO_SOURCE, 0x1E, 0, 0
|
||||
};
|
||||
static clock_t _clock_sor0 = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_NO_SOURCE, 0x16, 0, 0
|
||||
};
|
||||
static clock_t _clock_sor1 = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, 0x17, 0, 2
|
||||
};
|
||||
static clock_t _clock_kfuse = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_NO_SOURCE, 8, 0, 0
|
||||
};
|
||||
|
||||
static clock_t _clock_cl_dvfs = { CLK_RST_CONTROLLER_RST_DEVICES_W, CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_RST_CONTROLLER_RST_SOURCE, 0x1B, 0, 0 };
|
||||
static clock_t _clock_coresight = { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, 9, 0, 4};
|
||||
static clock_t _clock_cl_dvfs = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_W, CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_NO_SOURCE, 0x1B, 0, 0
|
||||
};
|
||||
static clock_t _clock_coresight = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, 9, 0, 4
|
||||
};
|
||||
|
||||
static clock_t _clock_pwm = { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, 0x11, 6, 4};
|
||||
static clock_t _clock_pwm = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, 0x11, 6, 4
|
||||
};
|
||||
|
||||
void clock_enable(const clock_t *clk)
|
||||
{
|
||||
@@ -157,11 +181,11 @@ void clock_disable_sor1()
|
||||
void clock_enable_kfuse()
|
||||
{
|
||||
//clock_enable(&_clock_kfuse);
|
||||
CLOCK(0x8) = (CLOCK(0x8) & 0xFFFFFEFF) | 0x100;
|
||||
CLOCK(0x14) &= 0xFFFFFEFF;
|
||||
CLOCK(0x14) = (CLOCK(0x14) & 0xFFFFFEFF) | 0x100;
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) = (CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) & 0xFFFFFEFF) | 0x100;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) &= 0xFFFFFEFF;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = (CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) & 0xFFFFFEFF) | 0x100;
|
||||
usleep(10);
|
||||
CLOCK(0x8) &= 0xFFFFFEFF;
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) &= 0xFFFFFEFF;
|
||||
usleep(20);
|
||||
}
|
||||
|
||||
|
||||
@@ -116,6 +116,8 @@
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_NVENC 0x6A0
|
||||
#define CLK_RST_CONTROLLER_SE_SUPER_CLK_DIVIDER 0x704
|
||||
|
||||
#define CLK_NO_SOURCE 0x0
|
||||
|
||||
/*! Generic clock descriptor. */
|
||||
typedef struct _clock_t
|
||||
{
|
||||
|
||||
@@ -25,15 +25,17 @@
|
||||
|
||||
void _cluster_enable_power()
|
||||
{
|
||||
u8 tmp = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO);
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO, tmp & 0xDF);
|
||||
u8 tmp = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO); // Get current pinmuxing
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO, tmp & ~(1 << 5)); // Disable GPIO5 pinmuxing.
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, MAX77620_CNFG_GPIO_DRV_PUSHPULL | MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH);
|
||||
|
||||
// Enable cores power.
|
||||
// 1-3.x: MAX77621_NFSR_ENABLE.
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL1_REG,
|
||||
MAX77621_AD_ENABLE | MAX77621_NFSR_ENABLE | MAX77621_SNS_ENABLE); // 1-3.x: MAX77621_NFSR_ENABLE
|
||||
MAX77621_AD_ENABLE | MAX77621_NFSR_ENABLE | MAX77621_SNS_ENABLE);
|
||||
// 1.0.0-3.x: MAX77621_T_JUNCTION_120 | MAX77621_CKKADV_TRIP_DISABLE | MAX77621_INDUCTOR_NOMINAL.
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL2_REG,
|
||||
MAX77621_T_JUNCTION_120 | MAX77621_WDTMR_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US| MAX77621_INDUCTOR_NOMINAL); // 1-3.x: MAX77621_T_JUNCTION_120 | MAX77621_CKKADV_TRIP_DISABLE | MAX77621_INDUCTOR_NOMINAL
|
||||
MAX77621_T_JUNCTION_120 | MAX77621_WDTMR_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US| MAX77621_INDUCTOR_NOMINAL);
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_ENABLE | 0x37);
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | 0x37);
|
||||
}
|
||||
@@ -112,7 +114,7 @@ void cluster_boot_cpu0(u32 entry)
|
||||
while (!(FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) & 2))
|
||||
;
|
||||
|
||||
EXCP_VEC(0x100) = 0;
|
||||
EXCP_VEC(EVP_CPU_RESET_VECTOR) = 0;
|
||||
|
||||
// Set reset vector.
|
||||
SB(SB_AA64_RESET_LOW) = entry | 1;
|
||||
@@ -125,6 +127,7 @@ void cluster_boot_cpu0(u32 entry)
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_V) &= 0xFFFFFFF7;
|
||||
// Clear NONCPU reset.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = 0x20000000;
|
||||
// Clear CPU{0,1,2,3} POR and CORE, CX0, L2, and DBG reset.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = 0x411F000F;
|
||||
// Clear CPU0 reset.
|
||||
// < 5.x: 0x411F000F, Clear CPU{0,1,2,3} POR and CORE, CX0, L2, and DBG reset.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = 0x41010001;
|
||||
}
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
#include "../utils/types.h"
|
||||
|
||||
/*! Flow controller registers. */
|
||||
#define LOW_CTLR_HALT_CPU0_EVENTS 0x0
|
||||
#define LOW_CTLR_HALT_CPU1_EVENTS 0x14
|
||||
#define LOW_CTLR_HALT_CPU2_EVENTS 0x1C
|
||||
#define LOW_CTLR_HALT_CPU3_EVENTS 0x24
|
||||
#define FLOW_CTLR_HALT_CPU0_EVENTS 0x0
|
||||
#define FLOW_CTLR_HALT_CPU1_EVENTS 0x14
|
||||
#define FLOW_CTLR_HALT_CPU2_EVENTS 0x1C
|
||||
#define FLOW_CTLR_HALT_CPU3_EVENTS 0x24
|
||||
#define FLOW_CTLR_HALT_COP_EVENTS 0x4
|
||||
#define FLOW_CTLR_CPU0_CSR 0x8
|
||||
#define FLOW_CTLR_CPU1_CSR 0x18
|
||||
|
||||
@@ -222,7 +222,7 @@ int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value))
|
||||
{
|
||||
for (u32 i = 0; i < ipatch_count; i++)
|
||||
{
|
||||
u32 word = words[i];
|
||||
u32 word = words[i + 1];
|
||||
u32 addr = (word >> 16) * 2;
|
||||
u32 data = word & 0xffff;
|
||||
|
||||
|
||||
@@ -36,7 +36,12 @@
|
||||
#define FUSE_DISABLEREGPROGRAM 0x2C
|
||||
#define FUSE_WRITE_ACCESS_SW 0x30
|
||||
#define FUSE_PWR_GOOD_SW 0x34
|
||||
#define FUSE_SKU_INFO 0x110
|
||||
#define FUSE_FIRST_BOOTROM_PATCH_SIZE 0x19c
|
||||
#define FUSE_PRIVATE_KEY0 0x1A4
|
||||
#define FUSE_PRIVATE_KEY1 0x1A8
|
||||
#define FUSE_PRIVATE_KEY2 0x1AC
|
||||
#define FUSE_PRIVATE_KEY3 0x1B0
|
||||
|
||||
/*! Fuse commands. */
|
||||
#define FUSE_READ 0x1
|
||||
|
||||
281
bootloader/soc/hw_init.c
Normal file
281
bootloader/soc/hw_init.c
Normal file
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "hw_init.h"
|
||||
#include "../gfx/di.h"
|
||||
#include "../mem/mc.h"
|
||||
#include "../mem/sdram.h"
|
||||
#include "../power/max77620.h"
|
||||
#include "../power/max7762x.h"
|
||||
#include "../sec/se.h"
|
||||
#include "../sec/se_t210.h"
|
||||
#include "../soc/clock.h"
|
||||
#include "../soc/fuse.h"
|
||||
#include "../soc/gpio.h"
|
||||
#include "../soc/i2c.h"
|
||||
#include "../soc/pinmux.h"
|
||||
#include "../soc/pmc.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../soc/uart.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
extern sdmmc_t sd_sdmmc;
|
||||
extern boot_cfg_t b_cfg;
|
||||
|
||||
void _config_oscillators()
|
||||
{
|
||||
CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) = (CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) & 0xFFFFFFF3) | 4;
|
||||
SYSCTR0(SYSCTR0_CNTFID0) = 19200000;
|
||||
TMR(TIMERUS_USEC_CFG) = 0x45F; // For 19.2MHz clk_m.
|
||||
CLOCK(CLK_RST_CONTROLLER_OSC_CTRL) = 0x50000071;
|
||||
PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFFFFF81) | 0xE;
|
||||
PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFBFFFFF) | 0x400000;
|
||||
PMC(APBDEV_PMC_CNTRL2) = (PMC(APBDEV_PMC_CNTRL2) & 0xFFFFEFFF) | 0x1000;
|
||||
PMC(APBDEV_PMC_SCRATCH188) = (PMC(APBDEV_PMC_SCRATCH188) & 0xFCFFFFFF) | 0x2000000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 0x10;
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) &= 0xBFFFFFFF;
|
||||
PMC(APBDEV_PMC_TSC_MULT) = (PMC(APBDEV_PMC_TSC_MULT) & 0xFFFF0000) | 0x249F; //0x249F = 19200000 * (16 / 32.768 kHz)
|
||||
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20004444;
|
||||
CLOCK(CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER) = 0x80000000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2;
|
||||
}
|
||||
|
||||
void _config_gpios()
|
||||
{
|
||||
PINMUX_AUX(PINMUX_AUX_UART2_TX) = 0;
|
||||
PINMUX_AUX(PINMUX_AUX_UART3_TX) = 0;
|
||||
|
||||
PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE;
|
||||
PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE;
|
||||
|
||||
#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_B
|
||||
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO);
|
||||
#endif
|
||||
#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_C
|
||||
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||
#endif
|
||||
gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_GPIO);
|
||||
gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_GPIO);
|
||||
gpio_output_enable(GPIO_PORT_G, GPIO_PIN_0, GPIO_OUTPUT_DISABLE);
|
||||
gpio_output_enable(GPIO_PORT_D, GPIO_PIN_1, GPIO_OUTPUT_DISABLE);
|
||||
gpio_output_enable(GPIO_PORT_E, GPIO_PIN_6, GPIO_OUTPUT_DISABLE);
|
||||
gpio_output_enable(GPIO_PORT_H, GPIO_PIN_6, GPIO_OUTPUT_DISABLE);
|
||||
|
||||
pinmux_config_i2c(I2C_1);
|
||||
pinmux_config_i2c(I2C_5);
|
||||
pinmux_config_uart(UART_A);
|
||||
|
||||
// Configure volume up/down as inputs.
|
||||
gpio_config(GPIO_PORT_X, GPIO_PIN_6, GPIO_MODE_GPIO);
|
||||
gpio_config(GPIO_PORT_X, GPIO_PIN_7, GPIO_MODE_GPIO);
|
||||
gpio_output_enable(GPIO_PORT_X, GPIO_PIN_6, GPIO_OUTPUT_DISABLE);
|
||||
gpio_output_enable(GPIO_PORT_X, GPIO_PIN_7, GPIO_OUTPUT_DISABLE);
|
||||
}
|
||||
|
||||
void _config_pmc_scratch()
|
||||
{
|
||||
PMC(APBDEV_PMC_SCRATCH20) &= 0xFFF3FFFF;
|
||||
PMC(APBDEV_PMC_SCRATCH190) &= 0xFFFFFFFE;
|
||||
PMC(APBDEV_PMC_SECURE_SCRATCH21) |= 0x10;
|
||||
}
|
||||
|
||||
void _mbist_workaround()
|
||||
{
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= (1 << 10); // Enable AHUB clock.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock.
|
||||
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) | 0x8000) & 0xFFFFBFFF;
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) |= 0x40800000u;
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_CLR) = 0x40;
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_CLR) = 0x40000;
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000;
|
||||
usleep(2);
|
||||
|
||||
I2S(I2S1_CTRL) |= I2S_CTRL_MASTER_EN;
|
||||
I2S(I2S1_CG) &= ~I2S_CG_SLCG_ENABLE;
|
||||
I2S(I2S2_CTRL) |= I2S_CTRL_MASTER_EN;
|
||||
I2S(I2S2_CG) &= ~I2S_CG_SLCG_ENABLE;
|
||||
I2S(I2S3_CTRL) |= I2S_CTRL_MASTER_EN;
|
||||
I2S(I2S3_CG) &= ~I2S_CG_SLCG_ENABLE;
|
||||
I2S(I2S4_CTRL) |= I2S_CTRL_MASTER_EN;
|
||||
I2S(I2S4_CG) &= ~I2S_CG_SLCG_ENABLE;
|
||||
I2S(I2S5_CTRL) |= I2S_CTRL_MASTER_EN;
|
||||
I2S(I2S5_CG) &= ~I2S_CG_SLCG_ENABLE;
|
||||
DISPLAY_A(_DIREG(DC_COM_DSC_TOP_CTL)) |= 4;
|
||||
VIC(0x8C) = 0xFFFFFFFF;
|
||||
usleep(2);
|
||||
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_SET) = 0x40;
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000;
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_SET) = 0x40000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = 0xC0;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80000130;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) = 0x1F00200;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = 0x80400808;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_W) = 0x402000FC;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) = 0x23000780;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) = 0x300;
|
||||
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA) = 0;
|
||||
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB) = 0;
|
||||
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC) = 0;
|
||||
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) = 0;
|
||||
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE) = 0;
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) &= 0x1F7FFFFF;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) &= 0xFFFF3FFF;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) & 0x1FFFFFFF) | 0x80000000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) & 0x1FFFFFFF) | 0x80000000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) & 0x1FFFFFFF) | 0x80000000;
|
||||
}
|
||||
|
||||
void _config_se_brom()
|
||||
{
|
||||
// Skip SBK/SSK if sept was run.
|
||||
if (!(b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN))
|
||||
{
|
||||
// Bootrom part we skipped.
|
||||
u32 sbk[4] = {
|
||||
FUSE(FUSE_PRIVATE_KEY0),
|
||||
FUSE(FUSE_PRIVATE_KEY1),
|
||||
FUSE(FUSE_PRIVATE_KEY2),
|
||||
FUSE(FUSE_PRIVATE_KEY3)
|
||||
};
|
||||
// Set SBK to slot 14.
|
||||
se_aes_key_set(14, sbk, 0x10);
|
||||
|
||||
// Lock SBK from being read.
|
||||
SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 14 * 4) = 0x7E;
|
||||
|
||||
// Lock SSK (although it's not set and unused anyways).
|
||||
SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 15 * 4) = 0x7E;
|
||||
}
|
||||
|
||||
// This memset needs to happen here, else TZRAM will behave weirdly later on.
|
||||
memset((void *)TZRAM_BASE, 0, 0x10000);
|
||||
PMC(APBDEV_PMC_CRYPTO_OP) = PMC_CRYPTO_OP_SE_ENABLE;
|
||||
SE(SE_INT_STATUS_REG_OFFSET) = 0x1F;
|
||||
|
||||
// Clear the boot reason to avoid problems later
|
||||
PMC(APBDEV_PMC_SCRATCH200) = 0x0;
|
||||
PMC(APBDEV_PMC_RST_STATUS) = 0x0;
|
||||
APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) = (APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) & 0xF0) | (7 << 10);
|
||||
}
|
||||
|
||||
void config_hw()
|
||||
{
|
||||
// Bootrom stuff we skipped by going through rcm.
|
||||
_config_se_brom();
|
||||
//FUSE(FUSE_PRIVATEKEYDISABLE) = 0x11;
|
||||
SYSREG(AHB_AHB_SPARE_REG) &= 0xFFFFFF9F;
|
||||
PMC(APBDEV_PMC_SCRATCH49) = ((PMC(APBDEV_PMC_SCRATCH49) >> 1) << 1) & 0xFFFFFFFD;
|
||||
|
||||
_mbist_workaround();
|
||||
clock_enable_se();
|
||||
|
||||
// Enable fuse clock.
|
||||
clock_enable_fuse(true);
|
||||
// Disable fuse programming.
|
||||
fuse_disable_program();
|
||||
|
||||
mc_enable();
|
||||
|
||||
_config_oscillators();
|
||||
APB_MISC(APB_MISC_PP_PINMUX_GLOBAL) = 0;
|
||||
_config_gpios();
|
||||
|
||||
#ifdef DEBUG_UART_PORT
|
||||
clock_enable_uart(DEBUG_UART_PORT);
|
||||
uart_init(DEBUG_UART_PORT, 115200);
|
||||
#endif
|
||||
|
||||
clock_enable_cl_dvfs();
|
||||
|
||||
clock_enable_i2c(I2C_1);
|
||||
clock_enable_i2c(I2C_5);
|
||||
|
||||
clock_enable_unk2();
|
||||
|
||||
i2c_init(I2C_1);
|
||||
i2c_init(I2C_5);
|
||||
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CNFGBBC, MAX77620_CNFGBBC_RESISTOR_1K);
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1,
|
||||
(1 << 6) | (3 << MAX77620_ONOFFCNFG1_MRT_SHIFT)); // PWR delay for forced shutdown off.
|
||||
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG0,
|
||||
(7 << MAX77620_FPS_TIME_PERIOD_SHIFT));
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG1,
|
||||
(7 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (1 << MAX77620_FPS_EN_SRC_SHIFT));
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG2,
|
||||
(7 << MAX77620_FPS_TIME_PERIOD_SHIFT));
|
||||
max77620_regulator_config_fps(REGULATOR_LDO4);
|
||||
max77620_regulator_config_fps(REGULATOR_LDO8);
|
||||
max77620_regulator_config_fps(REGULATOR_SD0);
|
||||
max77620_regulator_config_fps(REGULATOR_SD1);
|
||||
max77620_regulator_config_fps(REGULATOR_SD3);
|
||||
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_GPIO3,
|
||||
(4 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (2 << MAX77620_FPS_PD_PERIOD_SHIFT)); // 3.x+
|
||||
|
||||
max77620_regulator_set_voltage(REGULATOR_SD0, 1125000);
|
||||
|
||||
// Fix GPU after warmboot for Linux.
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, 2);
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO6, 2);
|
||||
|
||||
_config_pmc_scratch(); // Missing from 4.x+
|
||||
|
||||
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = (CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) & 0xFFFF8888) | 0x3333;
|
||||
|
||||
sdram_init();
|
||||
}
|
||||
|
||||
void reconfig_hw_workaround(bool extra_reconfig, u32 magic)
|
||||
{
|
||||
// Re-enable clocks to Audio Processing Engine as a workaround to hanging.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= (1 << 10); // Enable AHUB clock.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock.
|
||||
|
||||
if (extra_reconfig)
|
||||
{
|
||||
msleep(10);
|
||||
PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_SDMMC1_IO_EN;
|
||||
|
||||
clock_disable_cl_dvfs();
|
||||
|
||||
// Disable Joy-con GPIOs.
|
||||
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);
|
||||
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
|
||||
gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_SPIO);
|
||||
gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_SPIO);
|
||||
}
|
||||
|
||||
// Power off display.
|
||||
display_end();
|
||||
|
||||
// Enable clock to USBD and init SDMMC1 to avoid hangs with bad hw inits.
|
||||
if (magic == 0xBAADF00D)
|
||||
{
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) |= (1 << 22);
|
||||
sdmmc_init(&sd_sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, 5, 0);
|
||||
clock_disable_cl_dvfs();
|
||||
|
||||
msleep(200);
|
||||
}
|
||||
}
|
||||
26
bootloader/soc/hw_init.h
Normal file
26
bootloader/soc/hw_init.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018 CTCaer
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _HW_INIT_H_
|
||||
#define _HW_INIT_H_
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
void config_hw();
|
||||
void reconfig_hw_workaround(bool extra_reconfig, u32 magic);
|
||||
|
||||
#endif
|
||||
@@ -19,8 +19,8 @@
|
||||
|
||||
void pinmux_config_uart(u32 idx)
|
||||
{
|
||||
PINMUX_AUX(PINMUX_AUX_UARTX_RX(idx)) = 0;
|
||||
PINMUX_AUX(PINMUX_AUX_UARTX_TX(idx)) = PINMUX_INPUT_ENABLE | PINMUX_PULL_UP;
|
||||
PINMUX_AUX(PINMUX_AUX_UARTX_TX(idx)) = 0;
|
||||
PINMUX_AUX(PINMUX_AUX_UARTX_RX(idx)) = PINMUX_INPUT_ENABLE | PINMUX_PULL_UP;
|
||||
PINMUX_AUX(PINMUX_AUX_UARTX_RTS(idx)) = 0;
|
||||
PINMUX_AUX(PINMUX_AUX_UARTX_CTS(idx)) = PINMUX_INPUT_ENABLE | PINMUX_PULL_DOWN;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#define _PMC_H_
|
||||
|
||||
/*! PMC registers. */
|
||||
#define APBDEV_PMC_CNTRL 0x0
|
||||
#define PMC_CNTRL_MAIN_RST (1 << 4)
|
||||
#define APBDEV_PMC_SEC_DISABLE 0x4
|
||||
#define APBDEV_PMC_PWRGATE_TOGGLE 0x30
|
||||
#define APBDEV_PMC_PWRGATE_STATUS 0x38
|
||||
@@ -27,13 +29,21 @@
|
||||
#define APBDEV_PMC_SCRATCH1 0x54
|
||||
#define APBDEV_PMC_SCRATCH20 0xA0
|
||||
#define APBDEV_PMC_PWR_DET_VAL 0xE4
|
||||
#define PMC_PWR_DET_SDMMC1_IO_EN (1 << 12)
|
||||
#define APBDEV_PMC_DDR_PWR 0xE8
|
||||
#define APBDEV_PMC_CRYPTO_OP 0xF4
|
||||
#define PMC_CRYPTO_OP_SE_ENABLE 0
|
||||
#define PMC_CRYPTO_OP_SE_DISABLE 1
|
||||
#define APBDEV_PMC_SCRATCH33 0x120
|
||||
#define APBDEV_PMC_SCRATCH40 0x13C
|
||||
#define APBDEV_PMC_OSC_EDPD_OVER 0x1A4
|
||||
#define APBDEV_PMC_RST_STATUS 0x1B4
|
||||
#define APBDEV_PMC_IO_DPD_REQ 0x1B8
|
||||
#define APBDEV_PMC_IO_DPD2_REQ 0x1C0
|
||||
#define APBDEV_PMC_VDDP_SEL 0x1CC
|
||||
#define APBDEV_PMC_DDR_CFG 0x1D0
|
||||
#define APBDEV_PMC_SCRATCH45 0x234
|
||||
#define APBDEV_PMC_SCRATCH46 0x238
|
||||
#define APBDEV_PMC_SCRATCH49 0x244
|
||||
#define APBDEV_PMC_TSC_MULT 0x2B4
|
||||
#define APBDEV_PMC_SEC_DISABLE2 0x2C4
|
||||
@@ -44,6 +54,7 @@
|
||||
#define APBDEV_PMC_SECURE_SCRATCH32 0x360
|
||||
#define APBDEV_PMC_SECURE_SCRATCH49 0x3A4
|
||||
#define APBDEV_PMC_CNTRL2 0x440
|
||||
#define APBDEV_PMC_IO_DPD3_REQ 0x45C
|
||||
#define APBDEV_PMC_IO_DPD4_REQ 0x464
|
||||
#define APBDEV_PMC_UTMIP_PAD_CFG1 0x4C4
|
||||
#define APBDEV_PMC_UTMIP_PAD_CFG3 0x4CC
|
||||
|
||||
171
bootloader/soc/smmu.c
Normal file
171
bootloader/soc/smmu.c
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018 balika011
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "smmu.h"
|
||||
#include "../soc/cluster.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../mem/mc_t210.h"
|
||||
#include "../utils/util.h"
|
||||
#include "../utils/aarch64_util.h"
|
||||
|
||||
bool smmu_used = false;
|
||||
u8 *_pageheap = (u8 *)SMMU_HEAP_ADDR;
|
||||
|
||||
//Enabling SMMU requires a TZ secure write: MC(MC_SMMU_CONFIG) = 1;
|
||||
u8 smmu_payload[] __attribute__((aligned(16))) = {
|
||||
0x41, 0x01, 0x00, 0x58, // 0x00: LDR X1, =0x70019010
|
||||
0x20, 0x00, 0x80, 0xD2, // 0x04: MOV X0, #0x1
|
||||
0x20, 0x00, 0x00, 0xB9, // 0x08: STR W0, [X1]
|
||||
0x1F, 0x71, 0x08, 0xD5, // 0x0C: IC IALLUIS
|
||||
0x9F, 0x3B, 0x03, 0xD5, // 0x10: DSB ISH
|
||||
0xFE, 0xFF, 0xFF, 0x17, // 0x14: B loop
|
||||
0x00, 0x00, 0x80, 0xD2, // 0x18: MOV X0, #0x0
|
||||
0x20, 0x00, 0x00, 0xB9, // 0x1C: STR W0, [X1]
|
||||
0x80, 0x00, 0x00, 0x58, // 0x20: LDR X0, =0x4002B000
|
||||
0x00, 0x00, 0x1F, 0xD6, // 0x28: BR X0
|
||||
0x10, 0x90, 0x01, 0x70, // 0x28: MC_SMMU_CONFIG
|
||||
0x00, 0x00, 0x00, 0x00, // 0x2C:
|
||||
0x00, 0x00, 0x00, 0x00, // 0x30: secmon address
|
||||
0x00, 0x00, 0x00, 0x00 // 0x34:
|
||||
};
|
||||
|
||||
void *page_alloc(u32 num)
|
||||
{
|
||||
u8 *res = _pageheap;
|
||||
_pageheap += 0x1000 * num;
|
||||
memset(res, 0, 0x1000 * num);
|
||||
return res;
|
||||
}
|
||||
|
||||
u32 *smmu_alloc_pdir()
|
||||
{
|
||||
u32 *pdir = (u32 *)page_alloc(1);
|
||||
for (int pdn = 0; pdn < SMMU_PDIR_COUNT; pdn++)
|
||||
pdir[pdn] = _PDE_VACANT(pdn);
|
||||
return pdir;
|
||||
}
|
||||
|
||||
void smmu_flush_regs()
|
||||
{
|
||||
(void)MC(MC_SMMU_PTB_DATA);
|
||||
}
|
||||
|
||||
void smmu_flush_all()
|
||||
{
|
||||
MC(MC_SMMU_PTC_FLUSH) = 0;
|
||||
smmu_flush_regs();
|
||||
MC(MC_SMMU_TLB_FLUSH) = 0;
|
||||
smmu_flush_regs();
|
||||
}
|
||||
|
||||
void smmu_init(u32 secmon_base)
|
||||
{
|
||||
MC(MC_SMMU_PTB_ASID) = 0;
|
||||
MC(MC_SMMU_PTB_DATA) = 0;
|
||||
MC(MC_SMMU_TLB_CONFIG) = 0x30000030;
|
||||
MC(MC_SMMU_PTC_CONFIG) = 0x28000F3F;
|
||||
MC(MC_SMMU_PTC_FLUSH) = 0;
|
||||
MC(MC_SMMU_TLB_FLUSH) = 0;
|
||||
|
||||
// Set the secmon address
|
||||
*(u32 *)(smmu_payload + 0x30) = secmon_base;
|
||||
}
|
||||
|
||||
void smmu_enable()
|
||||
{
|
||||
if (smmu_used)
|
||||
return;
|
||||
|
||||
cluster_boot_cpu0((u32)smmu_payload);
|
||||
smmu_used = true;
|
||||
msleep(150);
|
||||
|
||||
smmu_flush_all();
|
||||
}
|
||||
|
||||
bool smmu_is_used()
|
||||
{
|
||||
return smmu_used;
|
||||
}
|
||||
|
||||
void smmu_exit()
|
||||
{
|
||||
*(uint32_t *)(smmu_payload + 0x14) = _NOP();
|
||||
}
|
||||
|
||||
u32 *smmu_init_domain4(u32 dev_base, u32 asid)
|
||||
{
|
||||
u32 *pdir = smmu_alloc_pdir();
|
||||
|
||||
MC(MC_SMMU_PTB_ASID) = asid;
|
||||
MC(MC_SMMU_PTB_DATA) = SMMU_MK_PDIR((u32)pdir, _PDIR_ATTR);
|
||||
smmu_flush_regs();
|
||||
|
||||
MC(dev_base) = 0x80000000 | (asid << 24) | (asid << 16) | (asid << 8) | (asid);
|
||||
smmu_flush_regs();
|
||||
|
||||
return pdir;
|
||||
}
|
||||
|
||||
u32 *smmu_get_pte(u32 *pdir, u32 iova)
|
||||
{
|
||||
u32 ptn = SMMU_ADDR_TO_PFN(iova);
|
||||
u32 pdn = SMMU_ADDR_TO_PDN(iova);
|
||||
u32 *ptbl;
|
||||
|
||||
if (pdir[pdn] != _PDE_VACANT(pdn))
|
||||
ptbl = (u32 *)((pdir[pdn] & SMMU_PFN_MASK) << SMMU_PDIR_SHIFT);
|
||||
else
|
||||
{
|
||||
ptbl = (u32 *)page_alloc(1);
|
||||
u32 addr = SMMU_PDN_TO_ADDR(pdn);
|
||||
for (int pn = 0; pn < SMMU_PTBL_COUNT; pn++, addr += SMMU_PAGE_SIZE)
|
||||
ptbl[pn] = _PTE_VACANT(addr);
|
||||
pdir[pdn] = SMMU_MK_PDE((u32)ptbl, _PDE_ATTR | _PDE_NEXT);
|
||||
smmu_flush_all();
|
||||
}
|
||||
|
||||
return &ptbl[ptn % SMMU_PTBL_COUNT];
|
||||
}
|
||||
|
||||
void smmu_map(u32 *pdir, u32 addr, u32 page, int cnt, u32 attr)
|
||||
{
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
u32 *pte = smmu_get_pte(pdir, addr);
|
||||
*pte = SMMU_ADDR_TO_PFN(page) | attr;
|
||||
addr += 0x1000;
|
||||
page += 0x1000;
|
||||
}
|
||||
smmu_flush_all();
|
||||
}
|
||||
|
||||
u32 *smmu_init_for_tsec()
|
||||
{
|
||||
return smmu_init_domain4(MC_SMMU_TSEC_ASID, 1);
|
||||
}
|
||||
|
||||
void smmu_deinit_for_tsec()
|
||||
{
|
||||
MC(MC_SMMU_PTB_ASID) = 1;
|
||||
MC(MC_SMMU_PTB_DATA) = 0;
|
||||
MC(MC_SMMU_TSEC_ASID) = 0;
|
||||
smmu_flush_regs();
|
||||
}
|
||||
|
||||
82
bootloader/soc/smmu.h
Normal file
82
bootloader/soc/smmu.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
#define SMMU_HEAP_ADDR 0xA0000000
|
||||
|
||||
#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_TSEC_ASID 0x294
|
||||
#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 SMMU_PDE_NEXT_SHIFT 28
|
||||
#define MC_SMMU_PTB_DATA_0_ASID_NONSECURE_SHIFT 29
|
||||
#define MC_SMMU_PTB_DATA_0_ASID_WRITABLE_SHIFT 30
|
||||
#define MC_SMMU_PTB_DATA_0_ASID_READABLE_SHIFT 31
|
||||
#define SMMU_PAGE_SHIFT 12
|
||||
#define SMMU_PAGE_SIZE (1 << SMMU_PAGE_SHIFT)
|
||||
#define SMMU_PDIR_COUNT 1024
|
||||
#define SMMU_PDIR_SIZE (sizeof(u32) * SMMU_PDIR_COUNT)
|
||||
#define SMMU_PTBL_COUNT 1024
|
||||
#define SMMU_PTBL_SIZE (sizeof(u32) * SMMU_PTBL_COUNT)
|
||||
#define SMMU_PDIR_SHIFT 12
|
||||
#define SMMU_PDE_SHIFT 12
|
||||
#define SMMU_PTE_SHIFT 12
|
||||
#define SMMU_PFN_MASK 0x000FFFFF
|
||||
#define SMMU_ADDR_TO_PFN(addr) ((addr) >> 12)
|
||||
#define SMMU_ADDR_TO_PDN(addr) ((addr) >> 22)
|
||||
#define SMMU_PDN_TO_ADDR(addr) ((pdn) << 22)
|
||||
#define _READABLE (1 << MC_SMMU_PTB_DATA_0_ASID_READABLE_SHIFT)
|
||||
#define _WRITABLE (1 << MC_SMMU_PTB_DATA_0_ASID_WRITABLE_SHIFT)
|
||||
#define _NONSECURE (1 << MC_SMMU_PTB_DATA_0_ASID_NONSECURE_SHIFT)
|
||||
#define _PDE_NEXT (1 << SMMU_PDE_NEXT_SHIFT)
|
||||
#define _MASK_ATTR (_READABLE | _WRITABLE | _NONSECURE)
|
||||
#define _PDIR_ATTR (_READABLE | _WRITABLE | _NONSECURE)
|
||||
#define _PDE_ATTR (_READABLE | _WRITABLE | _NONSECURE)
|
||||
#define _PDE_VACANT(pdn) (((pdn) << 10) | _PDE_ATTR)
|
||||
#define _PTE_ATTR (_READABLE | _WRITABLE | _NONSECURE)
|
||||
#define _PTE_VACANT(addr) (((addr) >> SMMU_PAGE_SHIFT) | _PTE_ATTR)
|
||||
#define SMMU_MK_PDIR(page, attr) (((page) >> SMMU_PDIR_SHIFT) | (attr))
|
||||
#define SMMU_MK_PDE(page, attr) (((page) >> SMMU_PDE_SHIFT) | (attr))
|
||||
|
||||
void *page_alloc(u32 num);
|
||||
u32 *smmu_alloc_pdir();
|
||||
void smmu_flush_regs();
|
||||
void smmu_flush_all();
|
||||
void smmu_init(u32 secmon_base);
|
||||
void smmu_enable();
|
||||
bool smmu_is_used();
|
||||
void smmu_exit();
|
||||
u32 *smmu_init_domain4(u32 dev_base, u32 asid);
|
||||
u32 *smmu_get_pte(u32 *pdir, u32 iova);
|
||||
void smmu_map(u32 *pdir, u32 addr, u32 page, int cnt, u32 attr);
|
||||
u32 *smmu_init_for_tsec();
|
||||
void smmu_deinit_for_tsec();
|
||||
@@ -56,8 +56,9 @@
|
||||
#define MC_BASE 0x70019000
|
||||
#define EMC_BASE 0x7001B000
|
||||
#define MIPI_CAL_BASE 0x700E3000
|
||||
#define I2S_BASE 0x702D1000
|
||||
#define CL_DVFS_BASE 0x70110000
|
||||
#define I2S_BASE 0x702D1000
|
||||
#define TZRAM_BASE 0x7C010000
|
||||
|
||||
#define _REG(base, off) *(vu32 *)((base) + (off))
|
||||
|
||||
@@ -99,10 +100,15 @@
|
||||
#define CL_DVFS(off) _REG(CL_DVFS_BASE, off)
|
||||
#define TEST_REG(off) _REG(0x0, off)
|
||||
|
||||
/*! EVP registers. */
|
||||
#define EVP_CPU_RESET_VECTOR 0x100
|
||||
|
||||
/*! Misc registers. */
|
||||
#define APB_MISC_PP_STRAPPING_OPT_A 0x08
|
||||
#define APB_MISC_PP_PINMUX_GLOBAL 0x40
|
||||
#define APB_MISC_GP_LCD_BL_PWM_CFGPADCTRL 0xA34
|
||||
#define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL 0xA98
|
||||
#define APB_MISC_GP_EMMC4_PAD_CFGPADCTRL 0xAB4
|
||||
#define APB_MISC_GP_WIFI_EN_CFGPADCTRL 0xB64
|
||||
#define APB_MISC_GP_WIFI_RST_CFGPADCTRL 0xB68
|
||||
|
||||
@@ -112,10 +118,70 @@
|
||||
|
||||
/*! Secure boot registers. */
|
||||
#define SB_CSR 0x0
|
||||
#define SB_AA64_RESET_LOW 0x30
|
||||
#define SB_AA64_RESET_LOW 0x30
|
||||
#define SB_AA64_RESET_HIGH 0x34
|
||||
|
||||
/*! SOR registers. */
|
||||
#define SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB 0x1E8
|
||||
#define SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB 0x21C
|
||||
#define SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB 0x208
|
||||
#define SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB 0x20C
|
||||
|
||||
/*! RTC registers. */
|
||||
#define APBDEV_RTC_SECONDS 0x8
|
||||
#define APBDEV_RTC_SHADOW_SECONDS 0xC
|
||||
#define APBDEV_RTC_MILLI_SECONDS 0x10
|
||||
|
||||
/*! SYSCTR0 registers. */
|
||||
#define SYSCTR0_CNTFID0 0x20
|
||||
#define SYSCTR0_CNTFID0 0x20
|
||||
#define SYSCTR0_CNTCR 0x00
|
||||
#define SYSCTR0_COUNTERID0 0xFE0
|
||||
#define SYSCTR0_COUNTERID1 0xFE4
|
||||
#define SYSCTR0_COUNTERID2 0xFE8
|
||||
#define SYSCTR0_COUNTERID3 0xFEC
|
||||
#define SYSCTR0_COUNTERID4 0xFD0
|
||||
#define SYSCTR0_COUNTERID5 0xFD4
|
||||
#define SYSCTR0_COUNTERID6 0xFD8
|
||||
#define SYSCTR0_COUNTERID7 0xFDC
|
||||
#define SYSCTR0_COUNTERID8 0xFF0
|
||||
#define SYSCTR0_COUNTERID9 0xFF4
|
||||
#define SYSCTR0_COUNTERID10 0xFF8
|
||||
#define SYSCTR0_COUNTERID11 0xFFC
|
||||
|
||||
/*! TMR registers. */
|
||||
#define TIMERUS_CNTR_1US (0x10 + 0x0)
|
||||
#define TIMERUS_USEC_CFG (0x10 + 0x4)
|
||||
#define TIMER_TMR9_TMR_PTV 0x80
|
||||
#define TIMER_EN (1 << 31)
|
||||
#define TIMER_PER_EN (1 << 30)
|
||||
#define TIMER_WDT4_CONFIG (0x100 + 0x80)
|
||||
#define TIMER_SRC(TMR) (TMR & 0xF)
|
||||
#define TIMER_PER(PER) ((PER & 0xFF) << 4)
|
||||
#define TIMER_SYSRESET_EN (1 << 14)
|
||||
#define TIMER_PMCRESET_EN (1 << 15)
|
||||
#define TIMER_WDT4_COMMAND (0x108 + 0x80)
|
||||
#define TIMER_START_CNT (1 << 0)
|
||||
#define TIMER_CNT_DISABLE (1 << 1)
|
||||
#define TIMER_WDT4_UNLOCK_PATTERN (0x10C + 0x80)
|
||||
#define TIMER_MAGIC_PTRN 0xC45A
|
||||
|
||||
/*! I2S registers. */
|
||||
#define I2S1_CG 0x88
|
||||
#define I2S1_CTRL 0xA0
|
||||
#define I2S2_CG 0x188
|
||||
#define I2S2_CTRL 0x1A0
|
||||
#define I2S3_CG 0x288
|
||||
#define I2S3_CTRL 0x2A0
|
||||
#define I2S4_CG 0x388
|
||||
#define I2S4_CTRL 0x3A0
|
||||
#define I2S5_CG 0x488
|
||||
#define I2S5_CTRL 0x4A0
|
||||
#define I2S_CG_SLCG_ENABLE (1 << 0)
|
||||
#define I2S_CTRL_MASTER_EN (1 << 10)
|
||||
|
||||
/*! Special registers. */
|
||||
#define EMC_SCRATCH0 0x324
|
||||
#define EMC_HEKA_UPD (1 << 30)
|
||||
#define EMC_SEPT_RUN (1 << 31)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -25,32 +25,37 @@ void uart_init(u32 idx, u32 baud)
|
||||
{
|
||||
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
|
||||
|
||||
//Set baud rate.
|
||||
u32 rate = (8 * baud + 408000000) / (16 * baud);
|
||||
uart->UART_LCR = 0x80; //Enable DLAB.
|
||||
uart->UART_THR_DLAB = (u8)rate; //Divisor latch LSB.
|
||||
uart->UART_IER_DLAB = (u8)(rate >> 8); //Divisor latch MSB.
|
||||
uart->UART_LCR = 0; //Diable DLAB.
|
||||
// Make sure no data is being sent.
|
||||
uart_wait_idle(idx, UART_TX_IDLE);
|
||||
|
||||
//Setup UART in fifo mode.
|
||||
uart->UART_IER_DLAB = 0;
|
||||
uart->UART_IIR_FCR = 7; //Enable and clear TX and RX FIFOs.
|
||||
(void)uart->UART_LSR;
|
||||
// Misc settings.
|
||||
u32 rate = (8 * baud + 408000000) / (16 * baud);
|
||||
uart->UART_IER_DLAB = 0; // Disable interrupts.
|
||||
uart->UART_MCR = 0; // Disable hardware flow control.
|
||||
uart->UART_LCR = UART_LCR_DLAB | UART_LCR_WORD_LENGTH_8; // Enable DLAB & set 8n1 mode.
|
||||
uart->UART_THR_DLAB = (u8)rate; // Divisor latch LSB.
|
||||
uart->UART_IER_DLAB = (u8)(rate >> 8); // Divisor latch MSB.
|
||||
uart->UART_LCR = UART_LCR_WORD_LENGTH_8; // Diable DLAB.
|
||||
|
||||
// Setup and flush fifo.
|
||||
uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO | UART_IIR_FCR_RX_CLR | UART_IIR_FCR_TX_CLR;
|
||||
usleep(3 * ((baud + 999999) / baud));
|
||||
uart->UART_LCR = 3; //Set word length 8.
|
||||
uart->UART_MCR = 0;
|
||||
uart->UART_MSR = 0;
|
||||
uart->UART_IRDA_CSR = 0;
|
||||
uart->UART_RX_FIFO_CFG = 1;
|
||||
uart->UART_MIE = 0;
|
||||
uart->UART_ASR = 0;
|
||||
uart_wait_idle(idx, UART_TX_IDLE | UART_RX_IDLE);
|
||||
}
|
||||
|
||||
void uart_wait_idle(u32 idx, u32 which)
|
||||
{
|
||||
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
|
||||
while (!(uart->UART_VENDOR_STATUS & which))
|
||||
;
|
||||
if (UART_TX_IDLE & which)
|
||||
{
|
||||
while (!(uart->UART_LSR & UART_LSR_TMTY))
|
||||
;
|
||||
}
|
||||
if (UART_RX_IDLE & which)
|
||||
{
|
||||
while (uart->UART_LSR & UART_LSR_RDR)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
void uart_send(u32 idx, u8 *buf, u32 len)
|
||||
@@ -59,7 +64,7 @@ void uart_send(u32 idx, u8 *buf, u32 len)
|
||||
|
||||
for (u32 i = 0; i != len; i++)
|
||||
{
|
||||
while (uart->UART_LSR & UART_TX_FIFO_FULL)
|
||||
while (!(uart->UART_LSR & UART_LSR_THRE))
|
||||
;
|
||||
uart->UART_THR_DLAB = buf[i];
|
||||
};
|
||||
@@ -71,7 +76,7 @@ void uart_recv(u32 idx, u8 *buf, u32 len)
|
||||
|
||||
for (u32 i = 0; i != len; i++)
|
||||
{
|
||||
while (uart->UART_LSR & UART_RX_FIFO_EMPTY)
|
||||
while (!(uart->UART_LSR & UART_LSR_RDR))
|
||||
;
|
||||
buf[i] = uart->UART_THR_DLAB;
|
||||
};
|
||||
|
||||
@@ -28,11 +28,21 @@
|
||||
|
||||
#define BAUD_115200 115200
|
||||
|
||||
#define UART_TX_IDLE 0x00000001
|
||||
#define UART_RX_IDLE 0x00000002
|
||||
#define UART_TX_IDLE 0x1
|
||||
#define UART_RX_IDLE 0x2
|
||||
|
||||
#define UART_TX_FIFO_FULL 0x100
|
||||
#define UART_RX_FIFO_EMPTY 0x200
|
||||
|
||||
#define UART_LCR_DLAB 0x80
|
||||
#define UART_LCR_WORD_LENGTH_8 0x3
|
||||
#define UART_LSR_RDR 0x1
|
||||
#define UART_LSR_THRE 0x20
|
||||
#define UART_LSR_TMTY 0x40
|
||||
#define UART_IIR_FCR_TX_CLR 0x4
|
||||
#define UART_IIR_FCR_RX_CLR 0x2
|
||||
#define UART_IIR_FCR_EN_FIFO 0x1
|
||||
|
||||
typedef struct _uart_t
|
||||
{
|
||||
/* 0x00 */ vu32 UART_THR_DLAB;
|
||||
|
||||
@@ -19,13 +19,11 @@
|
||||
#include "sdmmc.h"
|
||||
#include "mmc.h"
|
||||
#include "sd.h"
|
||||
#include "../utils/util.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
/*#include "gfx.h"
|
||||
extern gfx_ctxt_t gfx_ctxt;
|
||||
extern gfx_con_t gfx_con;
|
||||
#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)*/
|
||||
//#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
|
||||
#define DPRINTF(...)
|
||||
|
||||
static inline u32 unstuff_bits(u32 *resp, u32 start, u32 size)
|
||||
|
||||
@@ -17,20 +17,18 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "sdmmc.h"
|
||||
#include "../utils/util.h"
|
||||
#include "../soc/clock.h"
|
||||
#include "mmc.h"
|
||||
#include "sdmmc.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../power/max7762x.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../soc/pmc.h"
|
||||
#include "../soc/pinmux.h"
|
||||
#include "../soc/clock.h"
|
||||
#include "../soc/gpio.h"
|
||||
#include "../soc/pinmux.h"
|
||||
#include "../soc/pmc.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
/*#include "gfx.h"
|
||||
extern gfx_ctxt_t gfx_ctxt;
|
||||
extern gfx_con_t gfx_con;
|
||||
#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)*/
|
||||
//#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
|
||||
#define DPRINTF(...)
|
||||
|
||||
/*! SCMMC controller base addresses. */
|
||||
@@ -143,8 +141,20 @@ static int _sdmmc_get_clkcon(sdmmc_t *sdmmc)
|
||||
static void _sdmmc_pad_config_fallback(sdmmc_t *sdmmc, u32 power)
|
||||
{
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
if (sdmmc->id == SDMMC_4)
|
||||
*(vu32 *)0x70000AB4 = ((*(vu32 *)0x70000AB4) & 0x3FFC) | 0x1040;
|
||||
switch (sdmmc->id)
|
||||
{
|
||||
case SDMMC_1:
|
||||
if (power == SDMMC_POWER_OFF)
|
||||
break;
|
||||
if (power == SDMMC_POWER_1_8)
|
||||
APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = 0x304; // Up: 3, Dn: 4.
|
||||
else if (power == SDMMC_POWER_3_3)
|
||||
APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = 0x808; // Up: 8, Dn: 8.
|
||||
break;
|
||||
case SDMMC_4:
|
||||
APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) & 0x3FFC) | 0x1040;
|
||||
break;
|
||||
}
|
||||
//TODO: load standard values for other controllers, can depend on power.
|
||||
}
|
||||
|
||||
|
||||
@@ -22,9 +22,9 @@
|
||||
#include "util.h"
|
||||
#include "../power/max77620.h"
|
||||
|
||||
u32 btn_read()
|
||||
u8 btn_read()
|
||||
{
|
||||
u32 res = 0;
|
||||
u8 res = 0;
|
||||
if (!gpio_read(GPIO_PORT_X, GPIO_PIN_7))
|
||||
res |= BTN_VOL_DOWN;
|
||||
if (!gpio_read(GPIO_PORT_X, GPIO_PIN_6))
|
||||
@@ -34,9 +34,9 @@ u32 btn_read()
|
||||
return res;
|
||||
}
|
||||
|
||||
u32 btn_wait()
|
||||
u8 btn_wait()
|
||||
{
|
||||
u32 res = 0, btn = btn_read();
|
||||
u8 res = 0, btn = btn_read();
|
||||
bool pwr = false;
|
||||
|
||||
//Power button down, raise a filter.
|
||||
@@ -59,16 +59,18 @@ u32 btn_wait()
|
||||
return res;
|
||||
}
|
||||
|
||||
u32 btn_wait_timeout(u32 time_ms, u32 mask)
|
||||
u8 btn_wait_timeout(u32 time_ms, u8 mask)
|
||||
{
|
||||
u32 timeout = get_tmr_ms() + time_ms;
|
||||
u32 res = btn_read() & mask;
|
||||
u8 res = btn_read() & mask;
|
||||
|
||||
do
|
||||
while (get_tmr_ms() < timeout)
|
||||
{
|
||||
if (!(res & mask))
|
||||
if (res == mask)
|
||||
break;
|
||||
else
|
||||
res = btn_read() & mask;
|
||||
} while (get_tmr_ms() < timeout);
|
||||
};
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -20,12 +20,12 @@
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define BTN_POWER 0x1
|
||||
#define BTN_VOL_DOWN 0x2
|
||||
#define BTN_VOL_UP 0x4
|
||||
#define BTN_POWER (1 << 0)
|
||||
#define BTN_VOL_DOWN (1 << 1)
|
||||
#define BTN_VOL_UP (1 << 2)
|
||||
|
||||
u32 btn_read();
|
||||
u32 btn_wait();
|
||||
u32 btn_wait_timeout(u32 time_ms, u32 mask);
|
||||
u8 btn_read();
|
||||
u8 btn_wait();
|
||||
u8 btn_wait_timeout(u32 time_ms, u8 mask);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "../mem/heap.h"
|
||||
#include "../utils/types.h"
|
||||
|
||||
char *dirlist(const char *directory, const char *pattern)
|
||||
char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles)
|
||||
{
|
||||
u8 max_entries = 61;
|
||||
|
||||
@@ -40,7 +40,7 @@ char *dirlist(const char *directory, const char *pattern)
|
||||
res = f_readdir(&dir, &fno);
|
||||
if (res || !fno.fname[0])
|
||||
break;
|
||||
if (!(fno.fattrib & AM_DIR))
|
||||
if (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID)))
|
||||
{
|
||||
memcpy(dir_entries + (k * 256), fno.fname, strlen(fno.fname) + 1);
|
||||
k++;
|
||||
@@ -54,7 +54,7 @@ char *dirlist(const char *directory, const char *pattern)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (!(fno.fattrib & AM_DIR))
|
||||
if (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID)))
|
||||
{
|
||||
memcpy(dir_entries + (k * 256), fno.fname, strlen(fno.fname) + 1);
|
||||
k++;
|
||||
|
||||
@@ -16,4 +16,4 @@
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
char *dirlist(const char *directory, const char *pattern);
|
||||
char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles);
|
||||
|
||||
@@ -51,4 +51,37 @@ typedef int bool;
|
||||
#define true 1
|
||||
#define false 0
|
||||
|
||||
#define BOOT_CFG_AUTOBOOT_EN (1 << 0)
|
||||
#define BOOT_CFG_FROM_LAUNCH (1 << 1)
|
||||
#define BOOT_CFG_SEPT_RUN (1 << 7)
|
||||
|
||||
#define EXTRA_CFG_KEYS (1 << 0)
|
||||
#define EXTRA_CFG_PAYLOAD (1 << 1)
|
||||
#define EXTRA_CFG_MODULE (1 << 2)
|
||||
|
||||
typedef struct __attribute__((__packed__)) _boot_cfg_t
|
||||
{
|
||||
u8 boot_cfg;
|
||||
u8 autoboot;
|
||||
u8 autoboot_list;
|
||||
u8 extra_cfg;
|
||||
u8 rsvd[128];
|
||||
} boot_cfg_t;
|
||||
|
||||
typedef struct __attribute__((__packed__)) _ipl_ver_meta_t
|
||||
{
|
||||
u32 magic;
|
||||
u32 version;
|
||||
u16 rsvd0;
|
||||
u16 rsvd1;
|
||||
} ipl_ver_meta_t;
|
||||
|
||||
typedef struct __attribute__((__packed__)) _reloc_meta_t
|
||||
{
|
||||
u32 start;
|
||||
u32 stack;
|
||||
u32 end;
|
||||
u32 ep;
|
||||
} reloc_meta_t;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -16,36 +16,44 @@
|
||||
*/
|
||||
|
||||
#include "util.h"
|
||||
#include "../gfx/di.h"
|
||||
#include "../power/max77620.h"
|
||||
#include "../rtc/max77620-rtc.h"
|
||||
#include "../soc/i2c.h"
|
||||
#include "../soc/pmc.h"
|
||||
#include "../soc/t210.h"
|
||||
|
||||
extern void sd_unmount();
|
||||
|
||||
u32 get_tmr_s()
|
||||
{
|
||||
return RTC(0x8); //RTC_SECONDS
|
||||
return RTC(APBDEV_RTC_SECONDS);
|
||||
}
|
||||
|
||||
u32 get_tmr_ms()
|
||||
{
|
||||
// The registers must be read with the following order:
|
||||
// -> RTC_MILLI_SECONDS (0x10) -> RTC_SHADOW_SECONDS (0xC)
|
||||
return (RTC(0x10) | (RTC(0xC)<< 10));
|
||||
// RTC_MILLI_SECONDS (0x10) -> RTC_SHADOW_SECONDS (0xC)
|
||||
return (RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10));
|
||||
}
|
||||
|
||||
u32 get_tmr_us()
|
||||
{
|
||||
return TMR(0x10); //TIMERUS_CNTR_1US
|
||||
return TMR(TIMERUS_CNTR_1US); //TIMERUS_CNTR_1US
|
||||
}
|
||||
|
||||
void msleep(u32 milliseconds)
|
||||
{
|
||||
u32 start = RTC(0x10) | (RTC(0xC)<< 10);
|
||||
while (((RTC(0x10) | (RTC(0xC)<< 10)) - start) <= milliseconds)
|
||||
u32 start = RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10);
|
||||
while (((RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10)) - start) <= milliseconds)
|
||||
;
|
||||
}
|
||||
|
||||
void usleep(u32 microseconds)
|
||||
{
|
||||
u32 start = TMR(0x10);
|
||||
while ((TMR(0x10) - start) <= microseconds)
|
||||
u32 start = TMR(TIMERUS_CNTR_1US);
|
||||
// Casting to u32 is important!
|
||||
while ((u32)(TMR(TIMERUS_CNTR_1US) - start) <= microseconds)
|
||||
;
|
||||
}
|
||||
|
||||
@@ -55,6 +63,50 @@ void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops)
|
||||
base[ops[i].off] = ops[i].val;
|
||||
}
|
||||
|
||||
void panic(u32 val)
|
||||
{
|
||||
// Set panic code.
|
||||
PMC(APBDEV_PMC_SCRATCH200) = val;
|
||||
//PMC(APBDEV_PMC_CRYPTO_OP) = PMC_CRYPTO_OP_SE_DISABLE;
|
||||
TMR(TIMER_WDT4_UNLOCK_PATTERN) = TIMER_MAGIC_PTRN;
|
||||
TMR(TIMER_TMR9_TMR_PTV) = TIMER_EN | TIMER_PER_EN;
|
||||
TMR(TIMER_WDT4_CONFIG) = TIMER_SRC(9) | TIMER_PER(1) | TIMER_PMCRESET_EN;
|
||||
TMR(TIMER_WDT4_COMMAND) = TIMER_START_CNT;
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
void reboot_normal()
|
||||
{
|
||||
sd_unmount();
|
||||
display_end();
|
||||
|
||||
panic(0x21); // Bypass fuse programming in package1.
|
||||
}
|
||||
|
||||
void reboot_rcm()
|
||||
{
|
||||
sd_unmount();
|
||||
display_end();
|
||||
|
||||
PMC(APBDEV_PMC_SCRATCH0) = 2; // Reboot into rcm.
|
||||
PMC(APBDEV_PMC_CNTRL) |= PMC_CNTRL_MAIN_RST;
|
||||
|
||||
while (true)
|
||||
usleep(1);
|
||||
}
|
||||
|
||||
void power_off()
|
||||
{
|
||||
sd_unmount();
|
||||
|
||||
// Stop the alarm, in case we injected and powered off too fast.
|
||||
max77620_rtc_stop_alarm();
|
||||
|
||||
//TODO: we should probably make sure all regulators are powered off properly.
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_PWR_OFF);
|
||||
}
|
||||
|
||||
#define CRC32C_POLY 0x82F63B78
|
||||
u32 crc32c(const void *buf, u32 len)
|
||||
{
|
||||
@@ -68,31 +120,3 @@ u32 crc32c(const void *buf, u32 len)
|
||||
}
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
u32 memcmp32sparse(const u32 *buf1, const u32 *buf2, u32 len)
|
||||
{
|
||||
u32 len32 = len / 4;
|
||||
|
||||
if (!(len32 % 32))
|
||||
{
|
||||
while (len32)
|
||||
{
|
||||
len32 -= 32;
|
||||
if(buf1[len32] != buf2[len32])
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (len32)
|
||||
{
|
||||
len32 -= 32;
|
||||
if(buf1[len32] != buf2[len32])
|
||||
return 1;
|
||||
if (len32 < 32)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define byte_swap_32(num) ((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | \
|
||||
((num >> 8 )& 0xff00) | ((num << 24) & 0xff000000)
|
||||
#define byte_swap_32(num) (((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | \
|
||||
((num >> 8 )& 0xff00) | ((num << 24) & 0xff000000))
|
||||
|
||||
typedef struct _cfg_op_t
|
||||
{
|
||||
@@ -34,11 +34,11 @@ u32 get_tmr_ms();
|
||||
u32 get_tmr_s();
|
||||
void usleep(u32 ticks);
|
||||
void msleep(u32 milliseconds);
|
||||
void panic(u32 val);
|
||||
void reboot_normal();
|
||||
void reboot_rcm();
|
||||
void power_off();
|
||||
void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops);
|
||||
u32 crc32c(const void *buf, u32 len);
|
||||
|
||||
/* This is a faster implementation of memcmp that checks two u32 values */
|
||||
/* every 128 Bytes block. Intented only for Backup and Restore */
|
||||
u32 memcmp32sparse(const u32 *buf1, const u32 *buf2, u32 len);
|
||||
|
||||
#endif
|
||||
|
||||
32
modules/hekate_libsys_minerva/Makefile
Normal file
32
modules/hekate_libsys_minerva/Makefile
Normal file
@@ -0,0 +1,32 @@
|
||||
ifeq ($(strip $(DEVKITARM)),)
|
||||
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||
endif
|
||||
|
||||
include $(DEVKITARM)/base_rules
|
||||
|
||||
TARGET := libsys_minerva
|
||||
BUILD := ../../build/$(TARGET)
|
||||
OUTPUT := ../../output
|
||||
VPATH = $(dir $(wildcard ./*/)) $(dir $(wildcard ./*/*/))
|
||||
|
||||
OBJS = $(addprefix $(BUILD)/,\
|
||||
sys_sdrammtc.o \
|
||||
)
|
||||
|
||||
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork
|
||||
CFLAGS = $(ARCH) -O2 -nostdlib -fpie -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 -Wall $(CUSTOMDEFINES)
|
||||
LDFLAGS = $(ARCH) -fpie -pie -nostartfiles -lgcc
|
||||
|
||||
.PHONY: clean all
|
||||
|
||||
all: $(TARGET).bso
|
||||
$(BUILD)/%.o: ./%.c
|
||||
@mkdir -p "$(BUILD)"
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(TARGET).bso: $(OBJS)
|
||||
$(CC) $(LDFLAGS) -e _minerva_init $^ -o $(OUTPUT)/$(TARGET).bso
|
||||
$(STRIP) -g $(OUTPUT)/$(TARGET).bso
|
||||
|
||||
clean:
|
||||
@rm -rf $(OUTPUT)/$(TARGET).bso
|
||||
13
modules/hekate_libsys_minerva/README.md
Normal file
13
modules/hekate_libsys_minerva/README.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Minerva Training Cell
|
||||
|
||||
### Custom Nvidia Tegra X1 DRAM trainer.
|
||||
|
||||
For more, check [Here](https://github.com/CTCaer/minerva_tc).
|
||||
|
||||
|
||||
|
||||
```
|
||||
Minerva Training Cell (C) 2018 CTCaer.
|
||||
|
||||
/* Pain... And suffering. */
|
||||
```
|
||||
142
modules/hekate_libsys_minerva/mtc.h
Normal file
142
modules/hekate_libsys_minerva/mtc.h
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Minerva Training Cell
|
||||
* DRAM Training for Tegra X1 SoC. Supports DDR2/3 and LPDDR3/4.
|
||||
*
|
||||
* Copyright (c) 2018 CTCaer <ctcaer@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _MTC_H_
|
||||
#define _MTC_H_
|
||||
|
||||
#include "mtc_table.h"
|
||||
#include "types.h"
|
||||
|
||||
/* Address bases and access macros - Change these for mapped access */
|
||||
#define TMR_BASE 0x60005000
|
||||
#define CLOCK_BASE 0x60006000
|
||||
#define MC_BASE 0x70019000
|
||||
#define EMC_BASE 0x7001B000
|
||||
#define EMC0_BASE 0x7001E000
|
||||
#define EMC1_BASE 0x7001F000
|
||||
#define MTC_TABLE 0x8F000000
|
||||
|
||||
#define _REG(base, off) *(vu32 *)((base) + (off))
|
||||
|
||||
#define TMR(off) _REG(TMR_BASE, off)
|
||||
#define CLOCK(off) _REG(CLOCK_BASE, off)
|
||||
#define MC(off) _REG(MC_BASE, off)
|
||||
#define EMC(off) _REG(EMC_BASE, off)
|
||||
#define EMC_CH0(off) _REG(EMC0_BASE, off)
|
||||
#define EMC_CH1(off) _REG(EMC1_BASE, off)
|
||||
/* End of addresses and access macros */
|
||||
|
||||
#define EMC_TABLE_SIZE_R7 49280
|
||||
#define EMC_TABLE_ENTRY_SIZE_R7 4928
|
||||
#define EMC_STATUS_UPDATE_TIMEOUT 1000
|
||||
#define EMC_PERIODIC_TRAIN_MS 100
|
||||
#define EMC_TEMP_COMP_MS 1000
|
||||
|
||||
typedef struct
|
||||
{
|
||||
s32 rate_to;
|
||||
s32 rate_from;
|
||||
emc_table_t *mtc_table;
|
||||
u32 table_entries;
|
||||
emc_table_t *current_emc_table;
|
||||
u32 train_mode;
|
||||
u32 sdram_id;
|
||||
u32 prev_temp;
|
||||
bool emc_2X_clk_src_is_pllmb;
|
||||
bool fsp_for_src_freq;
|
||||
bool train_ram_patterns;
|
||||
} mtc_config_t;
|
||||
|
||||
enum train_mode_t
|
||||
{
|
||||
OP_SWITCH = 0,
|
||||
OP_TRAIN = 1,
|
||||
OP_TRAIN_SWITCH = 2,
|
||||
OP_PERIODIC_TRAIN = 3,
|
||||
OP_TEMP_COMP = 4
|
||||
};
|
||||
|
||||
enum comp_seq_t
|
||||
{
|
||||
DVFS_SEQUENCE = 1,
|
||||
WRITE_TRAINING_SEQUENCE = 2,
|
||||
PERIODIC_TRAINING_SEQUENCE = 3
|
||||
};
|
||||
|
||||
enum tree_update_mode_t
|
||||
{
|
||||
DVFS_PT1 = 10,
|
||||
DVFS_UPDATE = 11,
|
||||
TRAINING_PT1 = 12,
|
||||
TRAINING_UPDATE = 13,
|
||||
PERIODIC_TRAINING_UPDATE = 14
|
||||
};
|
||||
|
||||
enum emc_channels
|
||||
{
|
||||
EMC_CH0 = 0,
|
||||
EMC_CH1 = 1
|
||||
};
|
||||
|
||||
enum EMC_2X_CLK_SRC
|
||||
{
|
||||
PLLM_OUT0 = 0x0,
|
||||
PLLC_OUT0 = 0x1,
|
||||
PLLP_OUT0 = 0x2,
|
||||
CLK_M = 0x3,
|
||||
PLLM_UD = 0x4,
|
||||
PLLMB_UD = 0x5,
|
||||
PLLMB_OUT0 = 0x6,
|
||||
PLLP_UD = 0x7
|
||||
};
|
||||
|
||||
enum DRAM_TYPE
|
||||
{
|
||||
DRAM_TYPE_DDR3 = 0,
|
||||
DRAM_TYPE_LPDDR4 = 1,
|
||||
DRAM_TYPE_LPDDR2 = 2,
|
||||
DRAM_TYPE_DDR2 = 3
|
||||
};
|
||||
|
||||
enum DRAM_DEV_NO
|
||||
{
|
||||
ONE_RANK = 1,
|
||||
TWO_RANK = 2
|
||||
};
|
||||
|
||||
enum DRAM_OVER_TEMP_REF
|
||||
{
|
||||
REFRESH_X2 = 1,
|
||||
REFRESH_X4 = 2
|
||||
};
|
||||
|
||||
/* Timers for the below two compensation functions should be paused when changing timings. */
|
||||
|
||||
/* Change refresh rate based on dram temps. Run every 1000ms. */
|
||||
/* Timer should be run only when another component reports over temperature. */
|
||||
void _minerva_do_over_temp_compensation(mtc_config_t *mtc_cfg);
|
||||
|
||||
/* Periodic compensation only for tight timings that need it. Run every 100ms. */
|
||||
/* Over temp and periodic compensation, should not access EMC_MRR at the same time. */
|
||||
u32 _minerva_do_periodic_compensation(emc_table_t *mtc_table_entry);
|
||||
|
||||
/* Main function used to access all Minerva functions. */
|
||||
void _minerva_init(mtc_config_t *mtc_cfg, void* bp);
|
||||
|
||||
#endif
|
||||
626
modules/hekate_libsys_minerva/mtc_mc_emc_regs.h
Normal file
626
modules/hekate_libsys_minerva/mtc_mc_emc_regs.h
Normal file
@@ -0,0 +1,626 @@
|
||||
/*
|
||||
* Minerva Training Cell
|
||||
* DRAM Training for Tegra X1 SoC. Supports DDR2/3 and LPDDR3/4.
|
||||
*
|
||||
* Copyright (c) 2018 CTCaer <ctcaer@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _MTC_MC_EMC_REGS_H_
|
||||
#define _MTC_MC_EMC_REGS_H_
|
||||
|
||||
/* Clock controller registers */
|
||||
#define CLK_RST_CONTROLLER_PLLM_BASE 0x90
|
||||
#define CLK_RST_CONTROLLER_PLLM_MISC2 0x9C
|
||||
#define PLLM_ENABLE (1 << 30)
|
||||
#define PLLM_LOCK (1 << 27)
|
||||
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC 0x19C
|
||||
#define EMC_2X_CLK_SRC_SHIFT 29
|
||||
|
||||
#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X 0x280
|
||||
#define CLK_RST_CONTROLLER_CLK_ENB_X_SET 0x284
|
||||
#define CLK_RST_CONTROLLER_CLK_ENB_X_CLR 0x288
|
||||
#define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL 0x664
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC_SAFE 0x724
|
||||
|
||||
/* Memory controller registers */
|
||||
#define MC_EMEM_ADR_CFG 0x54
|
||||
#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_MISC2 0xC8
|
||||
#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_RING1_THROTTLE 0xE0
|
||||
|
||||
#define MC_LATENCY_ALLOWANCE_AVPC_0 0x2E4
|
||||
#define MC_LATENCY_ALLOWANCE_HC_0 0x310
|
||||
#define MC_LATENCY_ALLOWANCE_HC_1 0x314
|
||||
#define MC_LATENCY_ALLOWANCE_MPCORE_0 0x320
|
||||
#define MC_LATENCY_ALLOWANCE_NVENC_0 0x328
|
||||
#define MC_LATENCY_ALLOWANCE_PPCS_0 0x344
|
||||
#define MC_LATENCY_ALLOWANCE_PPCS_1 0x348
|
||||
#define MC_LATENCY_ALLOWANCE_ISP2_0 0x370
|
||||
#define MC_LATENCY_ALLOWANCE_ISP2_1 0x374
|
||||
#define MC_LATENCY_ALLOWANCE_XUSB_0 0x37C
|
||||
#define MC_LATENCY_ALLOWANCE_XUSB_1 0x380
|
||||
#define MC_LATENCY_ALLOWANCE_TSEC_0 0x390
|
||||
#define MC_LATENCY_ALLOWANCE_VIC_0 0x394
|
||||
#define MC_LATENCY_ALLOWANCE_VI2_0 0x398
|
||||
#define MC_LATENCY_ALLOWANCE_GPU_0 0x3AC
|
||||
#define MC_LATENCY_ALLOWANCE_SDMMCA_0 0x3B8
|
||||
#define MC_LATENCY_ALLOWANCE_SDMMCAA_0 0x3BC
|
||||
#define MC_LATENCY_ALLOWANCE_SDMMC_0 0x3C0
|
||||
#define MC_LATENCY_ALLOWANCE_SDMMCAB_0 0x3C4
|
||||
#define MC_LATENCY_ALLOWANCE_NVDEC_0 0x3D8
|
||||
#define MC_LATENCY_ALLOWANCE_GPU2_0 0x3E8
|
||||
|
||||
#define MC_MLL_MPCORER_PTSA_RATE 0x44C
|
||||
#define MC_FTOP_PTSA_RATE 0x50C
|
||||
|
||||
#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_PTSA_GRANT_DECREMENT 0x960
|
||||
|
||||
#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
|
||||
|
||||
/* External Memory controller registers */
|
||||
#define EMC_INTSTATUS 0x0
|
||||
#define CLKCHANGE_COMPLETE_INT (1 << 4)
|
||||
|
||||
#define EMC_DBG 0x8
|
||||
#define EMC_CFG 0xC
|
||||
#define EMC_PIN 0x24
|
||||
#define EMC_TIMING_CONTROL 0x28
|
||||
#define EMC_RC 0x2C
|
||||
#define EMC_RFC 0x30
|
||||
#define EMC_RAS 0x34
|
||||
#define EMC_RP 0x38
|
||||
#define EMC_R2W 0x3C
|
||||
#define EMC_W2R 0x40
|
||||
#define EMC_R2P 0x44
|
||||
#define EMC_W2P 0x48
|
||||
#define EMC_RD_RCD 0x4C
|
||||
#define EMC_WR_RCD 0x50
|
||||
#define EMC_RRD 0x54
|
||||
#define EMC_REXT 0x58
|
||||
#define EMC_WDV 0x5C
|
||||
#define EMC_QUSE 0x60
|
||||
#define EMC_QRST 0x64
|
||||
#define EMC_QSAFE 0x68
|
||||
#define EMC_RDV 0x6C
|
||||
#define EMC_REFRESH 0x70
|
||||
#define EMC_BURST_REFRESH_NUM 0x74
|
||||
#define EMC_PDEX2WR 0x78
|
||||
#define EMC_PDEX2RD 0x7C
|
||||
#define EMC_PCHG2PDEN 0x80
|
||||
#define EMC_ACT2PDEN 0x84
|
||||
#define EMC_AR2PDEN 0x88
|
||||
#define EMC_RW2PDEN 0x8C
|
||||
#define EMC_TXSR 0x90
|
||||
#define EMC_TCKE 0x94
|
||||
#define EMC_TFAW 0x98
|
||||
#define EMC_TRPAB 0x9C
|
||||
#define EMC_TCLKSTABLE 0xA0
|
||||
#define EMC_TCLKSTOP 0xA4
|
||||
#define EMC_TREFBW 0xA8
|
||||
#define EMC_TPPD 0xAC
|
||||
#define EMC_ODT_WRITE 0xB0
|
||||
#define EMC_PDEX2MRR 0xB4
|
||||
#define EMC_WEXT 0xB8
|
||||
#define EMC_RFC_SLR 0xC0
|
||||
#define EMC_MRS_WAIT_CNT2 0xC4
|
||||
#define EMC_MRS_WAIT_CNT 0xC8
|
||||
#define EMC_MRS 0xCC
|
||||
#define EMC_EMRS 0xD0
|
||||
#define EMC_REF 0xD4
|
||||
#define EMC_MRW 0xE8
|
||||
#define EMC_SELF_REF 0xE0
|
||||
#define EMC_MRR 0xEC
|
||||
#define EMC_FBIO_SPARE 0x100
|
||||
#define EMC_FBIO_CFG5 0x104
|
||||
#define EMC_PDEX2CKE 0x118
|
||||
#define EMC_CKE2PDEN 0x11C
|
||||
#define EMC_MPC 0x128
|
||||
#define EMC_EMRS2 0x12C
|
||||
#define EMC_MRW2 0x134
|
||||
#define EMC_MRW3 0x138
|
||||
#define EMC_MRW4 0x13C
|
||||
#define EMC_R2R 0x144
|
||||
#define EMC_EINPUT 0x14C
|
||||
#define EMC_EINPUT_DURATION 0x150
|
||||
#define EMC_PUTERM_EXTRA 0x154
|
||||
#define EMC_TCKESR 0x158
|
||||
#define EMC_TPD 0x15C
|
||||
#define EMC_AUTO_CAL_CONFIG 0x2A4
|
||||
|
||||
#define EMC_EMC_STATUS 0x2B4
|
||||
#define TIMING_UPDATE_STALLED (1 << 23)
|
||||
#define MRR_DIVLD (1 << 20)
|
||||
#define IN_SELF_REFRESH_MASK (3 << 8)
|
||||
#define IN_POWERDOWN_MASK (3 << 4)
|
||||
#define REQ_FIFO_EMPTY (1 << 0)
|
||||
|
||||
#define EMC_CFG_2 0x2B8
|
||||
#define EMC_CFG_DIG_DLL 0x2BC
|
||||
#define EMC_CFG_DIG_DLL_PERIOD 0x2C0
|
||||
#define EMC_DIG_DLL_STATUS 0x2C4
|
||||
#define EMC_RDV_MASK 0x2CC
|
||||
#define EMC_WDV_MASK 0x2D0
|
||||
#define EMC_RDV_EARLY_MASK 0x2D4
|
||||
#define EMC_RDV_EARLY 0x2D8
|
||||
#define EMC_AUTO_CAL_CONFIG8 0x2DC
|
||||
#define EMC_ZCAL_INTERVAL 0x2E0
|
||||
#define EMC_ZCAL_WAIT_CNT 0x2E4
|
||||
#define EMC_ZQ_CAL 0x2EC
|
||||
#define EMC_FDPD_CTRL_DQ 0x310
|
||||
#define EMC_FDPD_CTRL_CMD 0x314
|
||||
#define EMC_PMACRO_CMD_BRICK_CTRL_FDPD 0x318
|
||||
#define EMC_PMACRO_DATA_BRICK_CTRL_FDPD 0x31C
|
||||
#define EMC_SCRATCH0 0x324
|
||||
#define EMC_PMACRO_BRICK_CTRL_RFU1 0x330
|
||||
#define EMC_PMACRO_BRICK_CTRL_RFU2 0x334
|
||||
#define EMC_TR_TIMING_0 0x3B4
|
||||
#define EMC_TR_CTRL_0 0x3B8
|
||||
#define EMC_TR_CTRL_1 0x3BC
|
||||
#define EMC_SWITCH_BACK_CTRL 0x3C0
|
||||
#define EMC_TR_RDV 0x3C4
|
||||
#define EMC_STALL_THEN_EXE_AFTER_CLKCHANGE 0x3CC
|
||||
#define EMC_SEL_DPD_CTRL 0x3D8
|
||||
#define EMC_PRE_REFRESH_REQ_CNT 0x3DC
|
||||
#define EMC_DYN_SELF_REF_CONTROL 0x3E0
|
||||
#define EMC_TXSRDLL 0x3E4
|
||||
#define EMC_CCFIFO_ADDR 0x3E8
|
||||
#define EMC_CCFIFO_DATA 0x3EC
|
||||
#define EMC_CCFIFO_STATUS 0x3F0
|
||||
#define EMC_TR_QPOP 0x3F4
|
||||
#define EMC_TR_RDV_MASK 0x3F8
|
||||
#define EMC_TR_QSAFE 0x3FC
|
||||
#define EMC_TR_QRST 0x400
|
||||
#define EMC_AUTO_CAL_CONFIG2 0x458
|
||||
#define EMC_AUTO_CAL_CONFIG3 0x45C
|
||||
#define EMC_TR_DVFS 0x460
|
||||
#define EMC_AUTO_CAL_CHANNEL 0x464
|
||||
#define EMC_IBDLY 0x468
|
||||
#define EMC_OBDLY 0x46c
|
||||
#define EMC_TXDSRVTTGEN 0x480
|
||||
#define EMC_WE_DURATION 0x48C
|
||||
#define EMC_WS_DURATION 0x490
|
||||
#define EMC_WEV 0x494
|
||||
#define EMC_WSV 0x498
|
||||
#define EMC_CFG_3 0x49C
|
||||
#define EMC_MRW6 0x4A4
|
||||
#define EMC_MRW7 0x4A8
|
||||
#define EMC_MRW8 0x4AC
|
||||
#define EMC_MRW14 0x4C4
|
||||
#define EMC_MRW15 0x4D0
|
||||
#define EMC_CFG_SYNC 0x4D4
|
||||
#define EMC_FDPD_CTRL_CMD_NO_RAMP 0x4D8
|
||||
#define EMC_WDV_CHK 0x4E0
|
||||
#define EMC_CFG_PIPE_2 0x554
|
||||
#define EMC_CFG_PIPE_CLK 0x558
|
||||
#define EMC_CFG_PIPE_1 0x55C
|
||||
#define EMC_CFG_PIPE 0x560
|
||||
#define EMC_QPOP 0x564
|
||||
#define EMC_QUSE_WIDTH 0x568
|
||||
#define EMC_PUTERM_WIDTH 0x56C
|
||||
#define EMC_AUTO_CAL_CONFIG7 0x574
|
||||
#define EMC_REFCTRL2 0x580
|
||||
#define EMC_FBIO_CFG7 0x584
|
||||
|
||||
#define EMC_DATA_BRLSHFT_0 0x588
|
||||
#define EMC_DATA_BRLSHFT_0_RANK0_BYTE0_DATA_BRLSHFT_SHIFT 0
|
||||
#define EMC_DATA_BRLSHFT_0_RANK0_BYTE1_DATA_BRLSHFT_SHIFT 3
|
||||
#define EMC_DATA_BRLSHFT_0_RANK0_BYTE2_DATA_BRLSHFT_SHIFT 6
|
||||
#define EMC_DATA_BRLSHFT_0_RANK0_BYTE3_DATA_BRLSHFT_SHIFT 9
|
||||
#define EMC_DATA_BRLSHFT_0_RANK0_BYTE4_DATA_BRLSHFT_SHIFT 12
|
||||
#define EMC_DATA_BRLSHFT_0_RANK0_BYTE5_DATA_BRLSHFT_SHIFT 15
|
||||
#define EMC_DATA_BRLSHFT_0_RANK0_BYTE6_DATA_BRLSHFT_SHIFT 18
|
||||
#define EMC_DATA_BRLSHFT_0_RANK0_BYTE7_DATA_BRLSHFT_SHIFT 21
|
||||
|
||||
#define EMC_DATA_BRLSHFT_1 0x58C
|
||||
#define EMC_DATA_BRLSHFT_1_RANK1_BYTE0_DATA_BRLSHFT_SHIFT 0
|
||||
#define EMC_DATA_BRLSHFT_1_RANK1_BYTE1_DATA_BRLSHFT_SHIFT 3
|
||||
#define EMC_DATA_BRLSHFT_1_RANK1_BYTE2_DATA_BRLSHFT_SHIFT 6
|
||||
#define EMC_DATA_BRLSHFT_1_RANK1_BYTE3_DATA_BRLSHFT_SHIFT 9
|
||||
#define EMC_DATA_BRLSHFT_1_RANK1_BYTE4_DATA_BRLSHFT_SHIFT 12
|
||||
#define EMC_DATA_BRLSHFT_1_RANK1_BYTE5_DATA_BRLSHFT_SHIFT 15
|
||||
#define EMC_DATA_BRLSHFT_1_RANK1_BYTE6_DATA_BRLSHFT_SHIFT 18
|
||||
#define EMC_DATA_BRLSHFT_1_RANK1_BYTE7_DATA_BRLSHFT_SHIFT 21
|
||||
|
||||
#define EMC_RFCPB 0x590
|
||||
#define EMC_DQS_BRLSHFT_0 0x594
|
||||
#define EMC_DQS_BRLSHFT_1 0x598
|
||||
#define EMC_CMD_BRLSHFT_0 0x59C
|
||||
#define EMC_CMD_BRLSHFT_1 0x5A0
|
||||
#define EMC_CMD_BRLSHFT_2 0x5A4
|
||||
#define EMC_CMD_BRLSHFT_3 0x5A8
|
||||
#define EMC_QUSE_BRLSHFT_0 0x5AC
|
||||
#define EMC_AUTO_CAL_CONFIG4 0x5B0
|
||||
#define EMC_AUTO_CAL_CONFIG5 0x5B4
|
||||
#define EMC_QUSE_BRLSHFT_1 0x5B8
|
||||
#define EMC_QUSE_BRLSHFT_2 0x5BC
|
||||
#define EMC_CCDMW 0x5C0
|
||||
#define EMC_QUSE_BRLSHFT_3 0x5C4
|
||||
#define EMC_AUTO_CAL_CONFIG6 0x5CC
|
||||
#define EMC_DLL_CFG_0 0x5E4
|
||||
#define EMC_DLL_CFG_1 0x5E8
|
||||
#define EMC_CONFIG_SAMPLE_DELAY 0x5F0
|
||||
#define EMC_CFG_UPDATE 0x5F4
|
||||
|
||||
#define EMC_PMACRO_QUSE_DDLL_RANK0_0 0x600
|
||||
#define EMC_PMACRO_QUSE_DDLL_RANK0_1 0x604
|
||||
#define EMC_PMACRO_QUSE_DDLL_RANK0_2 0x608
|
||||
#define EMC_PMACRO_QUSE_DDLL_RANK0_3 0x60C
|
||||
#define EMC_PMACRO_QUSE_DDLL_RANK0_4 0x610
|
||||
#define EMC_PMACRO_QUSE_DDLL_RANK0_5 0x614
|
||||
#define EMC_PMACRO_QUSE_DDLL_RANK1_4 0x630
|
||||
#define EMC_PMACRO_QUSE_DDLL_RANK1_5 0x634
|
||||
#define EMC_PMACRO_QUSE_DDLL_RANK1_0 0x620
|
||||
#define EMC_PMACRO_QUSE_DDLL_RANK1_1 0x624
|
||||
#define EMC_PMACRO_QUSE_DDLL_RANK1_2 0x628
|
||||
#define EMC_PMACRO_QUSE_DDLL_RANK1_3 0x62C
|
||||
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0 0x640
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1 0x644
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2 0x648
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3 0x64C
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_4 0x650
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_5 0x654
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0 0x660
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1 0x664
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2 0x668
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3 0x66C
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4 0x670
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5 0x674
|
||||
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0 0x680
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1 0x684
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2 0x688
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_3 0x68C
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_4 0x690
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_5 0x694
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_0 0x6A0
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_1 0x6A4
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_2 0x6A8
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_3 0x6AC
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_4 0x6B0
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_5 0x6B4
|
||||
|
||||
#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_0 0x6C0
|
||||
#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_1 0x6C4
|
||||
#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_2 0x6C8
|
||||
#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_3 0x6CC
|
||||
#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_0 0x6E0
|
||||
#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1 0x6E4
|
||||
#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2 0x6E8
|
||||
#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3 0x6EC
|
||||
|
||||
#define EMC_PMACRO_TX_PWRD_0 0x720
|
||||
#define EMC_PMACRO_TX_PWRD_1 0x724
|
||||
#define EMC_PMACRO_TX_PWRD_2 0x728
|
||||
#define EMC_PMACRO_TX_PWRD_3 0x72C
|
||||
#define EMC_PMACRO_TX_PWRD_4 0x730
|
||||
#define EMC_PMACRO_TX_PWRD_5 0x734
|
||||
|
||||
#define EMC_PMACRO_TX_SEL_CLK_SRC_0 0x740
|
||||
#define EMC_PMACRO_TX_SEL_CLK_SRC_1 0x744
|
||||
#define EMC_PMACRO_TX_SEL_CLK_SRC_3 0x74C
|
||||
#define EMC_PMACRO_TX_SEL_CLK_SRC_2 0x748
|
||||
#define EMC_PMACRO_TX_SEL_CLK_SRC_4 0x750
|
||||
#define EMC_PMACRO_TX_SEL_CLK_SRC_5 0x754
|
||||
|
||||
#define EMC_PMACRO_DDLL_BYPASS 0x760
|
||||
#define EMC_PMACRO_DDLL_PWRD_0 0x770
|
||||
#define EMC_PMACRO_DDLL_PWRD_1 0x774
|
||||
#define EMC_PMACRO_DDLL_PWRD_2 0x778
|
||||
|
||||
#define EMC_PMACRO_CMD_CTRL_0 0x780
|
||||
#define EMC_PMACRO_CMD_CTRL_1 0x784
|
||||
#define EMC_PMACRO_CMD_CTRL_2 0x788
|
||||
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_0 0x800
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_1 0x804
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_2 0x808
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_3 0x80C
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_0 0x810
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_1 0x814
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_2 0x818
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_3 0x81C
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_0 0x820
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_1 0x824
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_2 0x828
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_3 0x82C
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_0 0x830
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_1 0x834
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_2 0x838
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_3 0x83C
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_0 0x840
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_1 0x844
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_2 0x848
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_3 0x84C
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_0 0x850
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_1 0x854
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_2 0x858
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_3 0x85C
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_0 0x860
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_1 0x864
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_2 0x868
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_3 0x86C
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_0 0x870
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_1 0x874
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_2 0x878
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_3 0x87C
|
||||
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_0 0x880
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_1 0x884
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_2 0x888
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_3 0x88C
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_0 0x890
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_1 0x894
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_2 0x898
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_3 0x89C
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_0 0x8A0
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_1 0x8A4
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_2 0x8A8
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_3 0x8AC
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_0 0x8B0
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_1 0x8B4
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_2 0x8B8
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_3 0x8BC
|
||||
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_0 0x900
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_1 0x904
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_2 0x908
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_3 0x90C
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_0 0x910
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_1 0x914
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_2 0x918
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_3 0x91C
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_0 0x920
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_1 0x924
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_2 0x928
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_3 0x92C
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_0 0x930
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_1 0x934
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_2 0x938
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_3 0x93C
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_0 0x940
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_1 0x944
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_2 0x948
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_3 0x94C
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_0 0x950
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_1 0x954
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_2 0x958
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_3 0x95C
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_0 0x960
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_1 0x964
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_2 0x968
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_3 0x96C
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_0 0x970
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_1 0x974
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_2 0x978
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_3 0x97C
|
||||
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_0 0x980
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_1 0x984
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_2 0x988
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_3 0x98C
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_0 0x990
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_1 0x994
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_2 0x998
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_3 0x99C
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_0 0x9A0
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_1 0x9A4
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_2 0x9A8
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_3 0x9AC
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_0 0x9B0
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_1 0x9B4
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_2 0x9B8
|
||||
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_3 0x9BC
|
||||
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_0 0xA00
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_1 0xA04
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_2 0xA08
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_0 0xA10
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_1 0xA14
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_2 0xA18
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_0 0xA20
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_1 0xA24
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_2 0xA28
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_0 0xA30
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_1 0xA34
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_2 0xA38
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_0 0xA40
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_1 0xA44
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_2 0xA48
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_0 0xA50
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_1 0xA54
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_2 0xA58
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_0 0xA60
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_1 0xA64
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_2 0xA68
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_0 0xA70
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_1 0xA74
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_2 0xA78
|
||||
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_0 0xB00
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_1 0xB04
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_2 0xB08
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_0 0xB10
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_1 0xB14
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_2 0xB18
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_0 0xB20
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_1 0xB24
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_2 0xB28
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_0 0xB30
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_1 0xB34
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_2 0xB38
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_0 0xB40
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_1 0xB44
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_2 0xB48
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_0 0xB50
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_1 0xB54
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_2 0xB58
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_0 0xB60
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_1 0xB64
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_2 0xB68
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_0 0xB70
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_1 0xB74
|
||||
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_2 0xB78
|
||||
|
||||
#define EMC_PMACRO_IB_VREF_DQ_0 0xBE0
|
||||
#define EMC_PMACRO_IB_VREF_DQ_1 0xBE4
|
||||
#define EMC_PMACRO_IB_VREF_DQS_0 0xBF0
|
||||
#define EMC_PMACRO_IB_VREF_DQS_1 0xBF4
|
||||
|
||||
#define EMC_PMACRO_DDLL_LONG_CMD_0 0xC00
|
||||
#define EMC_PMACRO_DDLL_LONG_CMD_1 0xC04
|
||||
#define EMC_PMACRO_DDLL_LONG_CMD_2 0xC08
|
||||
#define EMC_PMACRO_DDLL_LONG_CMD_3 0xC0C
|
||||
#define EMC_PMACRO_DDLL_LONG_CMD_4 0xC10
|
||||
|
||||
#define EMC_PMACRO_DDLL_SHORT_CMD_0 0xC20
|
||||
#define EMC_PMACRO_DDLL_SHORT_CMD_1 0xC24
|
||||
#define EMC_PMACRO_DDLL_SHORT_CMD_2 0xC28
|
||||
|
||||
#define EMC_PMACRO_CFG_PM_GLOBAL_0 0xC30
|
||||
#define EMC_PMACRO_VTTGEN_CTRL_0 0xC34
|
||||
#define EMC_PMACRO_VTTGEN_CTRL_1 0xC38
|
||||
#define EMC_PMACRO_BG_BIAS_CTRL_0 0xC3C
|
||||
#define EMC_PMACRO_PAD_CFG_CTRL 0xC40
|
||||
#define EMC_PMACRO_ZCTRL 0xC44
|
||||
#define EMC_PMACRO_CMD_PAD_RX_CTRL 0xC50
|
||||
#define EMC_PMACRO_DATA_PAD_RX_CTRL 0xC54
|
||||
#define EMC_PMACRO_CMD_RX_TERM_MODE 0xC58
|
||||
#define EMC_PMACRO_DATA_RX_TERM_MODE 0xC5C
|
||||
#define EMC_PMACRO_CMD_PAD_TX_CTRL 0xC60
|
||||
#define EMC_PMACRO_DATA_PAD_TX_CTRL 0xC64
|
||||
#define EMC_PMACRO_COMMON_PAD_TX_CTRL 0xC68
|
||||
#define EMC_PMACRO_AUTOCAL_CFG_COMMON 0xC78
|
||||
#define EMC_PMACRO_VTTGEN_CTRL_2 0xCF0
|
||||
#define EMC_PMACRO_IB_RXRT 0xCF4
|
||||
#define EMC_PMACRO_TRAINING_CTRL_0 0xCF8
|
||||
#define CH0_TRAINING_E_WRPTR (1 << 3)
|
||||
#define EMC_PMACRO_TRAINING_CTRL_1 0xCFC
|
||||
|
||||
#define EMC_TRAINING_CMD 0xE00
|
||||
#define EMC_TRAINING_CTRL 0xE04
|
||||
#define EMC_TRAINING_STATUS 0xE08
|
||||
#define EMC_TRAINING_QUSE_CORS_CTRL 0xE0C
|
||||
#define EMC_TRAINING_QUSE_FINE_CTRL 0xE10
|
||||
#define EMC_TRAINING_QUSE_CTRL_MISC 0xE14
|
||||
#define EMC_TRAINING_WRITE_FINE_CTRL 0xE18
|
||||
#define EMC_TRAINING_WRITE_CTRL_MISC 0xE1C
|
||||
#define EMC_TRAINING_WRITE_VREF_CTRL 0xE20
|
||||
#define EMC_TRAINING_READ_FINE_CTRL 0xE24
|
||||
#define EMC_TRAINING_READ_CTRL_MISC 0xE28
|
||||
#define EMC_TRAINING_READ_VREF_CTRL 0xE2C
|
||||
#define EMC_TRAINING_CA_FINE_CTRL 0xE30
|
||||
#define EMC_TRAINING_CA_CTRL_MISC 0xE34
|
||||
#define EMC_TRAINING_CA_CTRL_MISC1 0xE38
|
||||
#define EMC_TRAINING_CA_VREF_CTRL 0xE3C
|
||||
#define EMC_TRAINING_SETTLE 0xE44
|
||||
#define EMC_TRAINING_MPC 0xE5C
|
||||
#define EMC_TRAINING_PATRAM_CTRL 0xE60
|
||||
#define EMC_TRAINING_PATRAM_DQ 0xE64
|
||||
#define EMC_TRAINING_PATRAM_DMI 0xE68
|
||||
#define EMC_TRAINING_VREF_SETTLE 0xE6C
|
||||
#define EMC_TRAINING_OPT_CA_VREF 0xEC0
|
||||
#define EMC_TRAINING_OPT_DQ_OB_VREF 0xEC4
|
||||
#define EMC_TRAINING_QUSE_VREF_CTRL 0xED0
|
||||
#define EMC_TRAINING_OPT_DQS_IB_VREF_RANK0 0xED4
|
||||
#define EMC_TRAINING_OPT_DQS_IB_VREF_RANK1 0xED8
|
||||
|
||||
/* Per channel registers offsets. Should be used with EMC_BASE */
|
||||
#define EMC0_MRW10 0x34B4
|
||||
#define EMC0_MRW11 0x34B8
|
||||
#define EMC0_MRW12 0x34BC
|
||||
#define EMC0_MRW13 0x34C0
|
||||
#define EMC0_DATA_BRLSHFT_0 0x3588
|
||||
#define EMC0_DATA_BRLSHFT_1 0x358C
|
||||
#define EMC0_CMD_BRLSHFT_0 0x359C
|
||||
#define EMC0_QUSE_BRLSHFT_0 0x35AC
|
||||
#define EMC0_QUSE_BRLSHFT_2 0x35BC
|
||||
#define EMC0_TRAINING_RW_OFFSET_IB_BYTE0 0x3E98
|
||||
#define EMC0_TRAINING_RW_OFFSET_IB_BYTE1 0x3E9C
|
||||
#define EMC0_TRAINING_RW_OFFSET_IB_BYTE2 0x3EA0
|
||||
#define EMC0_TRAINING_RW_OFFSET_IB_BYTE3 0x3EA4
|
||||
#define EMC0_TRAINING_RW_OFFSET_IB_MISC 0x3EA8
|
||||
#define EMC0_TRAINING_RW_OFFSET_OB_BYTE0 0x3EAC
|
||||
#define EMC0_TRAINING_RW_OFFSET_OB_BYTE1 0x3EB0
|
||||
#define EMC0_TRAINING_RW_OFFSET_OB_BYTE2 0x3EB4
|
||||
#define EMC0_TRAINING_RW_OFFSET_OB_BYTE3 0x3EB8
|
||||
#define EMC0_TRAINING_RW_OFFSET_OB_MISC 0x3EBC
|
||||
#define EMC0_TRAINING_OPT_DQS_IB_VREF_RANK0 0x3ED4
|
||||
#define EMC0_TRAINING_OPT_DQS_IB_VREF_RANK1 0x3ED8
|
||||
|
||||
#define EMC1_MRW10 0x44B4
|
||||
#define EMC1_MRW11 0x44B8
|
||||
#define EMC1_MRW12 0x44BC
|
||||
#define EMC1_MRW13 0x44C0
|
||||
#define EMC1_DATA_BRLSHFT_0 0x4588
|
||||
#define EMC1_DATA_BRLSHFT_1 0x458C
|
||||
#define EMC1_CMD_BRLSHFT_1 0x45A0
|
||||
#define EMC1_QUSE_BRLSHFT_1 0x45B8
|
||||
#define EMC1_QUSE_BRLSHFT_3 0x45C4
|
||||
#define EMC1_TRAINING_RW_OFFSET_IB_BYTE0 0x4E98
|
||||
#define EMC1_TRAINING_RW_OFFSET_IB_BYTE1 0x4E9C
|
||||
#define EMC1_TRAINING_RW_OFFSET_IB_BYTE2 0x4EA0
|
||||
#define EMC1_TRAINING_RW_OFFSET_IB_BYTE3 0x4EA4
|
||||
#define EMC1_TRAINING_RW_OFFSET_IB_MISC 0x4EA8
|
||||
#define EMC1_TRAINING_RW_OFFSET_OB_BYTE0 0x4EAC
|
||||
#define EMC1_TRAINING_RW_OFFSET_OB_BYTE1 0x4EB0
|
||||
#define EMC1_TRAINING_RW_OFFSET_OB_BYTE2 0x4EB4
|
||||
#define EMC1_TRAINING_RW_OFFSET_OB_BYTE3 0x4EB8
|
||||
#define EMC1_TRAINING_RW_OFFSET_OB_MISC 0x4EBC
|
||||
#define EMC1_TRAINING_OPT_DQS_IB_VREF_RANK0 0x4ED4
|
||||
#define EMC1_TRAINING_OPT_DQS_IB_VREF_RANK1 0x4ED8
|
||||
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE0_SHIFT 0
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE1_SHIFT 16
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE2_SHIFT 0
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE3_SHIFT 16
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE4_SHIFT 0
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE5_SHIFT 16
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE6_SHIFT 0
|
||||
#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE7_SHIFT 16
|
||||
|
||||
#endif
|
||||
6193
modules/hekate_libsys_minerva/mtc_switch_tables.h
Normal file
6193
modules/hekate_libsys_minerva/mtc_switch_tables.h
Normal file
File diff suppressed because it is too large
Load Diff
560
modules/hekate_libsys_minerva/mtc_table.h
Normal file
560
modules/hekate_libsys_minerva/mtc_table.h
Normal file
@@ -0,0 +1,560 @@
|
||||
/*
|
||||
* Minerva Training Cell
|
||||
* DRAM Training for Tegra X1 SoC. Supports DDR2/3 and LPDDR3/4.
|
||||
*
|
||||
* Copyright (c) 2018 CTCaer <ctcaer@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _MTC_TABLE_H_
|
||||
#define _MTC_TABLE_H_
|
||||
|
||||
#include "types.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
s32 pll_osc_in;
|
||||
s32 pll_out;
|
||||
u32 pll_feedback_div;
|
||||
u32 pll_input_div;
|
||||
u32 pll_post_div;
|
||||
} pllm_clk_config_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 emc_rc_idx;
|
||||
u32 emc_rfc_idx;
|
||||
u32 emc_rfcpb_idx;
|
||||
u32 emc_refctrl2_idx;
|
||||
u32 emc_rfc_slr_idx;
|
||||
u32 emc_ras_idx;
|
||||
u32 emc_rp_idx;
|
||||
u32 emc_r2w_idx;
|
||||
u32 emc_w2r_idx;
|
||||
u32 emc_r2p_idx;
|
||||
u32 emc_w2p_idx;
|
||||
u32 emc_r2r_idx;
|
||||
u32 emc_tppd_idx;
|
||||
u32 emc_ccdmw_idx;
|
||||
u32 emc_rd_rcd_idx;
|
||||
u32 emc_wr_rcd_idx;
|
||||
u32 emc_rrd_idx;
|
||||
u32 emc_rext_idx;
|
||||
u32 emc_wext_idx;
|
||||
u32 emc_wdv_chk_idx;
|
||||
u32 emc_wdv_idx;
|
||||
u32 emc_wsv_idx;
|
||||
u32 emc_wev_idx;
|
||||
u32 emc_wdv_mask_idx;
|
||||
u32 emc_ws_duration_idx;
|
||||
u32 emc_we_duration_idx;
|
||||
u32 emc_quse_idx;
|
||||
u32 emc_quse_width_idx;
|
||||
u32 emc_ibdly_idx;
|
||||
u32 emc_obdly_idx;
|
||||
u32 emc_einput_idx;
|
||||
u32 emc_mrw6_idx;
|
||||
u32 emc_einput_duration_idx;
|
||||
u32 emc_puterm_extra_idx;
|
||||
u32 emc_puterm_width_idx;
|
||||
u32 emc_qrst_idx;
|
||||
u32 emc_qsafe_idx;
|
||||
u32 emc_rdv_idx;
|
||||
u32 emc_rdv_mask_idx;
|
||||
u32 emc_rdv_early_idx;
|
||||
u32 emc_rdv_early_mask_idx;
|
||||
u32 emc_refresh_idx;
|
||||
u32 emc_burst_refresh_num_idx;
|
||||
u32 emc_pre_refresh_req_cnt_idx;
|
||||
u32 emc_pdex2wr_idx;
|
||||
u32 emc_pdex2rd_idx;
|
||||
u32 emc_pchg2pden_idx;
|
||||
u32 emc_act2pden_idx;
|
||||
u32 emc_ar2pden_idx;
|
||||
u32 emc_rw2pden_idx;
|
||||
u32 emc_cke2pden_idx;
|
||||
u32 emc_pdex2cke_idx;
|
||||
u32 emc_pdex2mrr_idx;
|
||||
u32 emc_txsr_idx;
|
||||
u32 emc_txsrdll_idx;
|
||||
u32 emc_tcke_idx;
|
||||
u32 emc_tckesr_idx;
|
||||
u32 emc_tpd_idx;
|
||||
u32 emc_tfaw_idx;
|
||||
u32 emc_trpab_idx;
|
||||
u32 emc_tclkstable_idx;
|
||||
u32 emc_tclkstop_idx;
|
||||
u32 emc_mrw7_idx;
|
||||
u32 emc_trefbw_idx;
|
||||
u32 emc_odt_write_idx;
|
||||
u32 emc_fbio_cfg5_idx;
|
||||
u32 emc_fbio_cfg7_idx;
|
||||
u32 emc_cfg_dig_dll_idx;
|
||||
u32 emc_cfg_dig_dll_period_idx;
|
||||
u32 emc_pmacro_ib_rxrt_idx;
|
||||
u32 emc_cfg_pipe_1_idx;
|
||||
u32 emc_cfg_pipe_2_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank0_4_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank0_5_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank1_4_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank1_5_idx;
|
||||
u32 emc_mrw8_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank1_4_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank1_5_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank0_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank0_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank0_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank0_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank0_4_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank0_5_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank1_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank1_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank1_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank1_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank1_4_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dqs_rank1_5_idx;
|
||||
u32 emc_pmacro_ddll_long_cmd_0_idx;
|
||||
u32 emc_pmacro_ddll_long_cmd_1_idx;
|
||||
u32 emc_pmacro_ddll_long_cmd_2_idx;
|
||||
u32 emc_pmacro_ddll_long_cmd_3_idx;
|
||||
u32 emc_pmacro_ddll_long_cmd_4_idx;
|
||||
u32 emc_pmacro_ddll_short_cmd_0_idx;
|
||||
u32 emc_pmacro_ddll_short_cmd_1_idx;
|
||||
u32 emc_pmacro_ddll_short_cmd_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_3_idx;
|
||||
u32 emc_txdsrvttgen_idx;
|
||||
u32 emc_fdpd_ctrl_dq_idx;
|
||||
u32 emc_fdpd_ctrl_cmd_idx;
|
||||
u32 emc_fbio_spare_idx;
|
||||
u32 emc_zcal_interval_idx;
|
||||
u32 emc_zcal_wait_cnt_idx;
|
||||
u32 emc_mrs_wait_cnt_idx;
|
||||
u32 emc_mrs_wait_cnt2_idx;
|
||||
u32 emc_auto_cal_channel_idx;
|
||||
u32 emc_dll_cfg_0_idx;
|
||||
u32 emc_dll_cfg_1_idx;
|
||||
u32 emc_pmacro_autocal_cfg_common_idx;
|
||||
u32 emc_pmacro_zctrl_idx;
|
||||
u32 emc_cfg_idx;
|
||||
u32 emc_cfg_pipe_idx;
|
||||
u32 emc_dyn_self_ref_control_idx;
|
||||
u32 emc_qpop_idx;
|
||||
u32 emc_dqs_brlshft_0_idx;
|
||||
u32 emc_dqs_brlshft_1_idx;
|
||||
u32 emc_cmd_brlshft_2_idx;
|
||||
u32 emc_cmd_brlshft_3_idx;
|
||||
u32 emc_pmacro_pad_cfg_ctrl_idx;
|
||||
u32 emc_pmacro_data_pad_rx_ctrl_idx;
|
||||
u32 emc_pmacro_cmd_pad_rx_ctrl_idx;
|
||||
u32 emc_pmacro_data_rx_term_mode_idx;
|
||||
u32 emc_pmacro_cmd_rx_term_mode_idx;
|
||||
u32 emc_pmacro_cmd_pad_tx_ctrl_idx;
|
||||
u32 emc_pmacro_data_pad_tx_ctrl_idx;
|
||||
u32 emc_pmacro_common_pad_tx_ctrl_idx;
|
||||
u32 emc_pmacro_vttgen_ctrl_0_idx;
|
||||
u32 emc_pmacro_vttgen_ctrl_1_idx;
|
||||
u32 emc_pmacro_vttgen_ctrl_2_idx;
|
||||
u32 emc_pmacro_brick_ctrl_rfu1_idx;
|
||||
u32 emc_pmacro_cmd_brick_ctrl_fdpd_idx;
|
||||
u32 emc_pmacro_brick_ctrl_rfu2_idx;
|
||||
u32 emc_pmacro_data_brick_ctrl_fdpd_idx;
|
||||
u32 emc_pmacro_bg_bias_ctrl_0_idx;
|
||||
u32 emc_cfg_3_idx;
|
||||
u32 emc_pmacro_tx_pwrd_0_idx;
|
||||
u32 emc_pmacro_tx_pwrd_1_idx;
|
||||
u32 emc_pmacro_tx_pwrd_2_idx;
|
||||
u32 emc_pmacro_tx_pwrd_3_idx;
|
||||
u32 emc_pmacro_tx_pwrd_4_idx;
|
||||
u32 emc_pmacro_tx_pwrd_5_idx;
|
||||
u32 emc_config_sample_delay_idx;
|
||||
u32 emc_pmacro_tx_sel_clk_src_0_idx;
|
||||
u32 emc_pmacro_tx_sel_clk_src_1_idx;
|
||||
u32 emc_pmacro_tx_sel_clk_src_2_idx;
|
||||
u32 emc_pmacro_tx_sel_clk_src_3_idx;
|
||||
u32 emc_pmacro_tx_sel_clk_src_4_idx;
|
||||
u32 emc_pmacro_tx_sel_clk_src_5_idx;
|
||||
u32 emc_pmacro_ddll_bypass_idx;
|
||||
u32 emc_pmacro_ddll_pwrd_0_idx;
|
||||
u32 emc_pmacro_ddll_pwrd_1_idx;
|
||||
u32 emc_pmacro_ddll_pwrd_2_idx;
|
||||
u32 emc_pmacro_cmd_ctrl_0_idx;
|
||||
u32 emc_pmacro_cmd_ctrl_1_idx;
|
||||
u32 emc_pmacro_cmd_ctrl_2_idx;
|
||||
u32 emc_tr_timing_0_idx;
|
||||
u32 emc_tr_dvfs_idx;
|
||||
u32 emc_tr_ctrl_1_idx;
|
||||
u32 emc_tr_rdv_idx;
|
||||
u32 emc_tr_qpop_idx;
|
||||
u32 emc_tr_rdv_mask_idx;
|
||||
u32 emc_mrw14_idx;
|
||||
u32 emc_tr_qsafe_idx;
|
||||
u32 emc_tr_qrst_idx;
|
||||
u32 emc_training_ctrl_idx;
|
||||
u32 emc_training_settle_idx;
|
||||
u32 emc_training_vref_settle_idx;
|
||||
u32 emc_training_ca_fine_ctrl_idx;
|
||||
u32 emc_training_ca_ctrl_misc_idx;
|
||||
u32 emc_training_ca_ctrl_misc1_idx;
|
||||
u32 emc_training_ca_vref_ctrl_idx;
|
||||
u32 emc_training_quse_cors_ctrl_idx;
|
||||
u32 emc_training_quse_fine_ctrl_idx;
|
||||
u32 emc_training_quse_ctrl_misc_idx;
|
||||
u32 emc_training_quse_vref_ctrl_idx;
|
||||
u32 emc_training_read_fine_ctrl_idx;
|
||||
u32 emc_training_read_ctrl_misc_idx;
|
||||
u32 emc_training_read_vref_ctrl_idx;
|
||||
u32 emc_training_write_fine_ctrl_idx;
|
||||
u32 emc_training_write_ctrl_misc_idx;
|
||||
u32 emc_training_write_vref_ctrl_idx;
|
||||
u32 emc_training_mpc_idx;
|
||||
u32 emc_mrw15_idx;
|
||||
} burst_regs_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 burst_regs[221];
|
||||
u32 burst_reg_per_ch[8];
|
||||
u32 shadow_regs_ca_train[221];
|
||||
u32 shadow_regs_quse_train[221];
|
||||
u32 shadow_regs_rdwr_train[221];
|
||||
} burst_regs_table_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 ptfv_dqsosc_movavg_c0d0u0_idx;
|
||||
u32 ptfv_dqsosc_movavg_c0d0u1_idx;
|
||||
u32 ptfv_dqsosc_movavg_c0d1u0_idx;
|
||||
u32 ptfv_dqsosc_movavg_c0d1u1_idx;
|
||||
u32 ptfv_dqsosc_movavg_c1d0u0_idx;
|
||||
u32 ptfv_dqsosc_movavg_c1d0u1_idx;
|
||||
u32 ptfv_dqsosc_movavg_c1d1u0_idx;
|
||||
u32 ptfv_dqsosc_movavg_c1d1u1_idx;
|
||||
u32 ptfv_write_samples_idx;
|
||||
u32 ptfv_dvfs_samples_idx;
|
||||
u32 ptfv_movavg_weight_idx;
|
||||
u32 ptfv_config_ctrl_idx;
|
||||
} ptfv_list_table_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 emc0_mrw10_idx;
|
||||
u32 emc1_mrw10_idx;
|
||||
u32 emc0_mrw11_idx;
|
||||
u32 emc1_mrw11_idx;
|
||||
u32 emc0_mrw12_idx;
|
||||
u32 emc1_mrw12_idx;
|
||||
u32 emc0_mrw13_idx;
|
||||
u32 emc1_mrw13_idx;
|
||||
} burst_reg_per_ch_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 emc_pmacro_ib_ddll_long_dqs_rank0_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_long_dqs_rank0_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_long_dqs_rank0_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_long_dqs_rank0_3_idx;
|
||||
u32 emc_pmacro_ib_ddll_long_dqs_rank1_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_long_dqs_rank1_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_long_dqs_rank1_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_long_dqs_rank1_3_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_2_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_0_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_1_idx;
|
||||
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_2_idx;
|
||||
u32 emc_pmacro_ib_vref_dqs_0_idx;
|
||||
u32 emc_pmacro_ib_vref_dqs_1_idx;
|
||||
u32 emc_pmacro_ib_vref_dq_0_idx;
|
||||
u32 emc_pmacro_ib_vref_dq_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank0_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank0_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank0_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank0_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank0_4_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank0_5_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank1_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank1_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank1_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_long_dq_rank1_3_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_2_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_0_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_1_idx;
|
||||
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_2_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank0_0_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank0_1_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank0_2_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank0_3_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank1_0_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank1_1_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank1_2_idx;
|
||||
u32 emc_pmacro_quse_ddll_rank1_3_idx;
|
||||
} trim_regs_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 emc_cmd_brlshft_0_idx;
|
||||
u32 emc_cmd_brlshft_1_idx;
|
||||
u32 emc0_data_brlshft_0_idx;
|
||||
u32 emc1_data_brlshft_0_idx;
|
||||
u32 emc0_data_brlshft_1_idx;
|
||||
u32 emc1_data_brlshft_1_idx;
|
||||
u32 emc_quse_brlshft_0_idx;
|
||||
u32 emc_quse_brlshft_1_idx;
|
||||
u32 emc_quse_brlshft_2_idx;
|
||||
u32 emc_quse_brlshft_3_idx;
|
||||
} trim_perch_regs_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 t_rp;
|
||||
u32 t_fc_lpddr4;
|
||||
u32 t_rfc;
|
||||
u32 t_pdex;
|
||||
u32 rl;
|
||||
} dram_timings_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 emc0_training_opt_dqs_ib_vref_rank0_idx;
|
||||
u32 emc1_training_opt_dqs_ib_vref_rank0_idx;
|
||||
u32 emc0_training_opt_dqs_ib_vref_rank1_idx;
|
||||
u32 emc1_training_opt_dqs_ib_vref_rank1_idx;
|
||||
} vref_perch_regs_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 trim_regs[138];
|
||||
u32 trim_perch_regs[10];
|
||||
u32 vref_perch_regs[4];
|
||||
} trim_regs_table_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 rev;
|
||||
char dvfs_ver[60];
|
||||
u32 rate_khz;
|
||||
u32 min_volt;
|
||||
u32 gpu_min_volt;
|
||||
char clock_src[32];
|
||||
u32 clk_src_emc;
|
||||
u32 needs_training;
|
||||
u32 training_pattern;
|
||||
u32 trained;
|
||||
u32 periodic_training;
|
||||
u32 trained_dram_clktree_c0d0u0;
|
||||
u32 trained_dram_clktree_c0d0u1;
|
||||
u32 trained_dram_clktree_c0d1u0;
|
||||
u32 trained_dram_clktree_c0d1u1;
|
||||
u32 trained_dram_clktree_c1d0u0;
|
||||
u32 trained_dram_clktree_c1d0u1;
|
||||
u32 trained_dram_clktree_c1d1u0;
|
||||
u32 trained_dram_clktree_c1d1u1;
|
||||
u32 current_dram_clktree_c0d0u0;
|
||||
u32 current_dram_clktree_c0d0u1;
|
||||
u32 current_dram_clktree_c0d1u0;
|
||||
u32 current_dram_clktree_c0d1u1;
|
||||
u32 current_dram_clktree_c1d0u0;
|
||||
u32 current_dram_clktree_c1d0u1;
|
||||
u32 current_dram_clktree_c1d1u0;
|
||||
u32 current_dram_clktree_c1d1u1;
|
||||
u32 run_clocks;
|
||||
u32 tree_margin;
|
||||
u32 num_burst;
|
||||
u32 num_burst_per_ch;
|
||||
u32 num_trim;
|
||||
u32 num_trim_per_ch;
|
||||
u32 num_mc_regs;
|
||||
u32 num_up_down;
|
||||
u32 vref_num;
|
||||
u32 training_mod_num;
|
||||
u32 dram_timing_num;
|
||||
|
||||
ptfv_list_table_t ptfv_list;
|
||||
|
||||
burst_regs_t burst_regs;
|
||||
burst_reg_per_ch_t burst_reg_per_ch;
|
||||
burst_regs_t shadow_regs_ca_train;
|
||||
burst_regs_t shadow_regs_quse_train;
|
||||
burst_regs_t shadow_regs_rdwr_train;
|
||||
trim_regs_t trim_regs;
|
||||
trim_perch_regs_t trim_perch_regs;
|
||||
vref_perch_regs_t vref_perch_regs;
|
||||
dram_timings_t dram_timings;
|
||||
|
||||
u32 training_mod_regs[20];
|
||||
u32 save_restore_mod_regs[12];
|
||||
u32 burst_mc_regs[33];
|
||||
u32 la_scale_regs[24];
|
||||
|
||||
u32 min_mrs_wait;
|
||||
u32 emc_mrw;
|
||||
u32 emc_mrw2;
|
||||
u32 emc_mrw3;
|
||||
u32 emc_mrw4;
|
||||
u32 emc_mrw9;
|
||||
u32 emc_mrs;
|
||||
u32 emc_emrs;
|
||||
u32 emc_emrs2;
|
||||
u32 emc_auto_cal_config;
|
||||
u32 emc_auto_cal_config2;
|
||||
u32 emc_auto_cal_config3;
|
||||
u32 emc_auto_cal_config4;
|
||||
u32 emc_auto_cal_config5;
|
||||
u32 emc_auto_cal_config6;
|
||||
u32 emc_auto_cal_config7;
|
||||
u32 emc_auto_cal_config8;
|
||||
u32 emc_cfg_2;
|
||||
u32 emc_sel_dpd_ctrl;
|
||||
u32 emc_fdpd_ctrl_cmd_no_ramp;
|
||||
u32 dll_clk_src;
|
||||
u32 clk_out_enb_x_0_clk_enb_emc_dll;
|
||||
u32 latency;
|
||||
} emc_table_t;
|
||||
|
||||
#endif
|
||||
4068
modules/hekate_libsys_minerva/sys_sdrammtc.c
Normal file
4068
modules/hekate_libsys_minerva/sys_sdrammtc.c
Normal file
File diff suppressed because it is too large
Load Diff
54
modules/hekate_libsys_minerva/types.h
Normal file
54
modules/hekate_libsys_minerva/types.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _TYPES_H_
|
||||
#define _TYPES_H_
|
||||
|
||||
#define NULL ((void *)0)
|
||||
|
||||
#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
#define OFFSET_OF(t, m) ((u32)&((t *)NULL)->m)
|
||||
#define CONTAINER_OF(mp, t, mn) ((t *)((u32)mp - OFFSET_OF(t, mn)))
|
||||
|
||||
typedef char s8;
|
||||
typedef short s16;
|
||||
typedef short SHORT;
|
||||
typedef int s32;
|
||||
typedef int INT;
|
||||
typedef long LONG;
|
||||
typedef long long int s64;
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned short WORD;
|
||||
typedef unsigned short WCHAR;
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned int UINT;
|
||||
typedef unsigned long DWORD;
|
||||
typedef unsigned long long QWORD;
|
||||
typedef unsigned long long int u64;
|
||||
typedef volatile unsigned char vu8;
|
||||
typedef volatile unsigned short vu16;
|
||||
typedef volatile unsigned int vu32;
|
||||
|
||||
typedef int bool;
|
||||
#define true 1
|
||||
#define false 0
|
||||
|
||||
#endif
|
||||
@@ -1,46 +1,59 @@
|
||||
[config]
|
||||
autoboot=5
|
||||
autoboot=4
|
||||
autoboot_list=0
|
||||
bootwait=3
|
||||
customlogo=1
|
||||
verification=2
|
||||
verification=1
|
||||
backlight=100
|
||||
autohosoff=0
|
||||
autonogc=1
|
||||
|
||||
{-------- Stock -------}
|
||||
[Stock]
|
||||
[Stock 6.2.0 and lower]
|
||||
stock=1
|
||||
|
||||
[Stock (SVC perms)]
|
||||
fullsvcperm=1
|
||||
debugmode=1
|
||||
|
||||
[Stock (Prevent GC access)]
|
||||
kip1patch=nogc
|
||||
|
||||
[Stock (Allow unsigned NCA)]
|
||||
kip1patch=nosigchk
|
||||
[Stock All FW]
|
||||
fss0=atmosphere/fusee-secondary.bin
|
||||
stock=1
|
||||
{ }
|
||||
# Both above disable kernel patching
|
||||
# Stock All FW, includes exosphere and warmboot, ONLY when >= 7.0.0.
|
||||
|
||||
{-- Custom Firmwares --}
|
||||
[AtmoHB]
|
||||
kip1=cfw/loader.kip1
|
||||
kip1=cfw/sm.kip1
|
||||
[Atmo FSS0 Vanilla]
|
||||
fss0=atmosphere/fusee-secondary.bin
|
||||
logopath=cfw/atmo.bmp
|
||||
|
||||
[AtmoHB (SVC Perms)]
|
||||
kip1=cfw/loader.kip1
|
||||
kip1=cfw/sm.kip1
|
||||
fullsvcperm=1
|
||||
[CFW FSS0 extra kips]
|
||||
fss0=atmosphere/fusee-secondary.bin
|
||||
kip1=cfw/mods/mods_extra/*
|
||||
kip1=cfw/mods/mods_extra/single/extra.kip
|
||||
logopath=cfw/cfw.bmp
|
||||
# Both options for kip1 can be used. Wildcard and single.
|
||||
|
||||
[Atmosphere Full]
|
||||
secmon=cfw/atmo/exosphere.bin
|
||||
kip1=cfw/atmo/loader.kip
|
||||
kip1=cfw/atmo/sm.kip
|
||||
kip1=cfw/atmo/fs_mitm.kip
|
||||
logopath=cfw/atmo/atmo.bmp
|
||||
[Atmo Vanilla]
|
||||
secmon=cfw/mods/exosphere.bin
|
||||
warmboot=cfw/mods/lp0fw.bin
|
||||
kip1=cfw/mods/loader.kip
|
||||
kip1=cfw/mods/sm.kip
|
||||
kip1=cfw/mods/pm.kip
|
||||
kip1=cfw/mods/ams_mitm.kip
|
||||
logopath=cfw/atmo.bmp
|
||||
atmosphere=1
|
||||
# kip1=cfw/atmo/pm.kip
|
||||
# All kips defined.
|
||||
|
||||
[CFW Extra kips]
|
||||
secmon=cfw/mods/exosphere.bin
|
||||
warmboot=cfw/mods/lp0fw.bin
|
||||
kip1=cfw/mods/*
|
||||
kip1=cfw/mods/extra/extra.kip
|
||||
logopath=cfw/cfw.bmp
|
||||
atmosphere=1
|
||||
# All kips parsed from a directory and extra added.
|
||||
{ }
|
||||
|
||||
{------- Tools -------}
|
||||
[Clear Error Logs]
|
||||
kip1=cfw/nx-dreport.kip
|
||||
[memloader]
|
||||
payload=bootloader/payloads/memloader.bin
|
||||
|
||||
|
||||
# hekate - CTCaer mod v3.0 .ini template
|
||||
# hekate - CTCaer mod v4.9.1 .ini template
|
||||
|
||||
38
tools/smmu_payload.py
Normal file
38
tools/smmu_payload.py
Normal file
@@ -0,0 +1,38 @@
|
||||
'''
|
||||
Copyright (c) 2018 balika011
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
'''
|
||||
|
||||
from keystone import *
|
||||
|
||||
CODE = b'''
|
||||
LDR X1, =0x70019010
|
||||
MOV X0, #0x1
|
||||
STR W0, [X1]
|
||||
|
||||
loop:
|
||||
IC IALLUIS
|
||||
DSB ISH
|
||||
B loop
|
||||
MOV X0, #0x0
|
||||
STR W0, [X1]
|
||||
LDR X0, =0x4002B000
|
||||
BR X0
|
||||
'''
|
||||
try:
|
||||
ks = Ks(KS_ARCH_ARM64, KS_MODE_LITTLE_ENDIAN)
|
||||
encoding, count = ks.asm(CODE, 0x0)
|
||||
print("%s = %s (number of statements: %u)" %(CODE, ', '.join([('0x%02x' % (x)) for x in encoding]), count))
|
||||
except KsError as e:
|
||||
print("ERROR: %s" %e)
|
||||
Reference in New Issue
Block a user