Compare commits
23 Commits
Author | SHA1 | Date | |
---|---|---|---|
4a205a8720 | |||
1f2f0c433e | |||
250f068211 | |||
19796e486c | |||
6540ddc24b | |||
2c79f8c660 | |||
82bea6be8f | |||
34890f0025 | |||
ffc4c4281f | |||
a376837886 | |||
54d14196e0 | |||
0b2442fb8e | |||
7a50772703 | |||
abc2c85864 | |||
dae4c72910 | |||
b464042f3a | |||
220fb4ba3c | |||
83b75af726 | |||
f73bb0b7b7 | |||
f612ee2a8c | |||
1bc5c2a667 | |||
3b797318f5 | |||
4a320447b3 |
94
Makefile
94
Makefile
@ -1,92 +1,62 @@
|
||||
rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2))
|
||||
|
||||
ifeq ($(strip $(DEVKITARM)),)
|
||||
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||
endif
|
||||
|
||||
include $(DEVKITARM)/base_rules
|
||||
|
||||
################################################################################
|
||||
|
||||
IPL_LOAD_ADDR := 0x40003000
|
||||
LPVERSION_MAJOR := 1
|
||||
LPVERSION_MINOR := 5
|
||||
LPVERSION_BUGFX := 0
|
||||
|
||||
################################################################################
|
||||
|
||||
TARGET := Lockpick_RCM
|
||||
LPVERSION_MAJOR := 1
|
||||
LPVERSION_MINOR := 1
|
||||
BUILD := build
|
||||
OUTPUT := output
|
||||
BUILDDIR := build
|
||||
OUTPUTDIR := output
|
||||
SOURCEDIR = source
|
||||
VPATH = $(dir $(wildcard ./$(SOURCEDIR)/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/))
|
||||
|
||||
OBJS = $(addprefix $(BUILD)/$(TARGET)/, \
|
||||
start.o \
|
||||
main.o \
|
||||
keys.o \
|
||||
heap.o \
|
||||
btn.o \
|
||||
clock.o \
|
||||
cluster.o \
|
||||
fuse.o \
|
||||
gpio.o \
|
||||
sept.o \
|
||||
i2c.o \
|
||||
max7762x.o \
|
||||
max17050.o \
|
||||
mc.o \
|
||||
nx_emmc.o \
|
||||
sdmmc.o \
|
||||
sdmmc_driver.o \
|
||||
sdram.o \
|
||||
sdram_lp0.o \
|
||||
util.o \
|
||||
di.o \
|
||||
gfx.o \
|
||||
pinmux.o \
|
||||
pkg1.o \
|
||||
pkg2.o \
|
||||
se.o \
|
||||
tsec.o \
|
||||
hw_init.o \
|
||||
smmu.o \
|
||||
max77620-rtc.o \
|
||||
)
|
||||
OBJS = $(patsubst $(SOURCEDIR)/%.S, $(BUILDDIR)/$(TARGET)/%.o, \
|
||||
$(patsubst $(SOURCEDIR)/%.c, $(BUILDDIR)/$(TARGET)/%.o, \
|
||||
$(call rwildcard, $(SOURCEDIR), *.S *.c)))
|
||||
|
||||
OBJS += $(addprefix $(BUILD)/$(TARGET)/, \
|
||||
lz.o blz.o \
|
||||
diskio.o ff.o ffunicode.o ffsystem.o \
|
||||
)
|
||||
################################################################################
|
||||
|
||||
CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR)
|
||||
CUSTOMDEFINES += -DLP_VER_MJ=$(LPVERSION_MAJOR) -DLP_VER_MN=$(LPVERSION_MINOR)
|
||||
CUSTOMDEFINES += -DLP_VER_MJ=$(LPVERSION_MAJOR) -DLP_VER_MN=$(LPVERSION_MINOR) -DLP_VER_BF=$(LPVERSION_BUGFX)
|
||||
|
||||
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork
|
||||
CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -std=gnu11 -Wall $(CUSTOMDEFINES)
|
||||
LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=IPL_LOAD_ADDR=$(IPL_LOAD_ADDR)
|
||||
|
||||
MODULEDIRS := $(wildcard modules/*)
|
||||
################################################################################
|
||||
|
||||
.PHONY: all clean $(MODULEDIRS)
|
||||
.PHONY: all clean
|
||||
|
||||
all: $(TARGET).bin
|
||||
@echo -n "Payload size is "
|
||||
@wc -c < $(OUTPUT)/$(TARGET).bin
|
||||
@echo "Max size is 126296 Bytes."
|
||||
all: $(OUTPUTDIR)/$(TARGET).bin
|
||||
|
||||
clean:
|
||||
@rm -rf $(OBJS)
|
||||
@rm -rf $(BUILD)
|
||||
@rm -rf $(OUTPUT)
|
||||
@rm -rf $(BUILDDIR)
|
||||
@rm -rf $(OUTPUTDIR)
|
||||
|
||||
$(MODULEDIRS):
|
||||
$(MAKE) -C $@ $(MAKECMDGOALS)
|
||||
$(OUTPUTDIR)/$(TARGET).bin: $(BUILDDIR)/$(TARGET)/$(TARGET).elf
|
||||
@mkdir -p "$(@D)"
|
||||
$(OBJCOPY) -S -O binary $< $@
|
||||
@echo -n "Payload size is "
|
||||
@wc -c < $@
|
||||
@echo "Max size is 126296 Bytes."
|
||||
|
||||
$(TARGET).bin: $(BUILD)/$(TARGET)/$(TARGET).elf $(MODULEDIRS)
|
||||
$(OBJCOPY) -S -O binary $< $(OUTPUT)/$@
|
||||
|
||||
$(BUILD)/$(TARGET)/$(TARGET).elf: $(OBJS)
|
||||
$(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS)
|
||||
$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@
|
||||
|
||||
$(BUILD)/$(TARGET)/%.o: %.c
|
||||
$(BUILDDIR)/$(TARGET)/%.o: $(SOURCEDIR)/%.c
|
||||
@mkdir -p "$(@D)"
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(BUILD)/$(TARGET)/%.o: %.S
|
||||
@mkdir -p "$(BUILD)"
|
||||
@mkdir -p "$(BUILD)/$(TARGET)"
|
||||
@mkdir -p "$(OUTPUT)"
|
||||
$(BUILDDIR)/$(TARGET)/%.o: $(SOURCEDIR)/%.S
|
||||
@mkdir -p "$(@D)"
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
@ -2,13 +2,13 @@ Lockpick_RCM
|
||||
=
|
||||
Lockpick_RCM is a bare metal Nintendo Switch payload that derives encryption keys for use in Switch file handling software like hactool, hactoolnet/LibHac, ChoiDujour, etc. without booting Horizon OS.
|
||||
|
||||
Due to changes imposed by firmware 7.0.0, Lockpick homebrew can no longer derive the latest keys. In the boot-time environment however, there are fewer limitations.
|
||||
Due to changes imposed by firmware 7.0.0, Lockpick homebrew can no longer derive the latest keys. In the boot-time environment however, there is no such limitation.
|
||||
|
||||
Usage
|
||||
=
|
||||
* Launch Lockpick_RCM.bin using your favorite payload injector
|
||||
* Upon completion, keys will be saved to `/switch/prod.keys` on SD
|
||||
* If the console has Firmware 7.x, the `/sept/` folder from [Atmosphère](https://github.com/Atmosphere-NX/Atmosphere/releases) or [Kosmos](https://github.com/AtlasNX/Kosmos/releases) release zip containing both `sept-primary.bin` and `sept-secondary.enc` must be present on SD or else only keyblob master key derivation is possible (ie. up to `master_key_05` only)
|
||||
* If the console has Firmware 7.x or higher, the `/sept/` folder from [Atmosphère](https://github.com/Atmosphere-NX/Atmosphere/releases) or [Kosmos](https://github.com/AtlasNX/Kosmos/releases) release zip must be present on SD or else only keyblob master key derivation is possible (ie. up to `master_key_05` only)
|
||||
|
||||
Building
|
||||
=
|
||||
|
54
source/config/config.c
Normal file
54
source/config/config.c
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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 <stdlib.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "ini.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
#include "../utils/btn.h"
|
||||
#include "../utils/list.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
extern hekate_config h_cfg;
|
||||
extern bool sd_mount();
|
||||
extern void sd_unmount();
|
||||
|
||||
void set_default_configuration()
|
||||
{
|
||||
h_cfg.autoboot = 0;
|
||||
h_cfg.autoboot_list = 0;
|
||||
h_cfg.bootwait = 3;
|
||||
h_cfg.verification = 1;
|
||||
h_cfg.se_keygen_done = 0;
|
||||
h_cfg.sbar_time_keeping = 0;
|
||||
h_cfg.backlight = 100;
|
||||
h_cfg.autohosoff = 0;
|
||||
h_cfg.autonogc = 1;
|
||||
h_cfg.brand = NULL;
|
||||
h_cfg.tagline = NULL;
|
||||
h_cfg.errors = 0;
|
||||
h_cfg.sept_run = EMC(EMC_SCRATCH0) & EMC_SEPT_RUN;
|
||||
h_cfg.rcm_patched = true;
|
||||
h_cfg.emummc_force_disable = false;
|
||||
|
||||
sd_power_cycle_time_start = 0xFFFFFFF;
|
||||
}
|
||||
|
50
source/config/config.h
Normal file
50
source/config/config.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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 _CONFIG_H_
|
||||
#define _CONFIG_H_
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
typedef struct _hekate_config
|
||||
{
|
||||
// Non-volatile config.
|
||||
u32 autoboot;
|
||||
u32 autoboot_list;
|
||||
u32 bootwait;
|
||||
u32 verification;
|
||||
u32 backlight;
|
||||
u32 autohosoff;
|
||||
u32 autonogc;
|
||||
char *brand;
|
||||
char *tagline;
|
||||
// Global temporary config.
|
||||
bool se_keygen_done;
|
||||
bool sept_run;
|
||||
bool emummc_force_disable;
|
||||
bool rcm_patched;
|
||||
u32 sbar_time_keeping;
|
||||
u32 errors;
|
||||
} hekate_config;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ERR_LIBSYS_LP0 = (1 << 0),
|
||||
} hsysmodule_t;
|
||||
|
||||
void set_default_configuration();
|
||||
|
||||
#endif /* _CONFIG_H_ */
|
193
source/config/ini.c
Normal file
193
source/config/ini.c
Normal file
@ -0,0 +1,193 @@
|
||||
/*
|
||||
* 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 "ini.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../utils/dirlist.h"
|
||||
|
||||
static char *_strdup(char *str)
|
||||
{
|
||||
if (!str)
|
||||
return NULL;
|
||||
|
||||
// Remove starting space.
|
||||
if (str[0] == ' ' && strlen(str))
|
||||
str++;
|
||||
|
||||
char *res = (char *)malloc(strlen(str) + 1);
|
||||
strcpy(res, str);
|
||||
|
||||
// Remove trailing space.
|
||||
if (strlen(res) && res[strlen(res) - 1] == ' ')
|
||||
res[strlen(res) - 1] = 0;
|
||||
|
||||
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;
|
||||
u32 pathlen = strlen(ini_path);
|
||||
u32 k = 0;
|
||||
char lbuf[512];
|
||||
char *filelist = NULL;
|
||||
FIL fp;
|
||||
ini_sec_t *csec = NULL;
|
||||
|
||||
char *filename = (char *)malloc(256);
|
||||
|
||||
memcpy(filename, ini_path, pathlen + 1);
|
||||
|
||||
// Get all ini filenames.
|
||||
if (is_dir)
|
||||
{
|
||||
filelist = dirlist(filename, "*.ini", false);
|
||||
if (!filelist)
|
||||
{
|
||||
free(filename);
|
||||
return 0;
|
||||
}
|
||||
memcpy(filename + pathlen, "/", 2);
|
||||
pathlen++;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
// Copy ini filename in path string.
|
||||
if (is_dir)
|
||||
{
|
||||
if (filelist[k * 256])
|
||||
{
|
||||
memcpy(filename + pathlen, &filelist[k * 256], strlen(&filelist[k * 256]) + 1);
|
||||
k++;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
// Open ini.
|
||||
if (f_open(&fp, filename, FA_READ) != FR_OK)
|
||||
{
|
||||
free(filelist);
|
||||
free(filename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
// Fetch one line.
|
||||
lbuf[0] = 0;
|
||||
f_gets(lbuf, 512, &fp);
|
||||
lblen = strlen(lbuf);
|
||||
|
||||
// Remove trailing newline.
|
||||
if (lbuf[lblen - 1] == '\n' || lbuf[lblen - 1] == '\r')
|
||||
lbuf[lblen - 1] = 0;
|
||||
|
||||
if (lblen > 2 && lbuf[0] == '[') // Create new section.
|
||||
{
|
||||
_find_section_name(lbuf, lblen, ']');
|
||||
|
||||
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CHOICE);
|
||||
list_init(&csec->kvs);
|
||||
}
|
||||
else if (lblen > 2 && lbuf[0] == '{') //Create new caption.
|
||||
{
|
||||
_find_section_name(lbuf, lblen, '}');
|
||||
|
||||
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CAPTION);
|
||||
csec->color = 0xFF0AB9E6;
|
||||
}
|
||||
else if (lblen > 2 && lbuf[0] == '#') //Create empty lines and comments.
|
||||
{
|
||||
_find_section_name(lbuf, lblen, '\0');
|
||||
|
||||
csec = _ini_create_section(dst, csec, &lbuf[1], INI_COMMENT);
|
||||
}
|
||||
else if (lblen < 2)
|
||||
{
|
||||
csec = _ini_create_section(dst, csec, NULL, INI_NEWLINE);
|
||||
}
|
||||
else if (csec && csec->type == INI_CHOICE) //Extract key/value.
|
||||
{
|
||||
u32 i = _find_section_name(lbuf, lblen, '=');
|
||||
|
||||
ini_kv_t *kv = (ini_kv_t *)malloc(sizeof(ini_kv_t));
|
||||
kv->key = _strdup(&lbuf[0]);
|
||||
kv->val = _strdup(&lbuf[i + 1]);
|
||||
list_append(&csec->kvs, &kv->link);
|
||||
}
|
||||
} while (!f_eof(&fp));
|
||||
|
||||
f_close(&fp);
|
||||
|
||||
if (csec)
|
||||
{
|
||||
list_append(dst, &csec->link);
|
||||
if (is_dir)
|
||||
csec = NULL;
|
||||
}
|
||||
} while (is_dir);
|
||||
|
||||
free(filename);
|
||||
free(filelist);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *ini_check_payload_section(ini_sec_t *cfg)
|
||||
{
|
||||
if (cfg == NULL)
|
||||
return NULL;
|
||||
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)
|
||||
{
|
||||
if (!strcmp("payload", kv->key))
|
||||
return kv->val;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
50
source/config/ini.h
Normal file
50
source/config/ini.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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 _INI_H_
|
||||
#define _INI_H_
|
||||
|
||||
#include "../utils/types.h"
|
||||
#include "../utils/list.h"
|
||||
|
||||
#define INI_CHOICE 3
|
||||
#define INI_CAPTION 5
|
||||
#define INI_CHGLINE 6
|
||||
#define INI_NEWLINE 0xFE
|
||||
#define INI_COMMENT 0xFF
|
||||
|
||||
typedef struct _ini_kv_t
|
||||
{
|
||||
char *key;
|
||||
char *val;
|
||||
link_t link;
|
||||
} ini_kv_t;
|
||||
|
||||
typedef struct _ini_sec_t
|
||||
{
|
||||
char *name;
|
||||
link_t kvs;
|
||||
link_t link;
|
||||
u32 type;
|
||||
u32 color;
|
||||
} ini_sec_t;
|
||||
|
||||
int ini_parse(link_t *dst, char *ini_path, bool is_dir);
|
||||
char *ini_check_payload_section(ini_sec_t *cfg);
|
||||
|
||||
#endif
|
||||
|
112
source/gfx/di.c
112
source/gfx/di.c
@ -18,15 +18,16 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "di.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../utils/util.h"
|
||||
#include "../soc/i2c.h"
|
||||
#include "../soc/pmc.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../power/max77620.h"
|
||||
#include "../power/max7762x.h"
|
||||
#include "../soc/gpio.h"
|
||||
#include "../soc/pinmux.h"
|
||||
#include "../soc/clock.h"
|
||||
#include "../soc/gpio.h"
|
||||
#include "../soc/i2c.h"
|
||||
#include "../soc/pinmux.h"
|
||||
#include "../soc/pmc.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
#include "di.inl"
|
||||
|
||||
@ -46,54 +47,61 @@ void display_init()
|
||||
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;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x1010000;
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = 0x18000000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x20000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIP_CAL) = 0xA;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = 0x80000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP) = 0xA;
|
||||
// Enable Display Interface specific clocks.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x1010000; // Clear reset DSI, MIPI_CAL.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x1010000; // Set enable clock DSI, MIPI_CAL.
|
||||
|
||||
// DPD idle.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000; // Clear reset DISP1, HOST1X.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = 0x18000000; // Set enable clock DISP1, HOST1X.
|
||||
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x20000; // Set enable clock UART_FST_MIPI_CAL.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL) = 10; // Set PLLP_OUT3 and div 6 (17MHz).
|
||||
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = 0x80000; // Set enable clock DSIA_LP.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP) = 10; // Set PLLP_OUT and div 6 (68MHz).
|
||||
|
||||
// Disable deap power down.
|
||||
PMC(APBDEV_PMC_IO_DPD_REQ) = 0x40000000;
|
||||
PMC(APBDEV_PMC_IO_DPD2_REQ) = 0x40000000;
|
||||
|
||||
// Config pins.
|
||||
// Config LCD and Backlight pins.
|
||||
PINMUX_AUX(PINMUX_AUX_NFC_EN) &= ~PINMUX_TRISTATE;
|
||||
PINMUX_AUX(PINMUX_AUX_NFC_INT) &= ~PINMUX_TRISTATE;
|
||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) &= ~PINMUX_TRISTATE;
|
||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_EN) &= ~PINMUX_TRISTATE;
|
||||
PINMUX_AUX(PINMUX_AUX_LCD_RST) &= ~PINMUX_TRISTATE;
|
||||
|
||||
gpio_config(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_MODE_GPIO); // Backlight +-5V.
|
||||
gpio_output_enable(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_OUTPUT_ENABLE); // Backlight +-5V.
|
||||
// Set Backlight +-5V pins mode and direction
|
||||
gpio_config(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||
gpio_output_enable(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_OUTPUT_ENABLE);
|
||||
|
||||
// Enable Backlight power.
|
||||
gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_HIGH); // Backlight +5V enable.
|
||||
|
||||
usleep(10000);
|
||||
|
||||
gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_HIGH); // Backlight -5V enable.
|
||||
|
||||
usleep(10000);
|
||||
|
||||
gpio_config(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_MODE_GPIO); // Backlight PWM, Enable, Reset.
|
||||
// Configure Backlight pins (PWM, EN, RST).
|
||||
gpio_config(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_MODE_GPIO);
|
||||
gpio_output_enable(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_OUTPUT_ENABLE);
|
||||
gpio_write(GPIO_PORT_V, GPIO_PIN_1, GPIO_HIGH); // Backlight Enable enable.
|
||||
gpio_write(GPIO_PORT_V, GPIO_PIN_1, GPIO_HIGH); // Enable Backlight EN.
|
||||
|
||||
// Config display interface and display.
|
||||
// Power up supply regulator for display interface.
|
||||
MIPI_CAL(MIPI_CAL_MIPI_BIAS_PAD_CFG2) = 0;
|
||||
|
||||
// Set DISP1 clock source and parrent clock.
|
||||
exec_cfg((u32 *)CLOCK_BASE, _display_config_1, 4);
|
||||
|
||||
// Setup display communication interfaces.
|
||||
exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_2, 94);
|
||||
exec_cfg((u32 *)DSI_BASE, _display_config_3, 61);
|
||||
|
||||
usleep(10000);
|
||||
|
||||
gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_HIGH); // Backlight Reset enable.
|
||||
|
||||
// Enable Backlight Reset.
|
||||
gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_HIGH);
|
||||
usleep(60000);
|
||||
|
||||
// Setups DSI packet configuration and request display id.
|
||||
DSI(_DSIREG(DSI_BTA_TIMING)) = 0x50204;
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x337; // MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE
|
||||
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
|
||||
@ -122,19 +130,22 @@ void display_init()
|
||||
|
||||
usleep(20000);
|
||||
|
||||
// Configure PLLD for DISP1.
|
||||
exec_cfg((u32 *)CLOCK_BASE, _display_config_6, 3);
|
||||
|
||||
// Finalize DSI configuration.
|
||||
exec_cfg((u32 *)DSI_BASE, _display_config_5, 21);
|
||||
DISPLAY_A(_DIREG(DC_DISP_DISP_CLOCK_CONTROL)) = 4;
|
||||
exec_cfg((u32 *)DSI_BASE, _display_config_7, 10);
|
||||
|
||||
usleep(10000);
|
||||
|
||||
// Calibrate display communication pads.
|
||||
exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_8, 6);
|
||||
exec_cfg((u32 *)DSI_BASE, _display_config_9, 4);
|
||||
exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_10, 16);
|
||||
|
||||
usleep(10000);
|
||||
|
||||
// Enable video display controller.
|
||||
exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_11, 113);
|
||||
}
|
||||
|
||||
@ -142,11 +153,10 @@ void display_backlight_pwm_init()
|
||||
{
|
||||
clock_enable_pwm();
|
||||
|
||||
PWM(PWM_CONTROLLER_PWM_CSR_0) = (1 << 31); // Enable PWM
|
||||
PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN; // Enable PWM and set it to 25KHz PFM.
|
||||
|
||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) >> 2) << 2 | 1; // PWM clock source.
|
||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & 0xFFFFFFFC) | 1; // PWM clock source.
|
||||
gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight power mode.
|
||||
|
||||
}
|
||||
|
||||
void display_backlight(bool enable)
|
||||
@ -167,7 +177,7 @@ void display_backlight_brightness(u32 brightness, u32 step_delay)
|
||||
{
|
||||
for (u32 i = old_value; i < brightness + 1; i++)
|
||||
{
|
||||
PWM(PWM_CONTROLLER_PWM_CSR_0) = (1 << 31) | (i << 16); // Enable PWM
|
||||
PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN | (i << 16); // Enable PWM and set it to 25KHz PFM.
|
||||
usleep(step_delay);
|
||||
}
|
||||
}
|
||||
@ -175,7 +185,7 @@ void display_backlight_brightness(u32 brightness, u32 step_delay)
|
||||
{
|
||||
for (u32 i = old_value; i > brightness; i--)
|
||||
{
|
||||
PWM(PWM_CONTROLLER_PWM_CSR_0) = (1 << 31) | (i << 16); // Enable PWM
|
||||
PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN | (i << 16); // Enable PWM and set it to 25KHz PFM.
|
||||
usleep(step_delay);
|
||||
}
|
||||
}
|
||||
@ -191,13 +201,14 @@ void display_end()
|
||||
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;
|
||||
DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0; // Disable host cmd packet.
|
||||
|
||||
// De-initialize video controller.
|
||||
exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_12, 17);
|
||||
exec_cfg((u32 *)DSI_BASE, _display_config_13, 16);
|
||||
|
||||
usleep(10000);
|
||||
|
||||
// De-initialize display panel.
|
||||
if (_display_ver == 0x10)
|
||||
exec_cfg((u32 *)DSI_BASE, _display_config_14, 22);
|
||||
|
||||
@ -206,31 +217,31 @@ void display_end()
|
||||
|
||||
usleep(50000);
|
||||
|
||||
// Disable display and backlight pins.
|
||||
gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_LOW); //Backlight Reset disable.
|
||||
|
||||
usleep(10000);
|
||||
|
||||
gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_LOW); //Backlight -5V disable.
|
||||
|
||||
usleep(10000);
|
||||
|
||||
gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_LOW); //Backlight +5V disable.
|
||||
|
||||
usleep(10000);
|
||||
|
||||
// Disable clocks.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = 0x1010000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_CLR) = 0x1010000;
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = 0x18000000;
|
||||
// Disable Display Interface specific clocks.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = 0x1010000; // Set reset clock DSI, MIPI_CAL.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_CLR) = 0x1010000; // Clear enable clock DSI, MIPI_CAL.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000; // Set reset DISP1, HOST1X.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = 0x18000000; // Clear enable DISP1, HOST1X.
|
||||
|
||||
// Power down pads.
|
||||
DSI(_DSIREG(DSI_PAD_CONTROL_0)) = DSI_PAD_CONTROL_VS1_PULLDN_CLK | DSI_PAD_CONTROL_VS1_PULLDN(0xF) | DSI_PAD_CONTROL_VS1_PDIO_CLK | DSI_PAD_CONTROL_VS1_PDIO(0xF);
|
||||
DSI(_DSIREG(DSI_POWER_CONTROL)) = 0;
|
||||
|
||||
// Switch to automatic function mode.
|
||||
gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight PWM.
|
||||
|
||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & ~PINMUX_TRISTATE) | PINMUX_TRISTATE;
|
||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) >> 2) << 2 | 1;
|
||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & 0xFFFFFFFC)| 1;
|
||||
}
|
||||
|
||||
void display_color_screen(u32 color)
|
||||
@ -243,7 +254,6 @@ void display_color_screen(u32 color)
|
||||
DISPLAY_A(_DIREG(DC_WIN_CD_WIN_OPTIONS)) = 0;
|
||||
DISPLAY_A(_DIREG(DC_DISP_BLEND_BACKGROUND_COLOR)) = color;
|
||||
DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = (DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) & 0xFFFFFFFE) | GENERAL_ACT_REQ;
|
||||
|
||||
usleep(35000);
|
||||
|
||||
display_backlight(true);
|
||||
@ -252,11 +262,11 @@ void display_color_screen(u32 color)
|
||||
u32 *display_init_framebuffer()
|
||||
{
|
||||
// Sanitize framebuffer area.
|
||||
memset((u32 *)0xC0000000, 0, 0x3C0000);
|
||||
// This configures the framebuffer @ 0xC0000000 with a resolution of 1280x720 (line stride 768).
|
||||
memset((u32 *)FB_ADDRESS, 0, 0x3C0000);
|
||||
// This configures the framebuffer @ IPL_FB_ADDRESS with a resolution of 1280x720 (line stride 720).
|
||||
exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer, 32);
|
||||
|
||||
usleep(35000);
|
||||
|
||||
return (u32 *)0xC0000000;
|
||||
return (u32 *)FB_ADDRESS;
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,8 @@
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
#define FB_ADDRESS 0xC0000000
|
||||
|
||||
/*! Display registers. */
|
||||
#define _DIREG(reg) ((reg) * 4)
|
||||
|
||||
@ -233,7 +235,7 @@
|
||||
#define UV_LINE_STRIDE(x) (((x) & 0xffff) << 16)
|
||||
#define DC_WIN_DV_CONTROL 0x70E
|
||||
|
||||
// The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER).
|
||||
/*! The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER). */
|
||||
#define DC_WINBUF_START_ADDR 0x800
|
||||
#define DC_WINBUF_ADDR_H_OFFSET 0x806
|
||||
#define DC_WINBUF_ADDR_V_OFFSET 0x808
|
||||
@ -333,7 +335,7 @@
|
||||
#define DSI_PAD_CONTROL_VS1_PDIO_CLK (1 << 8)
|
||||
#define DSI_PAD_CONTROL_VS1_PDIO(x) (((x) & 0xf) << 0)
|
||||
|
||||
#define DSI_PAD_CONTROL_CD 0x4c
|
||||
#define DSI_PAD_CONTROL_CD 0x4C
|
||||
#define DSI_VIDEO_MODE_CONTROL 0x4E
|
||||
|
||||
#define DSI_PAD_CONTROL_1 0x4F
|
||||
|
@ -122,13 +122,13 @@ static const cfg_op_t _display_config_2[94] = {
|
||||
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{DC_WIN_WIN_OPTIONS, 0},
|
||||
{DC_DISP_DISP_WIN_OPTIONS, 0},
|
||||
{DC_CMD_DISPLAY_COMMAND, 0},
|
||||
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}
|
||||
};
|
||||
|
||||
//DSI Init config.
|
||||
static const cfg_op_t _display_config_3[61] = {
|
||||
static const cfg_op_t _display_config_3[61] = {
|
||||
{DSI_WR_DATA, 0},
|
||||
{DSI_INT_ENABLE, 0},
|
||||
{DSI_INT_STATUS, 0},
|
||||
@ -405,7 +405,7 @@ static const cfg_op_t _display_config_11[113] = {
|
||||
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{DC_WIN_WIN_OPTIONS, 0},
|
||||
{DC_DISP_DISP_WIN_OPTIONS, 0},
|
||||
{DC_CMD_DISPLAY_COMMAND, 0},
|
||||
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ},
|
||||
{DC_CMD_STATE_ACCESS, 0},
|
||||
@ -455,7 +455,7 @@ static const cfg_op_t _display_config_12[17] = {
|
||||
{DC_CMD_STATE_ACCESS, 0},
|
||||
{DC_CMD_INT_ENABLE, 0},
|
||||
{DC_CMD_CONT_SYNCPT_VSYNC, 0},
|
||||
{DC_CMD_DISPLAY_COMMAND, 0},
|
||||
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
@ -548,7 +548,7 @@ static const cfg_op_t cfg_display_framebuffer[32] = {
|
||||
{DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(720 * 2) | LINE_STRIDE(720 * 4)}, //768*2x768*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements.
|
||||
{DC_WIN_BUFFER_CONTROL, 0},
|
||||
{DC_WINBUF_SURFACE_KIND, 0}, //Regular surface.
|
||||
{DC_WINBUF_START_ADDR, 0xC0000000}, //Framebuffer address.
|
||||
{DC_WINBUF_START_ADDR, FB_ADDRESS}, //Framebuffer address.
|
||||
{DC_WINBUF_ADDR_H_OFFSET, 0},
|
||||
{DC_WINBUF_ADDR_V_OFFSET, 0},
|
||||
{DC_WIN_WIN_OPTIONS, 0},
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (C) 2018-2019 CTCaer
|
||||
* Copyright (c) 2019 shchmue
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@ -128,12 +128,12 @@ void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride)
|
||||
|
||||
void gfx_clear_grey(u8 color)
|
||||
{
|
||||
memset(gfx_ctxt.fb, color, 0x3C0000);
|
||||
memset(gfx_ctxt.fb, color, gfx_ctxt.width * gfx_ctxt.height * 4);
|
||||
}
|
||||
|
||||
void gfx_clear_color(u32 color)
|
||||
{
|
||||
for (u32 i = 0; i < gfx_ctxt.height * gfx_ctxt.stride; i++)
|
||||
for (u32 i = 0; i < gfx_ctxt.width * gfx_ctxt.height; i++)
|
||||
gfx_ctxt.fb[i] = color;
|
||||
}
|
||||
|
||||
@ -263,7 +263,6 @@ void gfx_putc(char c)
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void gfx_puts(const char *s)
|
||||
@ -306,7 +305,7 @@ static void _gfx_putn(u32 v, int base, char fill, int fcnt)
|
||||
gfx_puts(p);
|
||||
}
|
||||
|
||||
void gfx_put_small_sep(gfx_con_t *con)
|
||||
void gfx_put_small_sep()
|
||||
{
|
||||
u8 prevFontSize = gfx_con.fntsz;
|
||||
gfx_con.fntsz = 8;
|
||||
@ -314,7 +313,7 @@ void gfx_put_small_sep(gfx_con_t *con)
|
||||
gfx_con.fntsz = prevFontSize;
|
||||
}
|
||||
|
||||
void gfx_put_big_sep(gfx_con_t *con)
|
||||
void gfx_put_big_sep()
|
||||
{
|
||||
u8 prevFontSize = gfx_con.fntsz;
|
||||
gfx_con.fntsz = 16;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (C) 2018-2019 CTCaer
|
||||
* Copyright (C) 2018 M4xw
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@ -41,8 +41,8 @@ void gfx_hexdump(u32 base, const u8 *buf, u32 len);
|
||||
|
||||
void gfx_set_pixel(u32 x, u32 y, u32 color);
|
||||
void gfx_line(int x0, int y0, int x1, int y1, u32 color);
|
||||
void gfx_put_small_sep(gfx_con_t *con);
|
||||
void gfx_put_big_sep(gfx_con_t *con);
|
||||
void gfx_put_small_sep();
|
||||
void gfx_put_big_sep();
|
||||
void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
||||
void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
||||
void gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
||||
|
227
source/gfx/tui.c
Normal file
227
source/gfx/tui.c
Normal file
@ -0,0 +1,227 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include "di.h"
|
||||
#include "tui.h"
|
||||
#include "../utils/btn.h"
|
||||
#include "../config/config.h"
|
||||
#include "../power/max17050.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
#ifdef MENU_LOGO_ENABLE
|
||||
extern u8 *Kc_MENU_LOGO;
|
||||
#define X_MENU_LOGO 119
|
||||
#define Y_MENU_LOGO 57
|
||||
#define X_POS_MENU_LOGO 577
|
||||
#define Y_POS_MENU_LOGO 1179
|
||||
#endif //MENU_LOGO_ENABLE
|
||||
|
||||
extern hekate_config h_cfg;
|
||||
|
||||
void tui_sbar(bool force_update)
|
||||
{
|
||||
u32 cx, cy;
|
||||
|
||||
u32 timePassed = get_tmr_s() - h_cfg.sbar_time_keeping;
|
||||
if (!force_update)
|
||||
if (timePassed < 5)
|
||||
return;
|
||||
|
||||
u8 prevFontSize = gfx_con.fntsz;
|
||||
gfx_con.fntsz = 16;
|
||||
h_cfg.sbar_time_keeping = get_tmr_s();
|
||||
|
||||
u32 battPercent = 0;
|
||||
int battVoltCurr = 0;
|
||||
|
||||
gfx_con_getpos(&cx, &cy);
|
||||
gfx_con_setpos(0, 1260);
|
||||
|
||||
max17050_get_property(MAX17050_RepSOC, (int *)&battPercent);
|
||||
max17050_get_property(MAX17050_VCELL, &battVoltCurr);
|
||||
|
||||
gfx_clear_partial_grey(0x30, 1256, 24);
|
||||
gfx_printf("%K%k Battery: %d.%d%% (%d mV) - Charge:", 0xFF303030, 0xFF888888,
|
||||
(battPercent >> 8) & 0xFF, (battPercent & 0xFF) / 26, battVoltCurr);
|
||||
|
||||
max17050_get_property(MAX17050_Current, &battVoltCurr);
|
||||
|
||||
if (battVoltCurr >= 0)
|
||||
gfx_printf(" %k+%d mA%k%K\n",
|
||||
0xFF008800, battVoltCurr / 1000, 0xFFCCCCCC, 0xFF1B1B1B);
|
||||
else
|
||||
gfx_printf(" %k-%d mA%k%K\n",
|
||||
0xFF880000, (~battVoltCurr) / 1000, 0xFFCCCCCC, 0xFF1B1B1B);
|
||||
gfx_con.fntsz = prevFontSize;
|
||||
gfx_con_setpos(cx, cy);
|
||||
}
|
||||
|
||||
void tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol)
|
||||
{
|
||||
u32 cx, cy;
|
||||
if (val > 200)
|
||||
val = 200;
|
||||
|
||||
gfx_con_getpos(&cx, &cy);
|
||||
|
||||
gfx_con_setpos(x, y);
|
||||
|
||||
gfx_printf("%k[%3d%%]%k", fgcol, val, 0xFFCCCCCC);
|
||||
|
||||
x += 7 * gfx_con.fntsz;
|
||||
|
||||
for (int i = 0; i < (gfx_con.fntsz >> 3) * 6; i++)
|
||||
{
|
||||
gfx_line(x, y + i + 1, x + 3 * val, y + i + 1, fgcol);
|
||||
gfx_line(x + 3 * val, y + i + 1, x + 3 * 100, y + i + 1, bgcol);
|
||||
}
|
||||
|
||||
gfx_con_setpos(cx, cy);
|
||||
|
||||
// Update status bar.
|
||||
tui_sbar(false);
|
||||
}
|
||||
|
||||
void *tui_do_menu(menu_t *menu)
|
||||
{
|
||||
int idx = 0, prev_idx = 0, cnt = 0x7FFFFFFF;
|
||||
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
tui_sbar(true);
|
||||
|
||||
#ifdef MENU_LOGO_ENABLE
|
||||
gfx_set_rect_rgb(Kc_MENU_LOGO,
|
||||
X_MENU_LOGO, Y_MENU_LOGO, X_POS_MENU_LOGO, Y_POS_MENU_LOGO);
|
||||
#endif //MENU_LOGO_ENABLE
|
||||
|
||||
while (true)
|
||||
{
|
||||
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
|
||||
gfx_con_setpos(menu->x, menu->y);
|
||||
gfx_printf("[%kLo%kck%kpi%kck%k_R%kCM%k v%d.%d.%d%k]\n\n",
|
||||
colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], 0xFFFF00FF, LP_VER_MJ, LP_VER_MN, LP_VER_BF, 0xFFCCCCCC);
|
||||
|
||||
// Skip caption or seperator lines selection.
|
||||
while (menu->ents[idx].type == MENT_CAPTION ||
|
||||
menu->ents[idx].type == MENT_CHGLINE)
|
||||
{
|
||||
if (prev_idx <= idx || (!idx && prev_idx == cnt - 1))
|
||||
{
|
||||
idx++;
|
||||
if (idx > (cnt - 1))
|
||||
{
|
||||
idx = 0;
|
||||
prev_idx = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
idx--;
|
||||
if (idx < 0)
|
||||
{
|
||||
idx = cnt - 1;
|
||||
prev_idx = cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
prev_idx = idx;
|
||||
|
||||
// Draw the menu.
|
||||
for (cnt = 0; menu->ents[cnt].type != MENT_END; cnt++)
|
||||
{
|
||||
if (cnt == idx)
|
||||
gfx_con_setcol(0xFF1B1B1B, 1, 0xFFCCCCCC);
|
||||
else
|
||||
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
|
||||
// if (menu->ents[cnt].type == MENT_CAPTION)
|
||||
// gfx_printf("%k %s", menu->ents[cnt].color, menu->ents[cnt].caption);
|
||||
if (menu->ents[cnt].type != MENT_CHGLINE) {
|
||||
if (cnt == idx)
|
||||
gfx_printf(" %s", menu->ents[cnt].caption);
|
||||
else
|
||||
gfx_printf("%k %s", menu->ents[cnt].color, menu->ents[cnt].caption);//gfx_printf(" %s", menu->ents[cnt].caption);
|
||||
}
|
||||
if(menu->ents[cnt].type == MENT_MENU)
|
||||
gfx_printf("%k...", 0xFF0099EE);
|
||||
gfx_printf(" \n");
|
||||
}
|
||||
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
|
||||
gfx_putc('\n');
|
||||
|
||||
// Print help and battery status.
|
||||
gfx_con_setpos(0, 1127);
|
||||
if (h_cfg.emummc_force_disable)
|
||||
gfx_printf("%kNo emuMMC config found.\n", 0xFF800000);
|
||||
gfx_con_setpos(0, 1191);
|
||||
gfx_printf("%k VOL: Move up/down\n PWR: Select option%k", 0xFF555555, 0xFFCCCCCC);
|
||||
|
||||
display_backlight_brightness(h_cfg.backlight, 1000);
|
||||
|
||||
// Wait for user command.
|
||||
u32 btn = btn_wait();
|
||||
|
||||
if (btn & BTN_VOL_DOWN && idx < (cnt - 1))
|
||||
idx++;
|
||||
else if (btn & BTN_VOL_DOWN && idx == (cnt - 1))
|
||||
{
|
||||
idx = 0;
|
||||
prev_idx = -1;
|
||||
}
|
||||
if (btn & BTN_VOL_UP && idx > 0)
|
||||
idx--;
|
||||
else if (btn & BTN_VOL_UP && idx == 0)
|
||||
{
|
||||
idx = cnt - 1;
|
||||
prev_idx = cnt;
|
||||
}
|
||||
if (btn & BTN_POWER)
|
||||
{
|
||||
ment_t *ent = &menu->ents[idx];
|
||||
switch (ent->type)
|
||||
{
|
||||
case MENT_HANDLER:
|
||||
ent->handler(ent->data);
|
||||
break;
|
||||
case MENT_MENU:
|
||||
return tui_do_menu(ent->menu);
|
||||
break;
|
||||
case MENT_DATA:
|
||||
return ent->data;
|
||||
break;
|
||||
case MENT_BACK:
|
||||
return NULL;
|
||||
break;
|
||||
case MENT_HDLR_RE:
|
||||
ent->handler(ent);
|
||||
if (!ent->data)
|
||||
return NULL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
gfx_con.fntsz = 16;
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
#ifdef MENU_LOGO_ENABLE
|
||||
gfx_set_rect_rgb(Kc_MENU_LOGO,
|
||||
X_MENU_LOGO, Y_MENU_LOGO, X_POS_MENU_LOGO, Y_POS_MENU_LOGO);
|
||||
#endif //MENU_LOGO_ENABLE
|
||||
}
|
||||
tui_sbar(false);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
66
source/gfx/tui.h
Normal file
66
source/gfx/tui.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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 _TUI_H_
|
||||
#define _TUI_H_
|
||||
|
||||
#include "../utils/types.h"
|
||||
#include "gfx.h"
|
||||
|
||||
#define MENT_END 0
|
||||
#define MENT_HANDLER 1
|
||||
#define MENT_MENU 2
|
||||
#define MENT_DATA 3
|
||||
#define MENT_BACK 4
|
||||
#define MENT_CAPTION 5
|
||||
#define MENT_CHGLINE 6
|
||||
#define MENT_HDLR_RE 7
|
||||
|
||||
typedef struct _ment_t
|
||||
{
|
||||
u32 type;
|
||||
const char *caption;
|
||||
u32 color;
|
||||
void *data;
|
||||
union
|
||||
{
|
||||
void(*handler)(void *);
|
||||
struct _menu_t *menu;
|
||||
};
|
||||
} ment_t;
|
||||
|
||||
typedef struct _menu_t
|
||||
{
|
||||
ment_t *ents;
|
||||
const char *caption;
|
||||
u32 x;
|
||||
u32 y;
|
||||
} menu_t;
|
||||
|
||||
#define MDEF_END() {MENT_END}
|
||||
#define MDEF_HANDLER(caption, _handler, color) { MENT_HANDLER, caption, color, NULL, { .handler = _handler } }
|
||||
#define MDEF_HANDLER_EX(caption, data, _handler, color) { MENT_HANDLER, caption, color, data, { .handler = _handler } }
|
||||
#define MDEF_MENU(caption, _menu) { MENT_MENU, caption, 0, NULL, { .menu = _menu } }
|
||||
#define MDEF_BACK() { MENT_BACK, "Back" }
|
||||
#define MDEF_CAPTION(caption, color) { MENT_CAPTION, caption, color }
|
||||
#define MDEF_CHGLINE() {MENT_CHGLINE}
|
||||
|
||||
void tui_sbar(bool force_update);
|
||||
void tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol);
|
||||
void *tui_do_menu(menu_t *menu);
|
||||
|
||||
#endif
|
@ -23,17 +23,19 @@
|
||||
#include "../sec/se.h"
|
||||
|
||||
static const pkg1_id_t _pkg1_ids[] = {
|
||||
{ "20161121183008", 0, 0x1900, 0x3FE0, 0x4002B020 }, //1.0.0
|
||||
{ "20170210155124", 0, 0x1900, 0x3FE0, 0x4002D000 }, //2.0.0 - 2.3.0
|
||||
{ "20170519101410", 1, 0x1A00, 0x3FE0, 0x4002D000 }, //3.0.0
|
||||
{ "20170710161758", 2, 0x1A00, 0x3FE0, 0x4002D000 }, //3.0.1 - 3.0.2
|
||||
{ "20170921172629", 3, 0x1800, 0x3FE0, 0x4002B000 }, //4.0.0 - 4.1.0
|
||||
{ "20180220163747", 4, 0x1900, 0x3FE0, 0x4002B000 }, //5.0.0 - 5.1.0
|
||||
{ "20180802162753", 5, 0x1900, 0x3FE0, 0x4002B000 }, //6.0.0 - 6.1.0
|
||||
{ "20181107105733", 6, 0x0E00, 0x6FE0, 0x4002B000 }, //6.2.0
|
||||
{ "20181218175730", 7, 0x0F00, 0x6FE0, 0x40030000 }, //7.0.0
|
||||
{ "20190208150037", 7, 0x0F00, 0x6FE0, 0x40030000 }, //7.0.1
|
||||
{ "20190314172056", 7, 0x0E00, 0x6FE0, 0x40030000 }, //8.0.0
|
||||
{ "20161121183008", 0 }, //1.0.0
|
||||
{ "20170210155124", 0 }, //2.0.0 - 2.3.0
|
||||
{ "20170519101410", 1 }, //3.0.0
|
||||
{ "20170710161758", 2 }, //3.0.1 - 3.0.2
|
||||
{ "20170921172629", 3 }, //4.0.0 - 4.1.0
|
||||
{ "20180220163747", 4 }, //5.0.0 - 5.1.0
|
||||
{ "20180802162753", 5 }, //6.0.0 - 6.1.0
|
||||
{ "20181107105733", 6 }, //6.2.0
|
||||
{ "20181218175730", 7 }, //7.0.0
|
||||
{ "20190208150037", 7 }, //7.0.1
|
||||
{ "20190314172056", 7 }, //8.0.0
|
||||
{ "20190531152432", 8 }, //8.1.0
|
||||
{ "20190809135709", 9 }, //9.0.0
|
||||
{ NULL } //End.
|
||||
};
|
||||
|
||||
|
@ -23,9 +23,6 @@ typedef struct _pkg1_id_t
|
||||
{
|
||||
const char *id;
|
||||
u32 kb;
|
||||
u32 tsec_off;
|
||||
u32 pkg11_off;
|
||||
u32 secmon_base;
|
||||
} pkg1_id_t;
|
||||
|
||||
const pkg1_id_t *pkg1_identify(u8 *pkg1);
|
||||
|
@ -39,13 +39,28 @@ static u32 _pkg2_calc_kip1_size(pkg2_kip1_t *kip1)
|
||||
return size;
|
||||
}
|
||||
|
||||
void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2)
|
||||
void pkg2_get_newkern_info(u8 *kern_data)
|
||||
{
|
||||
u8 *ptr = pkg2->data;
|
||||
if (pkg2->sec_size[PKG2_SEC_INI1] == 0)
|
||||
ptr += *(u32 *)(ptr + 0x168);
|
||||
u32 info_op = *(u32 *)(kern_data + PKG2_NEWKERN_GET_INI1);
|
||||
pkg2_newkern_ini1_val = ((info_op & 0xFFFF) >> 3) + PKG2_NEWKERN_GET_INI1; // Parse ADR and PC.
|
||||
|
||||
pkg2_newkern_ini1_start = *(u32 *)(kern_data + pkg2_newkern_ini1_val);
|
||||
pkg2_newkern_ini1_end = *(u32 *)(kern_data + pkg2_newkern_ini1_val + 0x8);
|
||||
}
|
||||
|
||||
void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2)
|
||||
{
|
||||
u8 *ptr;
|
||||
// Check for new pkg2 type.
|
||||
if (!pkg2->sec_size[PKG2_SEC_INI1])
|
||||
{
|
||||
pkg2_get_newkern_info(pkg2->data);
|
||||
|
||||
ptr = pkg2->data + pkg2_newkern_ini1_start;
|
||||
*new_pkg2 = true;
|
||||
}
|
||||
else
|
||||
ptr += pkg2->sec_size[PKG2_SEC_KERNEL];
|
||||
ptr = pkg2->data + pkg2->sec_size[PKG2_SEC_KERNEL];
|
||||
|
||||
pkg2_ini1_t *ini1 = (pkg2_ini1_t *)ptr;
|
||||
ptr += sizeof(pkg2_ini1_t);
|
||||
@ -70,19 +85,19 @@ int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp)
|
||||
|
||||
pkg2_kip1_t hdr;
|
||||
memcpy(&hdr, ki->kip1, sizeof(hdr));
|
||||
|
||||
|
||||
unsigned int newKipSize = sizeof(hdr);
|
||||
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".
|
||||
if (sectIdx < 3 && (sectsToDecomp & sectCompBit) && (hdr.flags & sectCompBit))
|
||||
if (sectIdx < 3 && (sectsToDecomp & sectCompBit) && (hdr.flags & sectCompBit))
|
||||
newKipSize += hdr.sections[sectIdx].size_decomp;
|
||||
else
|
||||
newKipSize += hdr.sections[sectIdx].size_comp;
|
||||
}
|
||||
|
||||
pkg2_kip1_t* newKip = malloc(newKipSize);
|
||||
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++)
|
||||
@ -106,7 +121,7 @@ int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp)
|
||||
//gfx_printf("Decomping %s KIP1 sect %d of size %d...\n", (const char*)hdr.name, sectIdx, compSize);
|
||||
if (blz_uncompress_srcdest(srcDataPtr, compSize, dstDataPtr, outputSize) == 0)
|
||||
{
|
||||
gfx_printf("%kERROR decomping sect %d of %s KIP!%k\n", 0xFFFF0000, sectIdx, (char*)hdr.name, 0xFFCCCCCC);
|
||||
gfx_printf("%kERROR decomping sect %d of %s KIP!%k\n", 0xFFFF0000, sectIdx, (char*)hdr.name, 0xFFCCCCCC);
|
||||
free(newKip);
|
||||
|
||||
return 1;
|
||||
@ -134,7 +149,7 @@ int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp)
|
||||
pkg2_hdr_t *pkg2_decrypt(void *data)
|
||||
{
|
||||
u8 *pdata = (u8 *)data;
|
||||
|
||||
|
||||
// Skip signature.
|
||||
pdata += 0x100;
|
||||
|
||||
|
@ -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,
|
||||
@ -26,6 +26,12 @@
|
||||
#define PKG2_SEC_KERNEL 0
|
||||
#define PKG2_SEC_INI1 1
|
||||
|
||||
#define PKG2_NEWKERN_GET_INI1 0x44
|
||||
|
||||
u32 pkg2_newkern_ini1_val;
|
||||
u32 pkg2_newkern_ini1_start;
|
||||
u32 pkg2_newkern_ini1_end;
|
||||
|
||||
typedef struct _pkg2_hdr_t
|
||||
{
|
||||
u8 ctr[0x10];
|
||||
@ -81,7 +87,7 @@ typedef struct _pkg2_kip1_info_t
|
||||
link_t link;
|
||||
} pkg2_kip1_info_t;
|
||||
|
||||
void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2);
|
||||
void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2);
|
||||
int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp);
|
||||
pkg2_hdr_t *pkg2_decrypt(void *data);
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "../gfx/di.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../soc/hw_init.h"
|
||||
#include "../soc/pmc.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../storage/nx_emmc.h"
|
||||
@ -38,7 +39,7 @@ 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
|
||||
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
|
||||
@ -59,15 +60,15 @@ extern boot_cfg_t b_cfg;
|
||||
extern void sd_unmount();
|
||||
extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size);
|
||||
|
||||
int reboot_to_sept(const u8 *tsec_fw)
|
||||
int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb)
|
||||
{
|
||||
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;
|
||||
|
||||
memcpy((void *)SEPT_PK1T_ADDR, tsec_fw, tsec_size);
|
||||
*(vu32 *)SEPT_TCSZ_ADDR = tsec_size;
|
||||
|
||||
// Copy sept-primary.
|
||||
if (f_open(&fp, "sd:/sept/sept-primary.bin", FA_READ))
|
||||
goto error;
|
||||
@ -80,8 +81,17 @@ int reboot_to_sept(const u8 *tsec_fw)
|
||||
f_close(&fp);
|
||||
|
||||
// Copy sept-secondary.
|
||||
if (f_open(&fp, "sd:/sept/sept-secondary.enc", FA_READ))
|
||||
goto error;
|
||||
if (kb < KB_FIRMWARE_VERSION_810)
|
||||
{
|
||||
if (f_open(&fp, "sd:/sept/sept-secondary_00.enc", FA_READ))
|
||||
if (f_open(&fp, "sd:/sept/sept-secondary.enc", FA_READ)) // Try the deprecated version.
|
||||
goto error;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (f_open(&fp, "sd:/sept/sept-secondary_01.enc", FA_READ))
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (f_read(&fp, (u8 *)SEPT_STG2_ADDR, f_size(&fp), NULL))
|
||||
{
|
||||
@ -90,7 +100,7 @@ int reboot_to_sept(const u8 *tsec_fw)
|
||||
}
|
||||
f_close(&fp);
|
||||
|
||||
// Save auto boot config to payload, if any.
|
||||
// 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));
|
||||
|
||||
@ -121,14 +131,12 @@ int reboot_to_sept(const u8 *tsec_fw)
|
||||
PMC(APBDEV_PMC_SCRATCH33) = SEPT_PRI_ADDR;
|
||||
PMC(APBDEV_PMC_SCRATCH40) = 0x6000F208;
|
||||
|
||||
display_end();
|
||||
reconfig_hw_workaround(false, 0);
|
||||
|
||||
(*sept)();
|
||||
|
||||
return 1;
|
||||
|
||||
error:
|
||||
EPRINTF("Sept payloads not found in sd:/sept!\nPlace appropriate files and try again.");
|
||||
EPRINTF("\nSept files not found in sd:/sept!\nPlace appropriate files and try again.");
|
||||
display_backlight_brightness(100, 1000);
|
||||
|
||||
btn_wait();
|
||||
|
@ -19,6 +19,6 @@
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
int reboot_to_sept(const u8 *tsec_fw);
|
||||
int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb);
|
||||
|
||||
#endif
|
||||
|
165
source/keys/key_sources.inl
Normal file
165
source/keys/key_sources.inl
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (c) 2019 shchmue
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
static const u8 zeros[0x10] = {0};
|
||||
|
||||
static const u8 keyblob_key_source[][0x10] = {
|
||||
{0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3}, //1.0.0
|
||||
{0x0C, 0x25, 0x61, 0x5D, 0x68, 0x4C, 0xEB, 0x42, 0x1C, 0x23, 0x79, 0xEA, 0x82, 0x25, 0x12, 0xAC}, //3.0.0
|
||||
{0x33, 0x76, 0x85, 0xEE, 0x88, 0x4A, 0xAE, 0x0A, 0xC2, 0x8A, 0xFD, 0x7D, 0x63, 0xC0, 0x43, 0x3B}, //3.0.1
|
||||
{0x2D, 0x1F, 0x48, 0x80, 0xED, 0xEC, 0xED, 0x3E, 0x3C, 0xF2, 0x48, 0xB5, 0x65, 0x7D, 0xF7, 0xBE}, //4.0.0
|
||||
{0xBB, 0x5A, 0x01, 0xF9, 0x88, 0xAF, 0xF5, 0xFC, 0x6C, 0xFF, 0x07, 0x9E, 0x13, 0x3C, 0x39, 0x80}, //5.0.0
|
||||
{0xD8, 0xCC, 0xE1, 0x26, 0x6A, 0x35, 0x3F, 0xCC, 0x20, 0xF3, 0x2D, 0x3B, 0x51, 0x7D, 0xE9, 0xC0} //6.0.0
|
||||
};
|
||||
|
||||
static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600][0x10] = {
|
||||
{0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A}, //6.2.0
|
||||
{0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, //7.0.0
|
||||
{0xDE, 0xDC, 0xE3, 0x39, 0x30, 0x88, 0x16, 0xF8, 0xAE, 0x97, 0xAD, 0xEC, 0x64, 0x2D, 0x41, 0x41}, //8.1.0
|
||||
{0x1A, 0xEC, 0x11, 0x82, 0x2B, 0x32, 0x38, 0x7A, 0x2B, 0xED, 0xBA, 0x01, 0x47, 0x7E, 0x3B, 0x67}, //9.0.0
|
||||
};
|
||||
|
||||
static const u8 mkey_vectors[KB_FIRMWARE_VERSION_MAX+1][0x10] =
|
||||
{
|
||||
{0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D}, /* Zeroes encrypted with Master Key 00. */
|
||||
{0x29, 0x4C, 0x04, 0xC8, 0xEB, 0x10, 0xED, 0x9D, 0x51, 0x64, 0x97, 0xFB, 0xF3, 0x4D, 0x50, 0xDD}, /* Master key 00 encrypted with Master key 01. */
|
||||
{0xDE, 0xCF, 0xEB, 0xEB, 0x10, 0xAE, 0x74, 0xD8, 0xAD, 0x7C, 0xF4, 0x9E, 0x62, 0xE0, 0xE8, 0x72}, /* Master key 01 encrypted with Master key 02. */
|
||||
{0x0A, 0x0D, 0xDF, 0x34, 0x22, 0x06, 0x6C, 0xA4, 0xE6, 0xB1, 0xEC, 0x71, 0x85, 0xCA, 0x4E, 0x07}, /* Master key 02 encrypted with Master key 03. */
|
||||
{0x6E, 0x7D, 0x2D, 0xC3, 0x0F, 0x59, 0xC8, 0xFA, 0x87, 0xA8, 0x2E, 0xD5, 0x89, 0x5E, 0xF3, 0xE9}, /* Master key 03 encrypted with Master key 04. */
|
||||
{0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE}, /* Master key 04 encrypted with Master key 05. */
|
||||
{0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57}, /* Master key 05 encrypted with Master key 06. */
|
||||
{0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F}, /* Master key 06 encrypted with Master key 07. */
|
||||
{0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29}, /* Master key 07 encrypted with Master key 08. */
|
||||
{0x4D, 0xD9, 0x98, 0x42, 0x45, 0x0D, 0xB1, 0x3C, 0x52, 0x0C, 0x9A, 0x44, 0xBB, 0xAD, 0xAF, 0x80}, /* Master key 08 encrypted with Master key 09. */
|
||||
};
|
||||
|
||||
//======================================Keys======================================//
|
||||
// from Package1 -> Secure_Monitor
|
||||
static const u8 aes_kek_generation_source[0x10] = {
|
||||
0x4D, 0x87, 0x09, 0x86, 0xC4, 0x5D, 0x20, 0x72, 0x2F, 0xBA, 0x10, 0x53, 0xDA, 0x92, 0xE8, 0xA9};
|
||||
static const u8 aes_kek_seed_01[0x10] = {
|
||||
0xA2, 0xAB, 0xBF, 0x9C, 0x92, 0x2F, 0xBB, 0xE3, 0x78, 0x79, 0x9B, 0xC0, 0xCC, 0xEA, 0xA5, 0x74};
|
||||
static const u8 aes_kek_seed_03[0x10] = {
|
||||
0xE5, 0x4D, 0x9A, 0x02, 0xF0, 0x4F, 0x5F, 0xA8, 0xAD, 0x76, 0x0A, 0xF6, 0x32, 0x95, 0x59, 0xBB};
|
||||
static const u8 package2_key_source[0x10] = {
|
||||
0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7};
|
||||
static const u8 titlekek_source[0x10] = {
|
||||
0x1E, 0xDC, 0x7B, 0x3B, 0x60, 0xE6, 0xB4, 0xD8, 0x78, 0xB8, 0x17, 0x15, 0x98, 0x5E, 0x62, 0x9B};
|
||||
static const u8 retail_specific_aes_key_source[0x10] = {
|
||||
0xE2, 0xD6, 0xB8, 0x7A, 0x11, 0x9C, 0xB8, 0x80, 0xE8, 0x22, 0x88, 0x8A, 0x46, 0xFB, 0xA1, 0x95};
|
||||
|
||||
// from Package1ldr (or Secure_Monitor on 6.2.0)
|
||||
static const u8 keyblob_mac_key_source[0x10] = {
|
||||
0x59, 0xC7, 0xFB, 0x6F, 0xBE, 0x9B, 0xBE, 0x87, 0x65, 0x6B, 0x15, 0xC0, 0x53, 0x73, 0x36, 0xA5};
|
||||
static const u8 master_key_source[0x10] = {
|
||||
0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C};
|
||||
static const u8 per_console_key_source[0x10] = {
|
||||
0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78};
|
||||
static const u8 per_console_key_source_4x[0x10] = {
|
||||
0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28};
|
||||
|
||||
static const u8 new_device_key_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] = {
|
||||
{0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}, /* 4.x New Device Key Source. */
|
||||
{0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C}, /* 5.x New Device Key Source. */
|
||||
{0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4}, /* 6.x New Device Key Source. */
|
||||
{0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17}, /* 6.2.0 New Device Key Source. */
|
||||
{0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, /* 7.0.0 New Device Key Source. */
|
||||
{0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE}, /* 8.1.0 New Device Key Source. */
|
||||
{0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49}, /* 9.0.0 New Device Key Source. */
|
||||
};
|
||||
|
||||
static const u8 new_device_keygen_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] = {
|
||||
{0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D}, /* 4.x New Device Keygen Source. */
|
||||
{0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E}, /* 5.x New Device Keygen Source. */
|
||||
{0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF}, /* 6.x New Device Keygen Source. */
|
||||
{0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB}, /* 6.2.0 New Device Keygen Source. */
|
||||
{0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 New Device Keygen Source. */
|
||||
{0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D}, /* 8.1.0 New Device Keygen Source. */
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 9.0.0 New Device Keygen Source to be added on next change-of-keys. */
|
||||
};
|
||||
|
||||
// from SPL
|
||||
static const u8 aes_key_generation_source[0x10] = {
|
||||
0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8};
|
||||
|
||||
// from FS
|
||||
static const u8 bis_kek_source[0x10] = {
|
||||
0x34, 0xC1, 0xA0, 0xC4, 0x82, 0x58, 0xF8, 0xB4, 0xFA, 0x9E, 0x5E, 0x6A, 0xDA, 0xFC, 0x7E, 0x4F};
|
||||
static const u8 bis_key_source[3][0x20] = {
|
||||
{
|
||||
0xF8, 0x3F, 0x38, 0x6E, 0x2C, 0xD2, 0xCA, 0x32, 0xA8, 0x9A, 0xB9, 0xAA, 0x29, 0xBF, 0xC7, 0x48,
|
||||
0x7D, 0x92, 0xB0, 0x3A, 0xA8, 0xBF, 0xDE, 0xE1, 0xA7, 0x4C, 0x3B, 0x6E, 0x35, 0xCB, 0x71, 0x06},
|
||||
{
|
||||
0x41, 0x00, 0x30, 0x49, 0xDD, 0xCC, 0xC0, 0x65, 0x64, 0x7A, 0x7E, 0xB4, 0x1E, 0xED, 0x9C, 0x5F,
|
||||
0x44, 0x42, 0x4E, 0xDA, 0xB4, 0x9D, 0xFC, 0xD9, 0x87, 0x77, 0x24, 0x9A, 0xDC, 0x9F, 0x7C, 0xA4},
|
||||
{
|
||||
0x52, 0xC2, 0xE9, 0xEB, 0x09, 0xE3, 0xEE, 0x29, 0x32, 0xA1, 0x0C, 0x1F, 0xB6, 0xA0, 0x92, 0x6C,
|
||||
0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4}
|
||||
};
|
||||
|
||||
static const u8 fs_hashes_sha256[10][0x20] = {
|
||||
{ // header_kek_source
|
||||
0x18, 0x88, 0xca, 0xed, 0x55, 0x51, 0xb3, 0xed, 0xe0, 0x14, 0x99, 0xe8, 0x7c, 0xe0, 0xd8, 0x68,
|
||||
0x27, 0xf8, 0x08, 0x20, 0xef, 0xb2, 0x75, 0x92, 0x10, 0x55, 0xaa, 0x4e, 0x2a, 0xbd, 0xff, 0xc2},
|
||||
{ // header_key_source
|
||||
0x8f, 0x78, 0x3e, 0x46, 0x85, 0x2d, 0xf6, 0xbe, 0x0b, 0xa4, 0xe1, 0x92, 0x73, 0xc4, 0xad, 0xba,
|
||||
0xee, 0x16, 0x38, 0x00, 0x43, 0xe1, 0xb8, 0xc4, 0x18, 0xc4, 0x08, 0x9a, 0x8b, 0xd6, 0x4a, 0xa6},
|
||||
{ // key_area_key_application_source
|
||||
0x04, 0xad, 0x66, 0x14, 0x3c, 0x72, 0x6b, 0x2a, 0x13, 0x9f, 0xb6, 0xb2, 0x11, 0x28, 0xb4, 0x6f,
|
||||
0x56, 0xc5, 0x53, 0xb2, 0xb3, 0x88, 0x71, 0x10, 0x30, 0x42, 0x98, 0xd8, 0xd0, 0x09, 0x2d, 0x9e},
|
||||
{ // key_area_key_ocean_source
|
||||
0xfd, 0x43, 0x40, 0x00, 0xc8, 0xff, 0x2b, 0x26, 0xf8, 0xe9, 0xa9, 0xd2, 0xd2, 0xc1, 0x2f, 0x6b,
|
||||
0xe5, 0x77, 0x3c, 0xbb, 0x9d, 0xc8, 0x63, 0x00, 0xe1, 0xbd, 0x99, 0xf8, 0xea, 0x33, 0xa4, 0x17},
|
||||
{ // key_area_key_system_source
|
||||
0x1f, 0x17, 0xb1, 0xfd, 0x51, 0xad, 0x1c, 0x23, 0x79, 0xb5, 0x8f, 0x15, 0x2c, 0xa4, 0x91, 0x2e,
|
||||
0xc2, 0x10, 0x64, 0x41, 0xe5, 0x17, 0x22, 0xf3, 0x87, 0x00, 0xd5, 0x93, 0x7a, 0x11, 0x62, 0xf7},
|
||||
{ // save_mac_kek_source
|
||||
0x3D, 0xCB, 0xA1, 0x00, 0xAD, 0x4D, 0xF1, 0x54, 0x7F, 0xE3, 0xC4, 0x79, 0x5C, 0x4B, 0x22, 0x8A,
|
||||
0xA9, 0x80, 0x38, 0xF0, 0x7A, 0x36, 0xF1, 0xBC, 0x14, 0x8E, 0xEA, 0xF3, 0xDC, 0xD7, 0x50, 0xF4},
|
||||
{ // save_mac_key_source
|
||||
0xB4, 0x7B, 0x60, 0x0B, 0x1A, 0xD3, 0x14, 0xF9, 0x41, 0x14, 0x7D, 0x8B, 0x39, 0x1D, 0x4B, 0x19,
|
||||
0x87, 0xCC, 0x8C, 0x88, 0x4A, 0xC8, 0x9F, 0xFC, 0x91, 0xCA, 0xE2, 0x21, 0xC5, 0x24, 0x51, 0xF7},
|
||||
{ // sd_card_kek_source
|
||||
0x6B, 0x2E, 0xD8, 0x77, 0xC2, 0xC5, 0x23, 0x34, 0xAC, 0x51, 0xE5, 0x9A, 0xBF, 0xA7, 0xEC, 0x45,
|
||||
0x7F, 0x4A, 0x7D, 0x01, 0xE4, 0x62, 0x91, 0xE9, 0xF2, 0xEA, 0xA4, 0x5F, 0x01, 0x1D, 0x24, 0xB7},
|
||||
{ // sd_card_nca_key_source
|
||||
0x2E, 0x75, 0x1C, 0xEC, 0xF7, 0xD9, 0x3A, 0x2B, 0x95, 0x7B, 0xD5, 0xFF, 0xCB, 0x08, 0x2F, 0xD0,
|
||||
0x38, 0xCC, 0x28, 0x53, 0x21, 0x9D, 0xD3, 0x09, 0x2C, 0x6D, 0xAB, 0x98, 0x38, 0xF5, 0xA7, 0xCC},
|
||||
{ // sd_card_save_key_source
|
||||
0xD4, 0x82, 0x74, 0x35, 0x63, 0xD3, 0xEA, 0x5D, 0xCD, 0xC3, 0xB7, 0x4E, 0x97, 0xC9, 0xAC, 0x8A,
|
||||
0x34, 0x21, 0x64, 0xFA, 0x04, 0x1A, 0x1D, 0xC8, 0x0F, 0x17, 0xF6, 0xD3, 0x1E, 0x4B, 0xC0, 0x1C}
|
||||
};
|
||||
|
||||
static const u8 es_hashes_sha256[3][0x20] = {
|
||||
{ // eticket_rsa_kek
|
||||
0xB7, 0x1D, 0xB2, 0x71, 0xDC, 0x33, 0x8D, 0xF3, 0x80, 0xAA, 0x2C, 0x43, 0x35, 0xEF, 0x88, 0x73,
|
||||
0xB1, 0xAF, 0xD4, 0x08, 0xE8, 0x0B, 0x35, 0x82, 0xD8, 0x71, 0x9F, 0xC8, 0x1C, 0x5E, 0x51, 0x1C},
|
||||
{ // eticket_rsa_kekek
|
||||
0xE8, 0x96, 0x5A, 0x18, 0x7D, 0x30, 0xE5, 0x78, 0x69, 0xF5, 0x62, 0xD0, 0x43, 0x83, 0xC9, 0x96,
|
||||
0xDE, 0x48, 0x7B, 0xBA, 0x57, 0x61, 0x36, 0x3D, 0x2D, 0x4D, 0x32, 0x39, 0x18, 0x66, 0xA8, 0x5C},
|
||||
{ // ssl_rsa_kek_source_x
|
||||
0x69, 0xA0, 0x8E, 0x62, 0xE0, 0xAE, 0x50, 0x7B, 0xB5, 0xDA, 0x0E, 0x65, 0x17, 0x9A, 0xE3, 0xBE,
|
||||
0x05, 0x1F, 0xED, 0x3C, 0x49, 0x94, 0x1D, 0xF4, 0xEF, 0x29, 0x56, 0xD3, 0x6D, 0x30, 0x11, 0x0C}
|
||||
};
|
||||
|
||||
static const u8 ssl_hashes_sha256[2][0x20] = {
|
||||
{ // ssl_rsa_kek_source_x
|
||||
0x69, 0xA0, 0x8E, 0x62, 0xE0, 0xAE, 0x50, 0x7B, 0xB5, 0xDA, 0x0E, 0x65, 0x17, 0x9A, 0xE3, 0xBE,
|
||||
0x05, 0x1F, 0xED, 0x3C, 0x49, 0x94, 0x1D, 0xF4, 0xEF, 0x29, 0x56, 0xD3, 0x6D, 0x30, 0x11, 0x0C},
|
||||
{ // ssl_rsa_kek_source_y
|
||||
0x1C, 0x86, 0xF3, 0x63, 0x26, 0x54, 0x17, 0xD4, 0x99, 0x22, 0x9E, 0xB1, 0xC4, 0xAD, 0xC7, 0x47,
|
||||
0x9B, 0x2A, 0x15, 0xF9, 0x31, 0x26, 0x1F, 0x31, 0xEE, 0x67, 0x76, 0xAE, 0xB4, 0xC7, 0x65, 0x42}
|
||||
};
|
@ -15,13 +15,17 @@
|
||||
*/
|
||||
|
||||
#include "keys.h"
|
||||
|
||||
#include "../config/config.h"
|
||||
#include "../gfx/di.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../gfx/tui.h"
|
||||
#include "../hos/pkg1.h"
|
||||
#include "../hos/pkg2.h"
|
||||
#include "../hos/sept.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../mem/mc.h"
|
||||
#include "../mem/sdram.h"
|
||||
#include "../sec/se.h"
|
||||
#include "../sec/se_t210.h"
|
||||
@ -29,163 +33,44 @@
|
||||
#include "../soc/fuse.h"
|
||||
#include "../soc/smmu.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../storage/emummc.h"
|
||||
#include "../storage/nx_emmc.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
#include "../utils/btn.h"
|
||||
#include "../utils/list.h"
|
||||
#include "../utils/sprintf.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
#include "key_sources.inl"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
extern bool sd_mount();
|
||||
extern void sd_unmount();
|
||||
extern void *sd_file_read(char *path);
|
||||
extern int sd_save_to_file(void *buf, u32 size, const char *filename);
|
||||
extern void power_off();
|
||||
extern void reboot_normal();
|
||||
extern void reboot_rcm();
|
||||
|
||||
extern hekate_config h_cfg;
|
||||
|
||||
u32 _key_count = 0;
|
||||
sdmmc_storage_t storage;
|
||||
emmc_part_t *system_part;
|
||||
u32 start_time, end_time;
|
||||
|
||||
#define TPRINTF(text) \
|
||||
end_time = get_tmr_ms(); \
|
||||
gfx_printf(text" done @ %d.%03ds\n", (end_time - start_time) / 1000, (end_time - start_time) % 1000)
|
||||
end_time = get_tmr_us(); \
|
||||
gfx_printf(text" done in %d us\n", end_time - start_time); \
|
||||
start_time = get_tmr_us()
|
||||
#define TPRINTFARGS(text, args...) \
|
||||
end_time = get_tmr_ms(); \
|
||||
gfx_printf(text" done @ %d.%03ds\n", args, (end_time - start_time) / 1000, (end_time - start_time) % 1000)
|
||||
#define SAVE_KEY(name, src, len) _save_key(name, src, len, text_buffer, &buf_index)
|
||||
#define SAVE_KEY_FAMILY(name, src, count, len) _save_key_family(name, src, count, len, text_buffer, &buf_index)
|
||||
|
||||
static const u8 zeros[0x10] = {0};
|
||||
|
||||
static const u8 keyblob_key_source[][0x10] = {
|
||||
{0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3}, //1.0.0
|
||||
{0x0C, 0x25, 0x61, 0x5D, 0x68, 0x4C, 0xEB, 0x42, 0x1C, 0x23, 0x79, 0xEA, 0x82, 0x25, 0x12, 0xAC}, //3.0.0
|
||||
{0x33, 0x76, 0x85, 0xEE, 0x88, 0x4A, 0xAE, 0x0A, 0xC2, 0x8A, 0xFD, 0x7D, 0x63, 0xC0, 0x43, 0x3B}, //3.0.1
|
||||
{0x2D, 0x1F, 0x48, 0x80, 0xED, 0xEC, 0xED, 0x3E, 0x3C, 0xF2, 0x48, 0xB5, 0x65, 0x7D, 0xF7, 0xBE}, //4.0.0
|
||||
{0xBB, 0x5A, 0x01, 0xF9, 0x88, 0xAF, 0xF5, 0xFC, 0x6C, 0xFF, 0x07, 0x9E, 0x13, 0x3C, 0x39, 0x80}, //5.0.0
|
||||
{0xD8, 0xCC, 0xE1, 0x26, 0x6A, 0x35, 0x3F, 0xCC, 0x20, 0xF3, 0x2D, 0x3B, 0x51, 0x7D, 0xE9, 0xC0} //6.0.0
|
||||
};
|
||||
|
||||
static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600][0x10] = {
|
||||
{0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A},
|
||||
{0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}
|
||||
};
|
||||
|
||||
static const u8 mkey_vectors[KB_FIRMWARE_VERSION_MAX+1][0x10] =
|
||||
{
|
||||
{0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D}, /* Zeroes encrypted with Master Key 00. */
|
||||
{0x29, 0x4C, 0x04, 0xC8, 0xEB, 0x10, 0xED, 0x9D, 0x51, 0x64, 0x97, 0xFB, 0xF3, 0x4D, 0x50, 0xDD}, /* Master key 00 encrypted with Master key 01. */
|
||||
{0xDE, 0xCF, 0xEB, 0xEB, 0x10, 0xAE, 0x74, 0xD8, 0xAD, 0x7C, 0xF4, 0x9E, 0x62, 0xE0, 0xE8, 0x72}, /* Master key 01 encrypted with Master key 02. */
|
||||
{0x0A, 0x0D, 0xDF, 0x34, 0x22, 0x06, 0x6C, 0xA4, 0xE6, 0xB1, 0xEC, 0x71, 0x85, 0xCA, 0x4E, 0x07}, /* Master key 02 encrypted with Master key 03. */
|
||||
{0x6E, 0x7D, 0x2D, 0xC3, 0x0F, 0x59, 0xC8, 0xFA, 0x87, 0xA8, 0x2E, 0xD5, 0x89, 0x5E, 0xF3, 0xE9}, /* Master key 03 encrypted with Master key 04. */
|
||||
{0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE}, /* Master key 04 encrypted with Master key 05. */
|
||||
{0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57}, /* Master key 05 encrypted with Master key 06. */
|
||||
{0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F}, /* Master key 06 encrypted with Master key 07. */
|
||||
};
|
||||
|
||||
//======================================Keys======================================//
|
||||
// from Package1 -> Secure_Monitor
|
||||
static const u8 aes_kek_generation_source[0x10] = {
|
||||
0x4D, 0x87, 0x09, 0x86, 0xC4, 0x5D, 0x20, 0x72, 0x2F, 0xBA, 0x10, 0x53, 0xDA, 0x92, 0xE8, 0xA9};
|
||||
static const u8 aes_kek_seed_01[0x10] = {
|
||||
0xA2, 0xAB, 0xBF, 0x9C, 0x92, 0x2F, 0xBB, 0xE3, 0x78, 0x79, 0x9B, 0xC0, 0xCC, 0xEA, 0xA5, 0x74};
|
||||
static const u8 aes_kek_seed_03[0x10] = {
|
||||
0xE5, 0x4D, 0x9A, 0x02, 0xF0, 0x4F, 0x5F, 0xA8, 0xAD, 0x76, 0x0A, 0xF6, 0x32, 0x95, 0x59, 0xBB};
|
||||
static const u8 package2_key_source[0x10] = {
|
||||
0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7};
|
||||
static const u8 titlekek_source[0x10] = {
|
||||
0x1E, 0xDC, 0x7B, 0x3B, 0x60, 0xE6, 0xB4, 0xD8, 0x78, 0xB8, 0x17, 0x15, 0x98, 0x5E, 0x62, 0x9B};
|
||||
static const u8 retail_specific_aes_key_source[0x10] = {
|
||||
0xE2, 0xD6, 0xB8, 0x7A, 0x11, 0x9C, 0xB8, 0x80, 0xE8, 0x22, 0x88, 0x8A, 0x46, 0xFB, 0xA1, 0x95};
|
||||
|
||||
// from Package1ldr (or Secure_Monitor on 6.2.0)
|
||||
static const u8 keyblob_mac_key_source[0x10] = {
|
||||
0x59, 0xC7, 0xFB, 0x6F, 0xBE, 0x9B, 0xBE, 0x87, 0x65, 0x6B, 0x15, 0xC0, 0x53, 0x73, 0x36, 0xA5};
|
||||
static const u8 master_key_source[0x10] = {
|
||||
0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C};
|
||||
static const u8 per_console_key_source[0x10] = {
|
||||
0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78};
|
||||
|
||||
// from SPL
|
||||
static const u8 aes_key_generation_source[0x10] = {
|
||||
0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8};
|
||||
|
||||
// from FS
|
||||
static const u8 bis_kek_source[0x10] = {
|
||||
0x34, 0xC1, 0xA0, 0xC4, 0x82, 0x58, 0xF8, 0xB4, 0xFA, 0x9E, 0x5E, 0x6A, 0xDA, 0xFC, 0x7E, 0x4F};
|
||||
static const u8 bis_key_source[3][0x20] = {
|
||||
{
|
||||
0xF8, 0x3F, 0x38, 0x6E, 0x2C, 0xD2, 0xCA, 0x32, 0xA8, 0x9A, 0xB9, 0xAA, 0x29, 0xBF, 0xC7, 0x48,
|
||||
0x7D, 0x92, 0xB0, 0x3A, 0xA8, 0xBF, 0xDE, 0xE1, 0xA7, 0x4C, 0x3B, 0x6E, 0x35, 0xCB, 0x71, 0x06},
|
||||
{
|
||||
0x41, 0x00, 0x30, 0x49, 0xDD, 0xCC, 0xC0, 0x65, 0x64, 0x7A, 0x7E, 0xB4, 0x1E, 0xED, 0x9C, 0x5F,
|
||||
0x44, 0x42, 0x4E, 0xDA, 0xB4, 0x9D, 0xFC, 0xD9, 0x87, 0x77, 0x24, 0x9A, 0xDC, 0x9F, 0x7C, 0xA4},
|
||||
{
|
||||
0x52, 0xC2, 0xE9, 0xEB, 0x09, 0xE3, 0xEE, 0x29, 0x32, 0xA1, 0x0C, 0x1F, 0xB6, 0xA0, 0x92, 0x6C,
|
||||
0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4}
|
||||
};
|
||||
|
||||
static const u8 fs_hashes_sha256[10][0x20] = {
|
||||
{ // header_kek_source
|
||||
0x18, 0x88, 0xca, 0xed, 0x55, 0x51, 0xb3, 0xed, 0xe0, 0x14, 0x99, 0xe8, 0x7c, 0xe0, 0xd8, 0x68,
|
||||
0x27, 0xf8, 0x08, 0x20, 0xef, 0xb2, 0x75, 0x92, 0x10, 0x55, 0xaa, 0x4e, 0x2a, 0xbd, 0xff, 0xc2},
|
||||
{ // header_key_source
|
||||
0x8f, 0x78, 0x3e, 0x46, 0x85, 0x2d, 0xf6, 0xbe, 0x0b, 0xa4, 0xe1, 0x92, 0x73, 0xc4, 0xad, 0xba,
|
||||
0xee, 0x16, 0x38, 0x00, 0x43, 0xe1, 0xb8, 0xc4, 0x18, 0xc4, 0x08, 0x9a, 0x8b, 0xd6, 0x4a, 0xa6},
|
||||
{ // key_area_key_application_source
|
||||
0x04, 0xad, 0x66, 0x14, 0x3c, 0x72, 0x6b, 0x2a, 0x13, 0x9f, 0xb6, 0xb2, 0x11, 0x28, 0xb4, 0x6f,
|
||||
0x56, 0xc5, 0x53, 0xb2, 0xb3, 0x88, 0x71, 0x10, 0x30, 0x42, 0x98, 0xd8, 0xd0, 0x09, 0x2d, 0x9e},
|
||||
{ // key_area_key_ocean_source
|
||||
0xfd, 0x43, 0x40, 0x00, 0xc8, 0xff, 0x2b, 0x26, 0xf8, 0xe9, 0xa9, 0xd2, 0xd2, 0xc1, 0x2f, 0x6b,
|
||||
0xe5, 0x77, 0x3c, 0xbb, 0x9d, 0xc8, 0x63, 0x00, 0xe1, 0xbd, 0x99, 0xf8, 0xea, 0x33, 0xa4, 0x17},
|
||||
{ // key_area_key_system_source
|
||||
0x1f, 0x17, 0xb1, 0xfd, 0x51, 0xad, 0x1c, 0x23, 0x79, 0xb5, 0x8f, 0x15, 0x2c, 0xa4, 0x91, 0x2e,
|
||||
0xc2, 0x10, 0x64, 0x41, 0xe5, 0x17, 0x22, 0xf3, 0x87, 0x00, 0xd5, 0x93, 0x7a, 0x11, 0x62, 0xf7},
|
||||
{ // save_mac_kek_source
|
||||
0x3D, 0xCB, 0xA1, 0x00, 0xAD, 0x4D, 0xF1, 0x54, 0x7F, 0xE3, 0xC4, 0x79, 0x5C, 0x4B, 0x22, 0x8A,
|
||||
0xA9, 0x80, 0x38, 0xF0, 0x7A, 0x36, 0xF1, 0xBC, 0x14, 0x8E, 0xEA, 0xF3, 0xDC, 0xD7, 0x50, 0xF4},
|
||||
{ // save_mac_key_source
|
||||
0xB4, 0x7B, 0x60, 0x0B, 0x1A, 0xD3, 0x14, 0xF9, 0x41, 0x14, 0x7D, 0x8B, 0x39, 0x1D, 0x4B, 0x19,
|
||||
0x87, 0xCC, 0x8C, 0x88, 0x4A, 0xC8, 0x9F, 0xFC, 0x91, 0xCA, 0xE2, 0x21, 0xC5, 0x24, 0x51, 0xF7},
|
||||
{ // sd_card_kek_source
|
||||
0x6B, 0x2E, 0xD8, 0x77, 0xC2, 0xC5, 0x23, 0x34, 0xAC, 0x51, 0xE5, 0x9A, 0xBF, 0xA7, 0xEC, 0x45,
|
||||
0x7F, 0x4A, 0x7D, 0x01, 0xE4, 0x62, 0x91, 0xE9, 0xF2, 0xEA, 0xA4, 0x5F, 0x01, 0x1D, 0x24, 0xB7},
|
||||
{ // sd_card_nca_key_source
|
||||
0x2E, 0x75, 0x1C, 0xEC, 0xF7, 0xD9, 0x3A, 0x2B, 0x95, 0x7B, 0xD5, 0xFF, 0xCB, 0x08, 0x2F, 0xD0,
|
||||
0x38, 0xCC, 0x28, 0x53, 0x21, 0x9D, 0xD3, 0x09, 0x2C, 0x6D, 0xAB, 0x98, 0x38, 0xF5, 0xA7, 0xCC},
|
||||
{ // sd_card_save_key_source
|
||||
0xD4, 0x82, 0x74, 0x35, 0x63, 0xD3, 0xEA, 0x5D, 0xCD, 0xC3, 0xB7, 0x4E, 0x97, 0xC9, 0xAC, 0x8A,
|
||||
0x34, 0x21, 0x64, 0xFA, 0x04, 0x1A, 0x1D, 0xC8, 0x0F, 0x17, 0xF6, 0xD3, 0x1E, 0x4B, 0xC0, 0x1C}
|
||||
};
|
||||
|
||||
static const u8 es_hashes_sha256[3][0x20] = {
|
||||
{ // eticket_rsa_kek
|
||||
0xB7, 0x1D, 0xB2, 0x71, 0xDC, 0x33, 0x8D, 0xF3, 0x80, 0xAA, 0x2C, 0x43, 0x35, 0xEF, 0x88, 0x73,
|
||||
0xB1, 0xAF, 0xD4, 0x08, 0xE8, 0x0B, 0x35, 0x82, 0xD8, 0x71, 0x9F, 0xC8, 0x1C, 0x5E, 0x51, 0x1C},
|
||||
{ // eticket_rsa_kekek
|
||||
0xE8, 0x96, 0x5A, 0x18, 0x7D, 0x30, 0xE5, 0x78, 0x69, 0xF5, 0x62, 0xD0, 0x43, 0x83, 0xC9, 0x96,
|
||||
0xDE, 0x48, 0x7B, 0xBA, 0x57, 0x61, 0x36, 0x3D, 0x2D, 0x4D, 0x32, 0x39, 0x18, 0x66, 0xA8, 0x5C},
|
||||
{ // ssl_rsa_kek_source_x
|
||||
0x69, 0xA0, 0x8E, 0x62, 0xE0, 0xAE, 0x50, 0x7B, 0xB5, 0xDA, 0x0E, 0x65, 0x17, 0x9A, 0xE3, 0xBE,
|
||||
0x05, 0x1F, 0xED, 0x3C, 0x49, 0x94, 0x1D, 0xF4, 0xEF, 0x29, 0x56, 0xD3, 0x6D, 0x30, 0x11, 0x0C}
|
||||
};
|
||||
|
||||
static const u8 ssl_hashes_sha256[2][0x20] = {
|
||||
{ // ssl_rsa_kek_source_x
|
||||
0x69, 0xA0, 0x8E, 0x62, 0xE0, 0xAE, 0x50, 0x7B, 0xB5, 0xDA, 0x0E, 0x65, 0x17, 0x9A, 0xE3, 0xBE,
|
||||
0x05, 0x1F, 0xED, 0x3C, 0x49, 0x94, 0x1D, 0xF4, 0xEF, 0x29, 0x56, 0xD3, 0x6D, 0x30, 0x11, 0x0C},
|
||||
{ // ssl_rsa_kek_source_y
|
||||
0x1C, 0x86, 0xF3, 0x63, 0x26, 0x54, 0x17, 0xD4, 0x99, 0x22, 0x9E, 0xB1, 0xC4, 0xAD, 0xC7, 0x47,
|
||||
0x9B, 0x2A, 0x15, 0xF9, 0x31, 0x26, 0x1F, 0x31, 0xEE, 0x67, 0x76, 0xAE, 0xB4, 0xC7, 0x65, 0x42}
|
||||
};
|
||||
end_time = get_tmr_us(); \
|
||||
gfx_printf(text" done in %d us\n", args, end_time - start_time); \
|
||||
start_time = get_tmr_us()
|
||||
#define SAVE_KEY(name, src, len) _save_key(name, src, len, text_buffer)
|
||||
#define SAVE_KEY_FAMILY(name, src, count, len) _save_key_family(name, src, count, len, text_buffer)
|
||||
|
||||
static u8 temp_key[0x10],
|
||||
bis_key[4][0x20] = {0},
|
||||
device_key[0x10] = {0},
|
||||
new_device_key[0x10] = {0},
|
||||
sd_seed[0x10] = {0},
|
||||
// FS-related keys
|
||||
fs_keys[10][0x20] = {0},
|
||||
@ -208,66 +93,80 @@ static u8 temp_key[0x10],
|
||||
package2_key[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0},
|
||||
titlekek[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0};
|
||||
|
||||
static const u32 colors[6] = {COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_GREEN, COLOR_BLUE, COLOR_VIOLET};
|
||||
|
||||
// key functions
|
||||
static bool _key_exists(const void *data) { return memcmp(data, zeros, 0x10); };
|
||||
static void _save_key(const char *name, const void *data, const u32 len, char *outbuf, u32 *buf_index);
|
||||
static void _save_key_family(const char *name, const void *data, const u32 num_keys, const u32 len, char *outbuf, u32 *buf_index);
|
||||
static void _save_key(const char *name, const void *data, const u32 len, char *outbuf);
|
||||
static void _save_key_family(const char *name, const void *data, const u32 num_keys, const u32 len, char *outbuf);
|
||||
static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed);
|
||||
// nca functions
|
||||
static void *_nca_process(u32 hk_ks1, u32 hk_ks2, FIL *fp, u32 key_offset, u32 len);
|
||||
static u32 _nca_fread_ctr(u32 ks, FIL *fp, void *buffer, u32 offset, u32 len, u8 *ctr);
|
||||
static void _update_ctr(u8 *ctr, u32 ofs);
|
||||
// output functions
|
||||
static void _putc(char *buffer, const char c);
|
||||
static u32 _puts(char *buffer, const char *s);
|
||||
static u32 _putn(char *buffer, u32 v, int base, char fill, int fcnt);
|
||||
static u32 _sprintf(char *buffer, const char *fmt, ...);
|
||||
|
||||
void dump_keys() {
|
||||
display_backlight_brightness(100, 1000);
|
||||
gfx_clear_partial_grey(0x1B, 0, 1280);
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
gfx_printf("[%kLo%kck%kpi%kck%k-R%kCM%k v%d.%d%k]\n\n",
|
||||
colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], 0xFFFF00FF, LP_VER_MJ, LP_VER_MN, 0xFFCCCCCC);
|
||||
gfx_printf("[%kLo%kck%kpi%kck%k_R%kCM%k v%d.%d.%d%k]\n\n",
|
||||
colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], 0xFFFF00FF, LP_VER_MJ, LP_VER_MN, LP_VER_BF, 0xFFCCCCCC);
|
||||
|
||||
u32 start_time = get_tmr_ms(),
|
||||
end_time,
|
||||
retries = 0;
|
||||
start_time = get_tmr_us();
|
||||
u32 begin_time = get_tmr_us();
|
||||
u32 retries = 0;
|
||||
u32 color_idx = 0;
|
||||
|
||||
tsec_ctxt_t tsec_ctxt;
|
||||
sdmmc_t sdmmc;
|
||||
|
||||
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4);
|
||||
emummc_storage_init_mmc(&storage, &sdmmc);
|
||||
TPRINTFARGS("%kMMC init... ", colors[(color_idx++) % 6]);
|
||||
|
||||
// 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);
|
||||
emummc_storage_set_mmc_partition(&storage, 1);
|
||||
emummc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
|
||||
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
|
||||
if (!pkg1_id) {
|
||||
EPRINTF("Unknown pkg1 version.");
|
||||
goto out_wait;
|
||||
}
|
||||
|
||||
bool found_tsec_fw = false;
|
||||
for (const u32 *pos = (const u32 *)pkg1; (u8 *)pos < pkg1 + 0x40000; pos += 0x100 / sizeof(u32)) {
|
||||
if (*pos == 0xCF42004D) {
|
||||
tsec_ctxt.fw = (u8 *)pos;
|
||||
found_tsec_fw = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found_tsec_fw) {
|
||||
EPRINTF("Failed to locate TSEC firmware.");
|
||||
goto out_wait;
|
||||
}
|
||||
|
||||
tsec_key_data_t *key_data = (tsec_key_data_t *)(tsec_ctxt.fw + TSEC_KEY_DATA_ADDR);
|
||||
tsec_ctxt.pkg1 = pkg1;
|
||||
tsec_ctxt.size = 0x100 + key_data->blob0_size + key_data->blob1_size + key_data->blob2_size + key_data->blob3_size + key_data->blob4_size;
|
||||
|
||||
u32 MAX_KEY = 6;
|
||||
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_620)
|
||||
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_620) {
|
||||
MAX_KEY = pkg1_id->kb + 1;
|
||||
}
|
||||
|
||||
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700) {
|
||||
sd_mount();
|
||||
if (!f_stat("sd:/sept/payload.bak", NULL)) {
|
||||
f_unlink("sd:/sept/payload.bin");
|
||||
f_rename("sd:/sept/payload.bak", "sd:/sept/payload.bin");
|
||||
}
|
||||
|
||||
if (!(EMC(EMC_SCRATCH0) & EMC_SEPT_RUN)) {
|
||||
if (!h_cfg.sept_run) {
|
||||
// bundle lp0 fw for sept instead of loading it from SD as hekate does
|
||||
sdram_lp0_save_params(sdram_get_params_patched());
|
||||
FIL fp;
|
||||
if (f_stat("sd:/sept/sept-primary.bin", NULL) || f_stat("sd:/sept/sept-secondary.enc", NULL)) {
|
||||
EPRINTF("On firmware 7.x or higher but no sept payload present\nSkipping new key derivation...");
|
||||
if (f_stat("sd:/sept", NULL)) {
|
||||
EPRINTF("On firmware 7.x+ but Sept missing.\nSkipping new key derivation...");
|
||||
goto get_tsec;
|
||||
}
|
||||
// backup post-reboot payload
|
||||
@ -278,34 +177,21 @@ void dump_keys() {
|
||||
u32 payload_size = *(u32 *)(IPL_LOAD_ADDR + 0x84) - IPL_LOAD_ADDR;
|
||||
f_write(&fp, (u8 *)IPL_LOAD_ADDR, payload_size, NULL);
|
||||
f_close(&fp);
|
||||
gfx_printf("%kFirmware 7.x or higher detected.\n%kRenamed /sept/payload.bin", colors[0], colors[1]);
|
||||
gfx_printf("\n%k to /sept/payload.bak\n%kCopied self to /sept/payload.bin",colors[2], colors[3]);
|
||||
gfx_printf("%k\nFirmware 7.x or higher detected.\n%kRenamed /sept/payload.bin", colors[(color_idx) % 6], colors[(color_idx + 1) % 6]);
|
||||
color_idx += 2;
|
||||
gfx_printf("\n%k to /sept/payload.bak\n%kCopied self to /sept/payload.bin", colors[(color_idx) % 6], colors[(color_idx + 1) % 6]);
|
||||
color_idx += 2;
|
||||
sdmmc_storage_end(&storage);
|
||||
if (!reboot_to_sept((u8 *)pkg1 + pkg1_id->tsec_off))
|
||||
if (!reboot_to_sept((u8 *)tsec_ctxt.fw, tsec_ctxt.size, pkg1_id->kb))
|
||||
goto out_wait;
|
||||
} else {
|
||||
se_aes_key_read(12, master_key[pkg1_id->kb], 0x10);
|
||||
se_aes_key_read(12, master_key[KB_FIRMWARE_VERSION_MAX], 0x10);
|
||||
}
|
||||
}
|
||||
|
||||
get_tsec: ;
|
||||
u8 tsec_keys[0x10 * 2] = {0};
|
||||
|
||||
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);
|
||||
@ -314,22 +200,26 @@ get_tsec: ;
|
||||
|
||||
int res = 0;
|
||||
|
||||
mc_disable_ahb_redirect();
|
||||
|
||||
while (tsec_query(tsec_keys, pkg1_id->kb, &tsec_ctxt) < 0) {
|
||||
memset(tsec_keys, 0x00, 0x20);
|
||||
retries++;
|
||||
if (retries > 3) {
|
||||
if (retries > 15) {
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(pkg1);
|
||||
|
||||
mc_enable_ahb_redirect();
|
||||
|
||||
if (res < 0) {
|
||||
EPRINTFARGS("ERROR %x dumping TSEC.\n", res);
|
||||
goto out_wait;
|
||||
}
|
||||
|
||||
TPRINTFARGS("%kTSEC key(s)... ", colors[0]);
|
||||
TPRINTFARGS("%kTSEC key(s)... ", colors[(color_idx++) % 6]);
|
||||
|
||||
// Master key derivation
|
||||
if (pkg1_id->kb == KB_FIRMWARE_VERSION_620 && _key_exists(tsec_keys + 0x10)) {
|
||||
@ -339,11 +229,36 @@ get_tsec: ;
|
||||
se_aes_crypt_block_ecb(8, 0, master_key[6], master_key_source);
|
||||
}
|
||||
|
||||
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_620 && _key_exists(master_key[pkg1_id->kb])) {
|
||||
// derive all lower master keys in the event keyblobs are bad
|
||||
for (u32 i = pkg1_id->kb; i > 0; i--) {
|
||||
se_aes_key_set(8, master_key[i], 0x10);
|
||||
se_aes_crypt_block_ecb(8, 0, master_key[i-1], mkey_vectors[i]);
|
||||
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_620) {
|
||||
// derive all lower master keys in case keyblobs are bad
|
||||
if (_key_exists(master_key[pkg1_id->kb])) {
|
||||
for (u32 i = pkg1_id->kb; i > 0; i--) {
|
||||
se_aes_key_set(8, master_key[i], 0x10);
|
||||
se_aes_crypt_block_ecb(8, 0, master_key[i-1], mkey_vectors[i]);
|
||||
}
|
||||
se_aes_key_set(8, master_key[0], 0x10);
|
||||
se_aes_crypt_block_ecb(8, 0, temp_key, mkey_vectors[0]);
|
||||
if (_key_exists(temp_key)) {
|
||||
EPRINTFARGS("Failed to derive master key. kb = %d", pkg1_id->kb);
|
||||
}
|
||||
} else if (_key_exists(master_key[KB_FIRMWARE_VERSION_MAX])) {
|
||||
// handle sept version differences
|
||||
for (u32 kb = KB_FIRMWARE_VERSION_MAX; kb >= KB_FIRMWARE_VERSION_620; kb--) {
|
||||
for (u32 i = kb; i > 0; i--) {
|
||||
se_aes_key_set(8, master_key[i], 0x10);
|
||||
se_aes_crypt_block_ecb(8, 0, master_key[i-1], mkey_vectors[i]);
|
||||
}
|
||||
se_aes_key_set(8, master_key[0], 0x10);
|
||||
se_aes_crypt_block_ecb(8, 0, temp_key, mkey_vectors[0]);
|
||||
if (!_key_exists(temp_key)) {
|
||||
break;
|
||||
}
|
||||
memcpy(master_key[kb-1], master_key[kb], 0x10);
|
||||
memcpy(master_key[kb], zeros, 0x10);
|
||||
}
|
||||
if (_key_exists(temp_key)) {
|
||||
EPRINTF("Failed to derive master key.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -358,11 +273,13 @@ get_tsec: ;
|
||||
se_aes_crypt_block_ecb(9, 0, keyblob_key[i], keyblob_key[i]); // kbk = unwrap(temp, sbk)
|
||||
se_aes_key_set(7, keyblob_key[i], 0x10);
|
||||
se_aes_crypt_block_ecb(7, 0, keyblob_mac_key[i], keyblob_mac_key_source); // kbm = unwrap(kbms, kbk)
|
||||
if (i == 0)
|
||||
if (i == 0) {
|
||||
se_aes_crypt_block_ecb(7, 0, device_key, per_console_key_source); // devkey = unwrap(pcks, kbk0)
|
||||
se_aes_crypt_block_ecb(7, 0, new_device_key, per_console_key_source_4x);
|
||||
}
|
||||
|
||||
// verify keyblob is not corrupt
|
||||
sdmmc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + i, 1, keyblob_block);
|
||||
emummc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + i, 1, keyblob_block);
|
||||
se_aes_key_set(3, keyblob_mac_key[i], 0x10);
|
||||
se_aes_cmac(3, keyblob_mac, 0x10, keyblob_block + 0x10, 0xa0);
|
||||
if (memcmp(keyblob_block, keyblob_mac, 0x10)) {
|
||||
@ -383,18 +300,33 @@ get_tsec: ;
|
||||
}
|
||||
free(keyblob_block);
|
||||
|
||||
TPRINTFARGS("%kMaster keys... ", colors[1]);
|
||||
TPRINTFARGS("%kMaster keys... ", colors[(color_idx++) % 6]);
|
||||
|
||||
/* key = unwrap(source, wrapped_key):
|
||||
key_set(ks, wrapped_key), block_ecb(ks, 0, key, source) -> final key in key
|
||||
*/
|
||||
|
||||
u32 key_generation = 0;
|
||||
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_500) {
|
||||
if ((fuse_read_odm(4) & 0x800) && fuse_read_odm(0) == 0x8E61ECAE && fuse_read_odm(1) == 0xF2BA3BB2) {
|
||||
key_generation = fuse_read_odm(2) & 0x1F;
|
||||
}
|
||||
}
|
||||
if (_key_exists(device_key)) {
|
||||
se_aes_key_set(8, device_key, 0x10);
|
||||
if (key_generation) {
|
||||
se_aes_key_set(8, new_device_key, 0x10);
|
||||
se_aes_crypt_block_ecb(8, 0, temp_key, new_device_key_sources[pkg1_id->kb - KB_FIRMWARE_VERSION_400]);
|
||||
se_aes_key_set(8, master_key[0], 0x10);
|
||||
se_aes_unwrap_key(8, 8, new_device_keygen_sources[pkg1_id->kb - KB_FIRMWARE_VERSION_400]);
|
||||
se_aes_crypt_block_ecb(8, 0, temp_key, temp_key);
|
||||
} else
|
||||
memcpy(temp_key, device_key, 0x10);
|
||||
se_aes_key_set(8, temp_key, 0x10);
|
||||
se_aes_unwrap_key(8, 8, retail_specific_aes_key_source); // kek = unwrap(rsaks, devkey)
|
||||
se_aes_crypt_block_ecb(8, 0, bis_key[0] + 0x00, bis_key_source[0] + 0x00); // bkey = unwrap(bkeys, kek)
|
||||
se_aes_crypt_block_ecb(8, 0, bis_key[0] + 0x10, bis_key_source[0] + 0x10);
|
||||
// kek = generate_kek(bkeks, devkey, aeskek, aeskey)
|
||||
_generate_kek(8, bis_kek_source, device_key, aes_kek_generation_source, aes_key_generation_source);
|
||||
_generate_kek(8, bis_kek_source, temp_key, aes_kek_generation_source, aes_key_generation_source);
|
||||
se_aes_crypt_block_ecb(8, 0, bis_key[1] + 0x00, bis_key_source[1] + 0x00); // bkey = unwrap(bkeys, kek)
|
||||
se_aes_crypt_block_ecb(8, 0, bis_key[1] + 0x10, bis_key_source[1] + 0x10);
|
||||
se_aes_crypt_block_ecb(8, 0, bis_key[2] + 0x00, bis_key_source[2] + 0x00);
|
||||
@ -405,16 +337,12 @@ get_tsec: ;
|
||||
// Dump package2.
|
||||
u8 *pkg2 = NULL;
|
||||
pkg2_kip1_info_t *ki = NULL;
|
||||
if (!_key_exists(master_key[pkg1_id->kb])) {
|
||||
EPRINTF("Current master key not found.\nUnable to decrypt Package2.");
|
||||
goto pkg2_done;
|
||||
}
|
||||
|
||||
sdmmc_storage_set_mmc_partition(&storage, 0);
|
||||
emummc_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) {
|
||||
@ -438,19 +366,35 @@ get_tsec: ;
|
||||
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.
|
||||
se_aes_key_set(8, master_key[pkg1_id->kb], 0x10);
|
||||
se_aes_unwrap_key(8, 8, package2_key_source);
|
||||
pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(pkg2);
|
||||
// Decrypt package2 and parse KIP1 blobs in INI1 section. Try all available key generations in case of pkg1/pkg2 mismatch.
|
||||
pkg2_hdr_t *pkg2_hdr;
|
||||
pkg2_hdr_t hdr;
|
||||
u32 pkg2_kb;
|
||||
for (pkg2_kb = 0; pkg2_kb < MAX_KEY; pkg2_kb++) {
|
||||
se_aes_key_set(8, master_key[pkg2_kb], 0x10);
|
||||
se_aes_unwrap_key(8, 8, package2_key_source);
|
||||
memcpy(&hdr, pkg2 + 0x100, sizeof(pkg2_hdr_t));
|
||||
se_aes_crypt_ctr(8, &hdr, sizeof(pkg2_hdr_t), &hdr, sizeof(pkg2_hdr_t), &hdr);
|
||||
if (hdr.magic == PKG2_MAGIC)
|
||||
break;
|
||||
}
|
||||
if (pkg2_kb == MAX_KEY) {
|
||||
EPRINTF("Failed to derive Package2 key.");
|
||||
goto pkg2_done;
|
||||
} else if (pkg2_kb != pkg1_id->kb)
|
||||
EPRINTFARGS("Warning! Package1-Package2 mismatch: %d, %d", pkg1_id->kb, pkg2_kb);
|
||||
|
||||
pkg2_hdr = pkg2_decrypt(pkg2);
|
||||
if (!pkg2_hdr) {
|
||||
EPRINTF("Failed to decrypt Package2.");
|
||||
goto pkg2_done;
|
||||
}
|
||||
|
||||
TPRINTFARGS("%kDecrypt pkg2... ", colors[2]);
|
||||
TPRINTFARGS("%kDecrypt pkg2... ", colors[(color_idx++) % 6]);
|
||||
|
||||
LIST_INIT(kip1_info);
|
||||
pkg2_parse_kips(&kip1_info, pkg2_hdr);
|
||||
bool new_pkg2;
|
||||
pkg2_parse_kips(&kip1_info, pkg2_hdr, &new_pkg2);
|
||||
LIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki_tmp, &kip1_info, link) {
|
||||
if(ki_tmp->kip1->tid == 0x0100000000000000ULL) {
|
||||
ki = malloc(sizeof(pkg2_kip1_info_t));
|
||||
@ -467,7 +411,7 @@ get_tsec: ;
|
||||
}
|
||||
|
||||
pkg2_decompress_kip(ki, 2 | 4); // we only need .rodata and .data
|
||||
TPRINTFARGS("%kDecompress FS...", colors[3]);
|
||||
TPRINTFARGS("%kDecompress FS...", colors[(color_idx++) % 6]);
|
||||
|
||||
u8 hash_index = 0, hash_max = 9, hash_order[10],
|
||||
key_lengths[10] = {0x10, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20};
|
||||
@ -518,10 +462,16 @@ get_tsec: ;
|
||||
alignment = 8;
|
||||
break;
|
||||
case KB_FIRMWARE_VERSION_700:
|
||||
case KB_FIRMWARE_VERSION_810:
|
||||
start_offset = 0x29c50;
|
||||
hks_offset_from_end -= 0x6a73;
|
||||
alignment = 8;
|
||||
break;
|
||||
case KB_FIRMWARE_VERSION_900:
|
||||
start_offset = 0x2ec10;
|
||||
hks_offset_from_end -= 0x5573;
|
||||
alignment = 1; // RIP
|
||||
break;
|
||||
}
|
||||
|
||||
if (pkg1_id->kb <= KB_FIRMWARE_VERSION_500) {
|
||||
@ -559,7 +509,7 @@ pkg2_done:
|
||||
free(pkg2);
|
||||
free(ki);
|
||||
|
||||
TPRINTFARGS("%kFS keys... ", colors[4]);
|
||||
TPRINTFARGS("%kFS keys... ", colors[(color_idx++) % 6]);
|
||||
|
||||
if (_key_exists(fs_keys[0]) && _key_exists(fs_keys[1]) && _key_exists(master_key[0])) {
|
||||
_generate_kek(8, fs_keys[0], master_key[0], aes_kek_generation_source, aes_key_generation_source);
|
||||
@ -572,6 +522,9 @@ pkg2_done:
|
||||
se_aes_crypt_block_ecb(8, 0, save_mac_key, fs_keys[6]);
|
||||
}
|
||||
|
||||
if (_key_exists(master_key[MAX_KEY])) {
|
||||
MAX_KEY = KB_FIRMWARE_VERSION_MAX + 1;
|
||||
}
|
||||
for (u32 i = 0; i < MAX_KEY; i++) {
|
||||
if (!_key_exists(master_key[i]))
|
||||
continue;
|
||||
@ -588,7 +541,10 @@ pkg2_done:
|
||||
|
||||
|
||||
if (!_key_exists(header_key) || !_key_exists(bis_key[2]))
|
||||
{
|
||||
EPRINTF("Missing FS keys. Skipping ES/SSL keys.");
|
||||
goto key_output;
|
||||
}
|
||||
|
||||
se_aes_key_set(4, header_key + 0x00, 0x10);
|
||||
se_aes_key_set(5, header_key + 0x10, 0x10);
|
||||
@ -600,7 +556,7 @@ pkg2_done:
|
||||
EPRINTF("Failed to locate System partition.");
|
||||
goto key_output;
|
||||
}
|
||||
FATFS emmc_fs;
|
||||
__attribute__ ((aligned (16))) FATFS emmc_fs;
|
||||
if (f_mount(&emmc_fs, "emmc:", 1)) {
|
||||
EPRINTF("Mount failed.");
|
||||
goto key_output;
|
||||
@ -667,8 +623,12 @@ pkg2_done:
|
||||
start_offset = 0x5674;
|
||||
break;
|
||||
case KB_FIRMWARE_VERSION_700:
|
||||
case KB_FIRMWARE_VERSION_810:
|
||||
start_offset = 0x5563;
|
||||
break;
|
||||
case KB_FIRMWARE_VERSION_900:
|
||||
start_offset = 0x6495;
|
||||
break;
|
||||
}
|
||||
hash_order[2] = 2;
|
||||
if (pkg1_id->kb < KB_FIRMWARE_VERSION_500) {
|
||||
@ -717,8 +677,12 @@ pkg2_done:
|
||||
start_offset = 0x1d5be;
|
||||
break;
|
||||
case KB_FIRMWARE_VERSION_700:
|
||||
case KB_FIRMWARE_VERSION_810:
|
||||
start_offset = 0x1d437;
|
||||
break;
|
||||
case KB_FIRMWARE_VERSION_900:
|
||||
start_offset = 0x1d807;
|
||||
break;
|
||||
}
|
||||
if (!memcmp(pkg1_id->id, "2016", 4))
|
||||
start_offset = 0x449dc;
|
||||
@ -747,26 +711,32 @@ pkg2_done:
|
||||
f_closedir(&dir);
|
||||
free(dec_header);
|
||||
|
||||
if (memcmp(pkg1_id->id, "2016", 4)) {
|
||||
TPRINTFARGS("%kES & SSL keys...", colors[(color_idx++) % 6]);
|
||||
} else {
|
||||
TPRINTFARGS("%kSSL keys... ", colors[(color_idx++) % 6]);
|
||||
}
|
||||
|
||||
if (f_open(&fp, "sd:/Nintendo/Contents/private", FA_READ | FA_OPEN_EXISTING)) {
|
||||
EPRINTF("Failed to open SD seed verification file from SD.");
|
||||
EPRINTF("Unable to locate SD seed. Skipping.");
|
||||
goto dismount;
|
||||
}
|
||||
// get sd seed verification vector
|
||||
if (f_read(&fp, temp_key, 0x10, &read_bytes) || read_bytes != 0x10) {
|
||||
EPRINTF("Failed to read SD seed verification vector from SD.");
|
||||
EPRINTF("Unable to locate SD seed. Skipping.");
|
||||
f_close(&fp);
|
||||
goto dismount;
|
||||
}
|
||||
f_close(&fp);
|
||||
|
||||
if (f_open(&fp, "emmc:/save/8000000000000043", FA_READ | FA_OPEN_EXISTING) || f_stat("emmc:/save/8000000000000043", &fno)) {
|
||||
EPRINTF("Failed to open ns_appman save.");
|
||||
if (f_open(&fp, "emmc:/save/8000000000000043", FA_READ | FA_OPEN_EXISTING)) {
|
||||
EPRINTF("Failed to open ns_appman save.\nSkipping SD seed.");
|
||||
goto dismount;
|
||||
}
|
||||
|
||||
// locate sd seed
|
||||
u8 read_buf[0x20] = {0};
|
||||
for (u32 i = 0; i < fno.fsize; i += 0x4000) {
|
||||
for (u32 i = 0x8000; i < f_size(&fp); i += 0x4000) {
|
||||
if (f_lseek(&fp, i) || f_read(&fp, read_buf, 0x20, &read_bytes) || read_bytes != 0x20)
|
||||
break;
|
||||
if (!memcmp(temp_key, read_buf, 0x10)) {
|
||||
@ -776,16 +746,12 @@ pkg2_done:
|
||||
}
|
||||
f_close(&fp);
|
||||
|
||||
TPRINTFARGS("%kSD Seed... ", colors[(color_idx++) % 6]);
|
||||
|
||||
dismount:
|
||||
f_mount(NULL, "emmc:", 1);
|
||||
nx_emmc_gpt_free(&gpt);
|
||||
sdmmc_storage_end(&storage);
|
||||
|
||||
if (memcmp(pkg1_id->id, "2016", 4)) {
|
||||
TPRINTFARGS("%kES & SSL keys...", colors[5]);
|
||||
} else {
|
||||
TPRINTFARGS("%kSSL keys... ", colors[5]);
|
||||
}
|
||||
emummc_storage_end(&storage);
|
||||
|
||||
// derive eticket_rsa_kek and ssl_rsa_kek
|
||||
if (_key_exists(es_keys[0]) && _key_exists(es_keys[1]) && _key_exists(master_key[0])) {
|
||||
@ -802,8 +768,7 @@ dismount:
|
||||
}
|
||||
|
||||
key_output: ;
|
||||
char *text_buffer = (char *)calloc(0x4000, 1);
|
||||
u32 buf_index = 0;
|
||||
__attribute__ ((aligned (16))) char text_buffer[0x3000] = {0};
|
||||
|
||||
SAVE_KEY("aes_kek_generation_source", aes_kek_generation_source, 0x10);
|
||||
SAVE_KEY("aes_key_generation_source", aes_key_generation_source, 0x10);
|
||||
@ -831,6 +796,8 @@ key_output: ;
|
||||
SAVE_KEY_FAMILY("master_kek", master_kek, MAX_KEY, 0x10);
|
||||
SAVE_KEY("master_kek_source_06", master_kek_sources[0], 0x10);
|
||||
SAVE_KEY("master_kek_source_07", master_kek_sources[1], 0x10);
|
||||
SAVE_KEY("master_kek_source_08", master_kek_sources[2], 0x10);
|
||||
SAVE_KEY("master_kek_source_09", master_kek_sources[3], 0x10);
|
||||
SAVE_KEY_FAMILY("master_key", master_key, MAX_KEY, 0x10);
|
||||
SAVE_KEY("master_key_source", master_key_source, 0x10);
|
||||
SAVE_KEY_FAMILY("package1_key", package1_key, 6, 0x10);
|
||||
@ -863,43 +830,47 @@ key_output: ;
|
||||
|
||||
//gfx_con.fntsz = 8; gfx_puts(text_buffer); gfx_con.fntsz = 16;
|
||||
|
||||
TPRINTFARGS("\n%kFound %d keys.\n%kLockpick totally", colors[0], _key_count, colors[1]);
|
||||
end_time = get_tmr_us();
|
||||
gfx_printf("\n%kFound %d keys.", colors[(color_idx++) % 6], _key_count);
|
||||
_key_count = 0;
|
||||
gfx_printf("\n%kLockpick totally done in %d us", colors[(color_idx++) % 6], end_time - begin_time);
|
||||
gfx_printf("\n%kFound through master_key_%02x\n", colors[(color_idx++) % 6], MAX_KEY - 1);
|
||||
|
||||
f_mkdir("switch");
|
||||
if (!sd_save_to_file(text_buffer, buf_index, "sd:/switch/prod.keys"))
|
||||
gfx_printf("%kWrote %d bytes to /switch/prod.keys\n", colors[2], buf_index);
|
||||
f_mkdir("sd:/switch");
|
||||
char keyfile_path[30] = "sd:/switch/";
|
||||
if (!(fuse_read_odm(4) & 3))
|
||||
sprintf(&keyfile_path[11], "prod.keys");
|
||||
else
|
||||
sprintf(&keyfile_path[11], "dev.keys");
|
||||
if (sd_mount() && !sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) {
|
||||
gfx_printf("%kWrote %d bytes to %s\n", colors[(color_idx++) % 6], (u32)fno.fsize, keyfile_path);
|
||||
} else
|
||||
EPRINTF("Failed to save keys to SD.");
|
||||
h_cfg.emummc_force_disable = emummc_load_cfg();
|
||||
|
||||
out_wait:
|
||||
sd_unmount();
|
||||
free(text_buffer);
|
||||
gfx_printf("\n%kPress any key to return to the main menu.", colors[(color_idx) % 6], colors[(color_idx + 1) % 6], colors[(color_idx + 2) % 6]);
|
||||
|
||||
gfx_printf("\n%kVOL + -> Reboot to RCM\n%kVOL - -> Reboot normally\n%kPower -> Power off", colors[3], colors[4], colors[5]);
|
||||
|
||||
out_wait: ;
|
||||
u32 btn = btn_wait();
|
||||
if (btn & BTN_VOL_UP)
|
||||
reboot_rcm();
|
||||
else if (btn & BTN_VOL_DOWN)
|
||||
reboot_normal();
|
||||
else
|
||||
power_off();
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
static void _save_key(const char *name, const void *data, const u32 len, char *outbuf, u32 *buf_index) {
|
||||
static void _save_key(const char *name, const void *data, const u32 len, char *outbuf) {
|
||||
if (!_key_exists(data))
|
||||
return;
|
||||
*buf_index += _sprintf(outbuf + *buf_index, "%s = ", name);
|
||||
u32 pos = strlen(outbuf);
|
||||
pos += sprintf(&outbuf[pos], "%s = ", name);
|
||||
for (u32 i = 0; i < len; i++)
|
||||
*buf_index += _sprintf(outbuf + *buf_index, "%02x", *(u8*)(data + i));
|
||||
*buf_index += _sprintf(outbuf + *buf_index, "\n");
|
||||
pos += sprintf(&outbuf[pos], "%02x", *(u8*)(data + i));
|
||||
sprintf(&outbuf[pos], "\n");
|
||||
_key_count++;
|
||||
}
|
||||
|
||||
static void _save_key_family(const char *name, const void *data, const u32 num_keys, const u32 len, char *outbuf, u32 *buf_index) {
|
||||
static void _save_key_family(const char *name, const void *data, const u32 num_keys, const u32 len, char *outbuf) {
|
||||
char temp_name[0x40] = {0};
|
||||
for (u32 i = 0; i < num_keys; i++) {
|
||||
_sprintf(temp_name, "%s_%02x", name, i);
|
||||
_save_key(temp_name, data + i * len, len, outbuf, buf_index);
|
||||
sprintf(temp_name, "%s_%02x", name, i);
|
||||
_save_key(temp_name, data + i * len, len, outbuf);
|
||||
}
|
||||
}
|
||||
|
||||
@ -979,105 +950,3 @@ static void _update_ctr(u8 *ctr, u32 ofs) {
|
||||
for (u32 i = 0; i < 4; i++, ofs >>= 8)
|
||||
ctr[0x10-i-1] = (u8)(ofs & 0xff);
|
||||
}
|
||||
|
||||
static void _putc(char *buffer, const char c) {
|
||||
*buffer = c;
|
||||
}
|
||||
|
||||
static u32 _puts(char *buffer, const char *s) {
|
||||
u32 count = 0;
|
||||
for (; *s; s++, count++)
|
||||
_putc(buffer + count, *s);
|
||||
return count;
|
||||
}
|
||||
|
||||
static u32 _putn(char *buffer, u32 v, int base, char fill, int fcnt) {
|
||||
char buf[0x121];
|
||||
static const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
char *p;
|
||||
int c = fcnt;
|
||||
|
||||
if (base > 36)
|
||||
return 0;
|
||||
|
||||
p = buf + 0x120;
|
||||
*p = 0;
|
||||
do {
|
||||
c--;
|
||||
*--p = digits[v % base];
|
||||
v /= base;
|
||||
} while (v);
|
||||
|
||||
if (fill != 0) {
|
||||
while (c > 0) {
|
||||
*--p = fill;
|
||||
c--;
|
||||
}
|
||||
}
|
||||
|
||||
return _puts(buffer, p);
|
||||
}
|
||||
|
||||
static u32 _sprintf(char *buffer, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
int fill, fcnt;
|
||||
u32 count = 0;
|
||||
|
||||
va_start(ap, fmt);
|
||||
while(*fmt) {
|
||||
if (*fmt == '%') {
|
||||
fmt++;
|
||||
fill = 0;
|
||||
fcnt = 0;
|
||||
if ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ') {
|
||||
fcnt = *fmt;
|
||||
fmt++;
|
||||
if (*fmt >= '0' && *fmt <= '9') {
|
||||
fill = fcnt;
|
||||
fcnt = *fmt - '0';
|
||||
fmt++;
|
||||
} else {
|
||||
fill = ' ';
|
||||
fcnt -= '0';
|
||||
}
|
||||
}
|
||||
switch (*fmt) {
|
||||
case 'c':
|
||||
_putc(buffer + count, va_arg(ap, u32));
|
||||
count++;
|
||||
break;
|
||||
case 's':
|
||||
count += _puts(buffer + count, va_arg(ap, char *));
|
||||
break;
|
||||
case 'd':
|
||||
count += _putn(buffer + count, va_arg(ap, u32), 10, fill, fcnt);
|
||||
break;
|
||||
case 'p':
|
||||
case 'P':
|
||||
case 'x':
|
||||
case 'X':
|
||||
count += _putn(buffer + count, va_arg(ap, u32), 16, fill, fcnt);
|
||||
break;
|
||||
case '%':
|
||||
_putc(buffer + count, '%');
|
||||
count++;
|
||||
break;
|
||||
case '\0':
|
||||
goto out;
|
||||
default:
|
||||
_putc(buffer + count, '%');
|
||||
_putc(buffer + count, *fmt);
|
||||
count += 2;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
_putc(buffer + count, *fmt);
|
||||
count++;
|
||||
}
|
||||
fmt++;
|
||||
}
|
||||
|
||||
out:
|
||||
va_end(ap);
|
||||
return count;
|
||||
}
|
||||
|
@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2019 shchmue
|
||||
*
|
||||
* 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 _KEYS_H_
|
||||
#define _KEYS_H_
|
||||
|
||||
|
@ -32,24 +32,24 @@ const blz_footer *blz_get_footer(const unsigned char *compData, unsigned int com
|
||||
}
|
||||
|
||||
// From https://github.com/SciresM/hactool/blob/master/kip.c which is exactly how kernel does it, thanks SciresM!
|
||||
int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const blz_footer *footer)
|
||||
int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const blz_footer *footer)
|
||||
{
|
||||
u32 addl_size = footer->addl_size;
|
||||
u32 header_size = footer->header_size;
|
||||
u32 cmp_and_hdr_size = footer->cmp_and_hdr_size;
|
||||
|
||||
|
||||
unsigned char* cmp_start = &dataBuf[compSize] - cmp_and_hdr_size;
|
||||
u32 cmp_ofs = cmp_and_hdr_size - header_size;
|
||||
u32 out_ofs = cmp_and_hdr_size + addl_size;
|
||||
|
||||
while (out_ofs)
|
||||
|
||||
while (out_ofs)
|
||||
{
|
||||
unsigned char control = cmp_start[--cmp_ofs];
|
||||
for (unsigned int i=0; i<8; i++)
|
||||
for (unsigned int i=0; i<8; i++)
|
||||
{
|
||||
if (control & 0x80)
|
||||
if (control & 0x80)
|
||||
{
|
||||
if (cmp_ofs < 2)
|
||||
if (cmp_ofs < 2)
|
||||
return 0; // Out of bounds.
|
||||
|
||||
cmp_ofs -= 2;
|
||||
@ -64,17 +64,17 @@ int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const
|
||||
for (unsigned int j = 0; j < seg_size; j++)
|
||||
cmp_start[out_ofs + j] = cmp_start[out_ofs + j + seg_ofs];
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
// Copy directly.
|
||||
if (cmp_ofs < 1)
|
||||
if (cmp_ofs < 1)
|
||||
return 0; //out of bounds
|
||||
|
||||
cmp_start[--out_ofs] = cmp_start[--cmp_ofs];
|
||||
}
|
||||
control <<= 1;
|
||||
if (out_ofs == 0) // Blz works backwards, so if it reaches byte 0, it's done.
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,6 @@
|
||||
|
||||
#include <string.h>
|
||||
#include "diskio.h" /* FatFs lower layer API */
|
||||
#include "../../gfx/gfx.h"
|
||||
#include "../../mem/heap.h"
|
||||
#include "../../sec/se.h"
|
||||
#include "../../storage/nx_emmc.h"
|
||||
@ -38,30 +37,27 @@ extern sdmmc_storage_t sd_storage;
|
||||
extern sdmmc_storage_t storage;
|
||||
extern emmc_part_t *system_part;
|
||||
|
||||
typedef struct {
|
||||
u64 b, a;
|
||||
} le128;
|
||||
|
||||
typedef struct {
|
||||
u32 sector;
|
||||
u32 visit_count;
|
||||
u8 tweak[0x10];
|
||||
u8 cached_sector[0x200];
|
||||
u8 align[8];
|
||||
} sector_cache_t;
|
||||
|
||||
|
||||
#define MAX_SEC_CACHE_ENTRIES 64
|
||||
static sector_cache_t *sector_cache = (sector_cache_t*)0x40020000;
|
||||
static sector_cache_t *sector_cache = (sector_cache_t*)0x40022000;
|
||||
static u32 secindex = 0;
|
||||
|
||||
DSTATUS disk_status (
|
||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||
BYTE pdrv /* Physical drive number to identify the drive */
|
||||
)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
DSTATUS disk_initialize (
|
||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||
BYTE pdrv /* Physical drive number to identify the drive */
|
||||
)
|
||||
{
|
||||
return 0;
|
||||
@ -81,7 +77,6 @@ static inline void _gf256_mul_x_le(void *block) {
|
||||
pdata[0x0] ^= 0x87;
|
||||
}
|
||||
|
||||
//8378ms before doing the block op all at once, 2179ms after!
|
||||
static inline int _emmc_xts(u32 ks1, u32 ks2, u32 enc, u8 *tweak, bool regen_tweak, u32 tweak_exp, u64 sec, void *dst, void *src, u32 secsize) {
|
||||
int res = 0;
|
||||
u8 *pdst = (u8 *)dst;
|
||||
@ -131,7 +126,7 @@ out:;
|
||||
}
|
||||
|
||||
DRESULT disk_read (
|
||||
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||
BYTE pdrv, /* Physical drive number to identify the drive */
|
||||
BYTE *buff, /* Data buffer to store read data */
|
||||
DWORD sector, /* Start sector in LBA */
|
||||
UINT count /* Number of sectors to read */
|
||||
@ -140,20 +135,12 @@ DRESULT disk_read (
|
||||
switch (pdrv)
|
||||
{
|
||||
case 0:
|
||||
if ((u32)buff >= DRAM_START)
|
||||
return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR;
|
||||
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER;
|
||||
if (sdmmc_storage_read(&sd_storage, sector, count, buf))
|
||||
{
|
||||
memcpy(buff, buf, 512 * count);
|
||||
return RES_OK;
|
||||
}
|
||||
return RES_ERROR;
|
||||
return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR;
|
||||
|
||||
case 1:;
|
||||
static u8 tweak[0x10];
|
||||
static u64 prev_cluster = -1;
|
||||
static u32 prev_sector = 0;
|
||||
__attribute__ ((aligned (16))) static u8 tweak[0x10];
|
||||
__attribute__ ((aligned (16))) static u64 prev_cluster = -1;
|
||||
__attribute__ ((aligned (16))) static u32 prev_sector = 0;
|
||||
u32 tweak_exp = 0;
|
||||
bool regen_tweak = true, cache_sector = false;
|
||||
|
||||
@ -166,7 +153,6 @@ DRESULT disk_read (
|
||||
memcpy(tweak, sector_cache[s].tweak, 0x10);
|
||||
prev_sector = sector;
|
||||
prev_cluster = sector / 0x20;
|
||||
//gfx_printf("addr %x sec %x count %x cached\n", sector * 0x200, sector, count);
|
||||
return RES_OK;
|
||||
}
|
||||
}
|
||||
@ -180,7 +166,6 @@ DRESULT disk_read (
|
||||
}
|
||||
|
||||
if (nx_emmc_part_read(&storage, system_part, sector, count, buff)) {
|
||||
//gfx_hexdump(0, buff, 0x100);
|
||||
if (prev_cluster != sector / 0x20) { // sector in different cluster than last read
|
||||
prev_cluster = sector / 0x20;
|
||||
tweak_exp = sector % 0x20;
|
||||
@ -192,13 +177,11 @@ DRESULT disk_read (
|
||||
}
|
||||
|
||||
// fatfs will never pull more than a cluster
|
||||
//gfx_printf("sec %6x count %2x tweak %2x\n", sector, count, tweak_exp);
|
||||
_emmc_xts(9, 8, 0, tweak, regen_tweak, tweak_exp, prev_cluster, buff, buff, count * 0x200);
|
||||
if (cache_sector) {
|
||||
memcpy(sector_cache[s].cached_sector, buff, 0x200);
|
||||
memcpy(sector_cache[s].tweak, tweak, 0x10);
|
||||
}
|
||||
//gfx_hexdump(0, buff, 0x10);
|
||||
prev_sector = sector + count - 1;
|
||||
return RES_OK;
|
||||
}
|
||||
@ -208,7 +191,7 @@ DRESULT disk_read (
|
||||
}
|
||||
|
||||
DRESULT disk_write (
|
||||
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||
BYTE pdrv, /* Physical drive number to identify the drive */
|
||||
const BYTE *buff, /* Data to be written */
|
||||
DWORD sector, /* Start sector in LBA */
|
||||
UINT count /* Number of sectors to write */
|
||||
@ -216,17 +199,11 @@ DRESULT disk_write (
|
||||
{
|
||||
if (pdrv == 1)
|
||||
return RES_WRPRT;
|
||||
if ((u32)buff >= DRAM_START)
|
||||
return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR;
|
||||
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;
|
||||
return RES_ERROR;
|
||||
return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR;
|
||||
}
|
||||
|
||||
DRESULT disk_ioctl (
|
||||
BYTE pdrv, /* Physical drive nmuber (0..) */
|
||||
BYTE pdrv, /* Physical drive number (0..) */
|
||||
BYTE cmd, /* Control code */
|
||||
void *buff /* Buffer to send/receive control data */
|
||||
)
|
||||
|
@ -1,10 +1,25 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/*----------------------------------------------------------------------------/
|
||||
/ FatFs - Generic FAT Filesystem Module R0.13c (p3) /
|
||||
/ FatFs - Generic FAT Filesystem Module R0.13c (p4) /
|
||||
/-----------------------------------------------------------------------------/
|
||||
/
|
||||
/ Copyright (C) 2018, ChaN, all right reserved.
|
||||
/ Copyright (c) 2018 naehrwert
|
||||
/ Copyright (C) 2018-2019 CTCaer
|
||||
/
|
||||
/ FatFs module is an open source software. Redistribution and use of FatFs in
|
||||
/ source and binary forms, with or without modification, are permitted provided
|
||||
@ -3472,7 +3487,7 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
|
||||
#if FF_USE_LFN == 1
|
||||
fs->lfnbuf = LfnBuf; /* Static LFN working buffer */
|
||||
#if FF_FS_EXFAT
|
||||
fs->dirbuf = DirBuf; /* Static directory block scratchpad buuffer */
|
||||
fs->dirbuf = DirBuf; /* Static directory block scratchpad buffer */
|
||||
#endif
|
||||
#endif
|
||||
#if FF_FS_RPATH != 0
|
||||
@ -4243,9 +4258,9 @@ FRESULT f_getcwd (
|
||||
TCHAR *tp = buff;
|
||||
#if FF_VOLUMES >= 2
|
||||
UINT vl;
|
||||
#endif
|
||||
#if FF_STR_VOLUME_ID
|
||||
const char *vp;
|
||||
#endif
|
||||
#endif
|
||||
FILINFO fno;
|
||||
DEF_NAMBUF
|
||||
@ -4726,7 +4741,7 @@ FRESULT f_getfree (
|
||||
/* Get logical drive */
|
||||
res = find_volume(&path, &fs, 0);
|
||||
if (res == FR_OK) {
|
||||
*fatfs = fs; /* Return ptr to the fs object */
|
||||
if (fatfs) *fatfs = fs; /* Return ptr to the fs object */
|
||||
/* If free_clst is valid, return it without full FAT scan */
|
||||
if (fs->free_clst <= fs->n_fatent - 2) {
|
||||
*nclst = fs->free_clst;
|
||||
@ -6632,4 +6647,3 @@ FRESULT f_setcp (
|
||||
return FR_OK;
|
||||
}
|
||||
#endif /* FF_CODE_PAGE == 0 */
|
||||
|
||||
|
@ -95,6 +95,7 @@ typedef DWORD FSIZE_t;
|
||||
/* Filesystem object structure (FATFS) */
|
||||
|
||||
typedef struct {
|
||||
BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
|
||||
BYTE fs_type; /* Filesystem type (0:not mounted) */
|
||||
BYTE pdrv; /* Associated physical drive */
|
||||
BYTE n_fats; /* Number of FATs (1 or 2) */
|
||||
@ -137,7 +138,6 @@ typedef struct {
|
||||
DWORD bitbase; /* Allocation bitmap base sector */
|
||||
#endif
|
||||
DWORD winsect; /* Current sector appearing in the win[] */
|
||||
BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
|
||||
} FATFS;
|
||||
|
||||
|
||||
@ -168,6 +168,9 @@ typedef struct {
|
||||
/* File object structure (FIL) */
|
||||
|
||||
typedef struct {
|
||||
#if !FF_FS_TINY
|
||||
BYTE buf[FF_MAX_SS]; /* File private data read/write window */
|
||||
#endif
|
||||
FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */
|
||||
BYTE flag; /* File status flags */
|
||||
BYTE err; /* Abort flag (error code) */
|
||||
@ -178,9 +181,6 @@ typedef struct {
|
||||
DWORD dir_sect; /* Sector number containing the directory entry (not used at exFAT) */
|
||||
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */
|
||||
#endif
|
||||
#if !FF_FS_TINY
|
||||
BYTE buf[FF_MAX_SS]; /* File private data read/write window */
|
||||
#endif
|
||||
#if FF_USE_FASTSEEK
|
||||
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
|
||||
#endif
|
||||
@ -279,7 +279,7 @@ FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get numbe
|
||||
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
|
||||
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
|
||||
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
|
||||
FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */
|
||||
FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */
|
||||
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
|
||||
FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */
|
||||
FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */
|
||||
|
@ -25,7 +25,7 @@
|
||||
/ 3: f_lseek() function is removed in addition to 2. */
|
||||
|
||||
|
||||
#define FF_USE_STRFUNC 0
|
||||
#define FF_USE_STRFUNC 2
|
||||
/* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf().
|
||||
/
|
||||
/ 0: Disable string functions.
|
||||
@ -33,7 +33,7 @@
|
||||
/ 2: Enable with LF-CRLF conversion. */
|
||||
|
||||
|
||||
#define FF_USE_FIND 0
|
||||
#define FF_USE_FIND 1
|
||||
/* This option switches filtered directory read functions, f_findfirst() and
|
||||
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
|
||||
|
||||
@ -50,7 +50,7 @@
|
||||
/* This option switches f_expand function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define FF_USE_CHMOD 0
|
||||
#define FF_USE_CHMOD 1
|
||||
/* This option switches attribute manipulation functions, f_chmod() and f_utime().
|
||||
/ (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */
|
||||
|
||||
|
@ -34,7 +34,6 @@
|
||||
#define MERGE2(a, b) a ## b
|
||||
#define CVTBL(tbl, cp) MERGE2(tbl, cp)
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Code Conversion Tables */
|
||||
/*------------------------------------------------------------------------*/
|
||||
@ -623,5 +622,4 @@ DWORD ff_wtoupper ( /* Returns up-converted code point */
|
||||
return uni;
|
||||
}
|
||||
|
||||
|
||||
#endif /* #if FF_USE_LFN */
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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,
|
||||
@ -18,23 +18,29 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "config/config.h"
|
||||
#include "gfx/di.h"
|
||||
#include "gfx/gfx.h"
|
||||
#include "gfx/tui.h"
|
||||
#include "libs/fatfs/ff.h"
|
||||
#include "mem/heap.h"
|
||||
#include "power/max77620.h"
|
||||
#include "rtc/max77620-rtc.h"
|
||||
#include "soc/bpmp.h"
|
||||
#include "soc/hw_init.h"
|
||||
#include "storage/emummc.h"
|
||||
#include "storage/sdmmc.h"
|
||||
#include "utils/sprintf.h"
|
||||
#include "utils/util.h"
|
||||
|
||||
#include "keys/keys.h"
|
||||
|
||||
sdmmc_t sd_sdmmc;
|
||||
sdmmc_storage_t sd_storage;
|
||||
FATFS sd_fs;
|
||||
__attribute__ ((aligned (16))) FATFS sd_fs;
|
||||
static bool sd_mounted;
|
||||
|
||||
hekate_config h_cfg;
|
||||
boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg;
|
||||
|
||||
bool sd_mount()
|
||||
@ -49,7 +55,7 @@ bool sd_mount()
|
||||
else
|
||||
{
|
||||
int res = 0;
|
||||
res = f_mount(&sd_fs, "", 1);
|
||||
res = f_mount(&sd_fs, "sd:", 1);
|
||||
if (res == FR_OK)
|
||||
{
|
||||
sd_mounted = 1;
|
||||
@ -68,33 +74,30 @@ void sd_unmount()
|
||||
{
|
||||
if (sd_mounted)
|
||||
{
|
||||
f_mount(NULL, "", 1);
|
||||
f_mount(NULL, "sd:", 1);
|
||||
sdmmc_storage_end(&sd_storage);
|
||||
sd_mounted = false;
|
||||
}
|
||||
}
|
||||
|
||||
void *sd_file_read(char *path)
|
||||
void *sd_file_read(const char *path, u32 *fsize)
|
||||
{
|
||||
FIL fp;
|
||||
if (f_open(&fp, path, FA_READ) != FR_OK)
|
||||
return NULL;
|
||||
|
||||
u32 size = f_size(&fp);
|
||||
if (fsize)
|
||||
*fsize = size;
|
||||
|
||||
void *buf = malloc(size);
|
||||
|
||||
u8 *ptr = buf;
|
||||
while (size > 0)
|
||||
if (f_read(&fp, buf, size, NULL) != FR_OK)
|
||||
{
|
||||
u32 rsize = MIN(size, 512 * 512);
|
||||
if (f_read(&fp, ptr, rsize, NULL) != FR_OK)
|
||||
{
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
free(buf);
|
||||
f_close(&fp);
|
||||
|
||||
ptr += rsize;
|
||||
size -= rsize;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
f_close(&fp);
|
||||
@ -110,7 +113,7 @@ int sd_save_to_file(void *buf, u32 size, const char *filename)
|
||||
if (res)
|
||||
{
|
||||
EPRINTFARGS("Error (%d) creating file\n%s.\n", res, filename);
|
||||
return 1;
|
||||
return res;
|
||||
}
|
||||
|
||||
f_write(&fp, buf, size, NULL);
|
||||
@ -145,23 +148,74 @@ void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size)
|
||||
}
|
||||
}
|
||||
|
||||
void dump_sysnand()
|
||||
{
|
||||
h_cfg.emummc_force_disable = true;
|
||||
b_cfg.extra_cfg &= ~EXTRA_CFG_DUMP_EMUMMC;
|
||||
dump_keys();
|
||||
}
|
||||
|
||||
void dump_emunand()
|
||||
{
|
||||
if (h_cfg.emummc_force_disable)
|
||||
return;
|
||||
emu_cfg.enabled = 1;
|
||||
b_cfg.extra_cfg |= EXTRA_CFG_DUMP_EMUMMC;
|
||||
dump_keys();
|
||||
}
|
||||
|
||||
ment_t ment_top[] = {
|
||||
MDEF_HANDLER("Dump keys from SysNAND", dump_sysnand, COLOR_RED),
|
||||
MDEF_HANDLER("Dump keys from emuMMC", dump_emunand, COLOR_ORANGE),
|
||||
MDEF_CAPTION("---------------", COLOR_YELLOW),
|
||||
MDEF_HANDLER("Reboot (Normal)", reboot_normal, COLOR_GREEN),
|
||||
MDEF_HANDLER("Reboot (RCM)", reboot_rcm, COLOR_BLUE),
|
||||
MDEF_HANDLER("Power off", power_off, COLOR_VIOLET),
|
||||
MDEF_END()
|
||||
};
|
||||
|
||||
menu_t menu_top = { ment_top, NULL, 0, 0 };
|
||||
|
||||
#define IPL_STACK_TOP 0x4003F000
|
||||
#define IPL_HEAP_START 0x90020000
|
||||
|
||||
extern void pivot_stack(u32 stack_top);
|
||||
|
||||
void ipl_main() {
|
||||
|
||||
void ipl_main()
|
||||
{
|
||||
config_hw();
|
||||
pivot_stack(IPL_STACK_TOP);
|
||||
heap_init(IPL_HEAP_START);
|
||||
|
||||
set_default_configuration();
|
||||
|
||||
display_init();
|
||||
u32 *fb = display_init_framebuffer();
|
||||
gfx_init_ctxt(fb, 720, 1280, 720);
|
||||
gfx_con_init();
|
||||
display_backlight_pwm_init();
|
||||
|
||||
sd_mount();
|
||||
dump_keys();
|
||||
bpmp_clk_rate_set(BPMP_CLK_SUPER_BOOST);
|
||||
|
||||
h_cfg.emummc_force_disable = emummc_load_cfg();
|
||||
|
||||
if (b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN)
|
||||
{
|
||||
if (!(b_cfg.extra_cfg & EXTRA_CFG_DUMP_EMUMMC))
|
||||
h_cfg.emummc_force_disable = true;
|
||||
dump_keys();
|
||||
}
|
||||
|
||||
if (h_cfg.emummc_force_disable)
|
||||
{
|
||||
ment_top[1].type = MENT_CAPTION;
|
||||
ment_top[1].color = 0xFF555555;
|
||||
ment_top[1].handler = NULL;
|
||||
}
|
||||
|
||||
while (true)
|
||||
tui_do_menu(&menu_top);
|
||||
|
||||
while (true)
|
||||
bpmp_halt();
|
||||
}
|
||||
|
@ -107,17 +107,12 @@ void heap_init(u32 base)
|
||||
|
||||
void *malloc(u32 size)
|
||||
{
|
||||
return (void *)_heap_alloc(&_heap, size, 0x10);
|
||||
}
|
||||
|
||||
void *memalign(u32 align, u32 size)
|
||||
{
|
||||
return (void *)_heap_alloc(&_heap, size, align);
|
||||
return (void *)_heap_alloc(&_heap, size, sizeof(hnode_t));
|
||||
}
|
||||
|
||||
void *calloc(u32 num, u32 size)
|
||||
{
|
||||
void *res = (void *)_heap_alloc(&_heap, num * size, 0x10);
|
||||
void *res = (void *)_heap_alloc(&_heap, num * size, sizeof(hnode_t));
|
||||
memset(res, 0, num * size);
|
||||
return res;
|
||||
}
|
||||
|
@ -23,6 +23,5 @@ void heap_init(u32 base);
|
||||
void *malloc(u32 size);
|
||||
void *calloc(u32 num, u32 size);
|
||||
void free(void *buf);
|
||||
void *memalign(u32 align, u32 size);
|
||||
|
||||
#endif
|
||||
|
@ -127,7 +127,7 @@ void mc_disable_ahb_redirect()
|
||||
void mc_enable()
|
||||
{
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) & 0x1FFFFFFF) | 0x40000000;
|
||||
// Enable MIPI CAL clock.
|
||||
// Enable EMC clock.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFDFFFFFF) | 0x2000000;
|
||||
// Enable MC clock.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFFFFFFFE) | 1;
|
||||
|
@ -39,7 +39,13 @@
|
||||
|
||||
static u32 _get_sdram_id()
|
||||
{
|
||||
return (fuse_read_odm(4) & 0x38) >> 3;
|
||||
u32 sdram_id = (fuse_read_odm(4) & 0x38) >> 3;
|
||||
|
||||
// Check if id is proper.
|
||||
if (sdram_id > 7)
|
||||
sdram_id = 0;
|
||||
|
||||
return sdram_id;
|
||||
}
|
||||
|
||||
static void _sdram_config(const sdram_params_t *params)
|
||||
@ -539,7 +545,7 @@ void sdram_init()
|
||||
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);
|
||||
max77620_regulator_set_voltage(REGULATOR_SD1, 1100000);
|
||||
max77620_regulator_set_voltage(REGULATOR_SD1, 1100000); // Set DRAM voltage.
|
||||
|
||||
PMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel;
|
||||
usleep(params->pmc_vddp_sel_wait);
|
||||
|
@ -1,162 +0,0 @@
|
||||
/*
|
||||
* Battery charger driver for Nintendo Switch's TI BQ24193
|
||||
*
|
||||
* 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 "bq24193.h"
|
||||
#include "../soc/i2c.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
int bq24193_get_property(enum BQ24193_reg_prop prop, int *value)
|
||||
{
|
||||
u8 data;
|
||||
|
||||
switch (prop) {
|
||||
case BQ24193_InputVoltageLimit: // Input voltage limit (mV).
|
||||
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_InputSource);
|
||||
data = (data & BQ24193_INCONFIG_VINDPM_MASK) >> 3;
|
||||
*value += ((data >> 0) & 1) ? 80 : 0;
|
||||
*value += ((data >> 1) & 1) ? 160 : 0;
|
||||
*value += ((data >> 2) & 1) ? 320 : 0;
|
||||
*value += ((data >> 3) & 1) ? 640 : 0;
|
||||
*value += 3880;
|
||||
break;
|
||||
case BQ24193_InputCurrentLimit: // Input current limit (mA).
|
||||
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_InputSource);
|
||||
data &= BQ24193_INCONFIG_INLIMIT_MASK;
|
||||
switch (data)
|
||||
{
|
||||
case 0:
|
||||
*value = 100;
|
||||
break;
|
||||
case 1:
|
||||
*value = 150;
|
||||
break;
|
||||
case 2:
|
||||
*value = 500;
|
||||
break;
|
||||
case 3:
|
||||
*value = 900;
|
||||
break;
|
||||
case 4:
|
||||
*value = 1200;
|
||||
break;
|
||||
case 5:
|
||||
*value = 1500;
|
||||
break;
|
||||
case 6:
|
||||
*value = 2000;
|
||||
break;
|
||||
case 7:
|
||||
*value = 3000;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case BQ24193_SystemMinimumVoltage: // Minimum system voltage limit (mV).
|
||||
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_PORConfig);
|
||||
*value = (data & BQ24193_PORCONFIG_SYSMIN_MASK) >> 1;
|
||||
*value *= 100;
|
||||
*value += 3000;
|
||||
break;
|
||||
case BQ24193_FastChargeCurrentLimit: // Fast charge current limit (mA).
|
||||
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgCurr);
|
||||
data = (data & BQ24193_CHRGCURR_ICHG_MASK) >> 2;
|
||||
*value += ((data >> 0) & 1) ? 64 : 0;
|
||||
*value += ((data >> 1) & 1) ? 128 : 0;
|
||||
*value += ((data >> 2) & 1) ? 256 : 0;
|
||||
*value += ((data >> 3) & 1) ? 512 : 0;
|
||||
*value += ((data >> 4) & 1) ? 1024 : 0;
|
||||
*value += ((data >> 5) & 1) ? 2048 : 0;
|
||||
*value += 512;
|
||||
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgCurr);
|
||||
data &= BQ24193_CHRGCURR_20PCT_MASK;
|
||||
if (data)
|
||||
*value = *value * 20 / 100; // Fast charge current limit is 20%.
|
||||
break;
|
||||
case BQ24193_ChargeVoltageLimit: // Charge voltage limit (mV).
|
||||
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgVolt);
|
||||
data = (data & BQ24193_CHRGVOLT_VREG) >> 2;
|
||||
*value += ((data >> 0) & 1) ? 16 : 0;
|
||||
*value += ((data >> 1) & 1) ? 32 : 0;
|
||||
*value += ((data >> 2) & 1) ? 64 : 0;
|
||||
*value += ((data >> 3) & 1) ? 128 : 0;
|
||||
*value += ((data >> 4) & 1) ? 256 : 0;
|
||||
*value += ((data >> 5) & 1) ? 512 : 0;
|
||||
*value += 3504;
|
||||
break;
|
||||
case BQ24193_RechargeThreshold: // Recharge voltage threshold less than voltage limit (mV).
|
||||
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgVolt);
|
||||
data &= BQ24193_IRTHERMAL_THERM_MASK;
|
||||
if (data)
|
||||
*value = 300;
|
||||
else
|
||||
*value = 100;
|
||||
break;
|
||||
case BQ24193_ThermalRegulation: // Thermal regulation threshold (oC).
|
||||
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_IRCompThermal);
|
||||
data &= BQ24193_IRTHERMAL_THERM_MASK;
|
||||
switch (data)
|
||||
{
|
||||
case 0:
|
||||
*value = 60;
|
||||
break;
|
||||
case 1:
|
||||
*value = 80;
|
||||
break;
|
||||
case 2:
|
||||
*value = 100;
|
||||
break;
|
||||
case 3:
|
||||
*value = 120;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case BQ24193_ChargeStatus: // 0: Not charging, 1: Pre-charge, 2: Fast charging, 3: Charge termination done
|
||||
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_Status);
|
||||
*value = (data & BQ24193_STATUS_CHRG_MASK) >> 4;
|
||||
break;
|
||||
case BQ24193_TempStatus: // 0: Normal, 2: Warm, 3: Cool, 5: Cold, 6: Hot.
|
||||
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_FaultReg);
|
||||
*value = data & BQ24193_FAULT_THERM_MASK;
|
||||
break;
|
||||
case BQ24193_DevID: // Dev ID.
|
||||
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_VendorPart);
|
||||
*value = data & BQ24193_VENDORPART_DEV_MASK;
|
||||
break;
|
||||
case BQ24193_ProductNumber: // Product number.
|
||||
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_VendorPart);
|
||||
*value = (data & BQ24193_VENDORPART_PN_MASK) >> 3;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bq24193_fake_battery_removal()
|
||||
{
|
||||
u8 value;
|
||||
|
||||
// Disable watchdog to keep BATFET disabled.
|
||||
value = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgTermTimer);
|
||||
value &= ~BQ24193_CHRGTERM_WATCHDOG_MASK;
|
||||
i2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgTermTimer, value);
|
||||
|
||||
// Force BATFET to disabled state. This disconnects the battery from the system.
|
||||
value = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_Misc);
|
||||
value |= BQ24193_MISC_BATFET_DI_MASK;
|
||||
i2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_Misc, value);
|
||||
}
|
@ -1,119 +0,0 @@
|
||||
/*
|
||||
* Battery charger driver for Nintendo Switch's TI BQ24193
|
||||
*
|
||||
* 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 __BQ24193_H_
|
||||
#define __BQ24193_H_
|
||||
|
||||
#define BQ24193_I2C_ADDR 0x6B
|
||||
|
||||
// REG 0 masks.
|
||||
#define BQ24193_INCONFIG_INLIMIT_MASK (7<<0)
|
||||
#define BQ24193_INCONFIG_VINDPM_MASK 0x78
|
||||
#define BQ24193_INCONFIG_HIZ_EN_MASK (1<<7)
|
||||
|
||||
// REG 1 masks.
|
||||
#define BQ24193_PORCONFIG_BOOST_MASK (1<<0)
|
||||
#define BQ24193_PORCONFIG_SYSMIN_MASK (7<<1)
|
||||
#define BQ24193_PORCONFIG_CHGCONFIG_MASK (3<<4)
|
||||
#define BQ24193_PORCONFIG_I2CWATCHDOG_MASK (1<<6)
|
||||
#define BQ24193_PORCONFIG_RESET_MASK (1<<7)
|
||||
|
||||
// REG 2 masks.
|
||||
#define BQ24193_CHRGCURR_20PCT_MASK (1<<0)
|
||||
#define BQ24193_CHRGCURR_ICHG_MASK 0xFC
|
||||
|
||||
// REG 3 masks.
|
||||
#define BQ24193_PRECHRG_ITERM 0x0F
|
||||
#define BQ24193_PRECHRG_IPRECHG 0xF0
|
||||
|
||||
// REG 4 masks.
|
||||
#define BQ24193_CHRGVOLT_VTHRES (1<<0)
|
||||
#define BQ24193_CHRGVOLT_BATTLOW (1<<1)
|
||||
#define BQ24193_CHRGVOLT_VREG 0xFC
|
||||
|
||||
// REG 5 masks.
|
||||
#define BQ24193_CHRGTERM_ISET_MASK (1<<0)
|
||||
#define BQ24193_CHRGTERM_CHGTIMER_MASK (3<<1)
|
||||
#define BQ24193_CHRGTERM_ENTIMER_MASK (1<<3)
|
||||
#define BQ24193_CHRGTERM_WATCHDOG_MASK (3<<4)
|
||||
#define BQ24193_CHRGTERM_TERM_ST_MASK (1<<6)
|
||||
#define BQ24193_CHRGTERM_TERM_EN_MASK (1<<7)
|
||||
|
||||
// REG 6 masks.
|
||||
#define BQ24193_IRTHERMAL_THERM_MASK (3<<0)
|
||||
#define BQ24193_IRTHERMAL_VCLAMP_MASK (7<<2)
|
||||
#define BQ24193_IRTHERMAL_BATTCOMP_MASK (7<<5)
|
||||
|
||||
// REG 7 masks.
|
||||
#define BQ24193_MISC_INT_MASK (3<<0)
|
||||
#define BQ24193_MISC_VSET_MASK (1<<4)
|
||||
#define BQ24193_MISC_BATFET_DI_MASK (1<<5)
|
||||
#define BQ24193_MISC_TMR2X_EN_MASK (1<<6)
|
||||
#define BQ24193_MISC_DPDM_EN_MASK (1<<7)
|
||||
|
||||
// REG 8 masks.
|
||||
#define BQ24193_STATUS_VSYS_MASK (1<<0)
|
||||
#define BQ24193_STATUS_THERM_MASK (1<<1)
|
||||
#define BQ24193_STATUS_PG_MASK (1<<2)
|
||||
#define BQ24193_STATUS_DPM_MASK (1<<3)
|
||||
#define BQ24193_STATUS_CHRG_MASK (3<<4)
|
||||
#define BQ24193_STATUS_VBUS_MASK (3<<6)
|
||||
|
||||
// REG 9 masks.
|
||||
#define BQ24193_FAULT_THERM_MASK (7<<0)
|
||||
#define BQ24193_FAULT_BATT_OVP_MASK (1<<3)
|
||||
#define BQ24193_FAULT_CHARGE_MASK (3<<4)
|
||||
#define BQ24193_FAULT_BOOST_MASK (1<<6)
|
||||
#define BQ24193_FAULT_WATCHDOG_MASK (1<<7)
|
||||
|
||||
// REG A masks.
|
||||
#define BQ24193_VENDORPART_DEV_MASK (3<<0)
|
||||
#define BQ24193_VENDORPART_PN_MASK (7<<3)
|
||||
|
||||
enum BQ24193_reg {
|
||||
BQ24193_InputSource = 0x00,
|
||||
BQ24193_PORConfig = 0x01,
|
||||
BQ24193_ChrgCurr = 0x02,
|
||||
BQ24193_PreChrgTerm = 0x03,
|
||||
BQ24193_ChrgVolt = 0x04,
|
||||
BQ24193_ChrgTermTimer = 0x05,
|
||||
BQ24193_IRCompThermal = 0x06,
|
||||
BQ24193_Misc = 0x07,
|
||||
BQ24193_Status = 0x08,
|
||||
BQ24193_FaultReg = 0x09,
|
||||
BQ24193_VendorPart = 0x0A,
|
||||
};
|
||||
|
||||
enum BQ24193_reg_prop {
|
||||
BQ24193_InputVoltageLimit, // REG 0.
|
||||
BQ24193_InputCurrentLimit, // REG 0.
|
||||
BQ24193_SystemMinimumVoltage, // REG 1.
|
||||
BQ24193_FastChargeCurrentLimit, // REG 2.
|
||||
BQ24193_ChargeVoltageLimit, // REG 4.
|
||||
BQ24193_RechargeThreshold, // REG 4.
|
||||
BQ24193_ThermalRegulation, // REG 6.
|
||||
BQ24193_ChargeStatus, // REG 8.
|
||||
BQ24193_TempStatus, // REG 9.
|
||||
BQ24193_DevID, // REG A.
|
||||
BQ24193_ProductNumber, // REG A.
|
||||
};
|
||||
|
||||
int bq24193_get_property(enum BQ24193_reg_prop prop, int *value);
|
||||
void bq24193_fake_battery_removal();
|
||||
|
||||
#endif /* __BQ24193_H_ */
|
@ -43,6 +43,9 @@
|
||||
|
||||
#define MAX17050_VMAX_TOLERANCE 50 /* 50 mV */
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("Os")
|
||||
|
||||
int max17050_get_property(enum MAX17050_reg reg, int *value)
|
||||
{
|
||||
u16 data;
|
||||
@ -259,8 +262,10 @@ int max17050_fix_configuration()
|
||||
/* Init complete, Clear the POR bit */
|
||||
//_max17050_set_por_bit(0); // Should we? Or let the switch to reconfigure POR?
|
||||
|
||||
// Sets POR, BI, BR.
|
||||
// Sets POR, BI, BR.
|
||||
_max17050_set_por_bit(0x8801);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#pragma GCC pop_options
|
@ -130,7 +130,7 @@
|
||||
#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_DISABLE (0 << 1)
|
||||
#define MAX77620_LDO_CFG2_ADE_ENABLE (1 << 1)
|
||||
#define MAX77620_LDO_CFG2_SS_MASK (1 << 0)
|
||||
#define MAX77620_LDO_CFG2_SS_FAST (1 << 0)
|
||||
@ -153,6 +153,24 @@
|
||||
#define MAX77620_REG_PUE_GPIO 0x3E
|
||||
#define MAX77620_REG_PDE_GPIO 0x3F
|
||||
#define MAX77620_REG_AME_GPIO 0x40
|
||||
#define MAX77620_CNFG_GPIO_DRV_MASK (1 << 0)
|
||||
#define MAX77620_CNFG_GPIO_DRV_PUSHPULL (1 << 0)
|
||||
#define MAX77620_CNFG_GPIO_DRV_OPENDRAIN (0 << 0)
|
||||
#define MAX77620_CNFG_GPIO_DIR_MASK (1 << 1)
|
||||
#define MAX77620_CNFG_GPIO_DIR_INPUT (1 << 1)
|
||||
#define MAX77620_CNFG_GPIO_DIR_OUTPUT (0 << 1)
|
||||
#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 << 3)
|
||||
#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_REG_ONOFFCNFG1 0x41
|
||||
#define MAX77620_ONOFFCNFG1_SFT_RST (1 << 7)
|
||||
@ -259,25 +277,6 @@
|
||||
#define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0
|
||||
#define MAX77620_SD_CFG1_FSRADE_SD_ENABLE (1 << 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_LVL2_GPIO_EDGE0 (1 << 0)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE1 (1 << 1)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE2 (1 << 2)
|
||||
|
@ -24,16 +24,16 @@
|
||||
* Switch Power domains (max77620):
|
||||
* Name | Usage | uV step | uV min | uV default | uV max | Init
|
||||
*-------+---------------+---------+--------+------------+---------+------------------
|
||||
* sd0 | core | 12500 | 600000 | 625000 | 1400000 | 1.125V (pkg1.1)
|
||||
* sd0 | SoC | 12500 | 600000 | 625000 | 1400000 | 1.125V (pkg1.1)
|
||||
* sd1 | SDRAM | 12500 | 600000 | 1125000 | 1125000 | 1.1V (pkg1.1)
|
||||
* sd2 | ldo{0-1, 7-8} | 12500 | 600000 | 1325000 | 1350000 | 1.325V (pcv)
|
||||
* sd3 | 1.8V general | 12500 | 600000 | 1800000 | 1800000 |
|
||||
* 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 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv)
|
||||
* ldo3 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv)
|
||||
* ldo4 | RTC | 12500 | 800000 | 850000 | 850000 |
|
||||
* ldo5 | GC ASIC | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv)
|
||||
* 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 |
|
||||
@ -71,6 +71,8 @@
|
||||
/* MAX77621_VOUT */
|
||||
#define MAX77621_VOUT_ENABLE (1 << 7)
|
||||
#define MAX77621_VOUT_MASK 0x7F
|
||||
#define MAX77621_VOUT_0_95V 0x37
|
||||
#define MAX77621_VOUT_1_09V 0x4F
|
||||
|
||||
/* MAX77621_VOUT_DVC_DVS */
|
||||
#define MAX77621_DVS_VOUT_MASK 0x7F
|
||||
|
@ -36,7 +36,7 @@ void max77620_rtc_get_time(rtc_time_t *time)
|
||||
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;
|
||||
|
||||
@ -52,7 +52,7 @@ void max77620_rtc_get_time(rtc_time_t *time)
|
||||
}
|
||||
|
||||
// Get date.
|
||||
time->date = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_DATE_REG) & 0x1f;
|
||||
time->day = 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;
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ typedef struct _rtc_time_t {
|
||||
u8 sec;
|
||||
u8 min;
|
||||
u8 hour;
|
||||
u8 date;
|
||||
u8 day;
|
||||
u8 month;
|
||||
u16 year;
|
||||
} rtc_time_t;
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include "../sec/se.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../soc/bpmp.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../sec/se_t210.h"
|
||||
#include "../utils/util.h"
|
||||
@ -108,10 +109,14 @@ static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src
|
||||
|
||||
SE(SE_ERR_STATUS_0) = SE(SE_ERR_STATUS_0);
|
||||
SE(SE_INT_STATUS_REG_OFFSET) = SE(SE_INT_STATUS_REG_OFFSET);
|
||||
SE(SE_OPERATION_REG_OFFSET) = SE_OPERATION(op);
|
||||
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY);
|
||||
|
||||
SE(SE_OPERATION_REG_OFFSET) = SE_OPERATION(op);
|
||||
int res = _se_wait();
|
||||
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY);
|
||||
|
||||
if (src)
|
||||
free(ll_src);
|
||||
if (dst)
|
||||
@ -133,7 +138,7 @@ static int _se_execute_one_block(u32 op, void *dst, u32 dst_size, const void *sr
|
||||
memcpy(block, src, src_size);
|
||||
int res = _se_execute(op, block, 0x10, block, 0x10);
|
||||
memcpy(dst, block, dst_size);
|
||||
|
||||
|
||||
free(block);
|
||||
return res;
|
||||
}
|
||||
@ -227,18 +232,7 @@ int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src,
|
||||
|
||||
int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src)
|
||||
{
|
||||
if (enc)
|
||||
{
|
||||
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY);
|
||||
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT);
|
||||
}
|
||||
else
|
||||
{
|
||||
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_MEMORY);
|
||||
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_DECRYPT);
|
||||
}
|
||||
SE(SE_BLOCK_COUNT_REG_OFFSET) = 0;
|
||||
return _se_execute(OP_START, dst, 0x10, src, 0x10);
|
||||
return se_aes_crypt_ecb(ks, enc, dst, 0x10, src, 0x10);
|
||||
}
|
||||
|
||||
int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr)
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "../sec/tsec.h"
|
||||
#include "../sec/tsec_t210.h"
|
||||
#include "../sec/se_t210.h"
|
||||
#include "../soc/bpmp.h"
|
||||
#include "../soc/clock.h"
|
||||
#include "../soc/smmu.h"
|
||||
#include "../soc/t210.h"
|
||||
@ -28,7 +29,7 @@
|
||||
#include "../mem/mc.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
/* #include "../gfx/gfx.h" */
|
||||
// #include "../gfx/gfx.h"
|
||||
|
||||
static int _tsec_dma_wait_idle()
|
||||
{
|
||||
@ -64,8 +65,12 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
u32 *pdir, *car, *fuse, *pmc, *flowctrl, *se, *mc, *iram, *evec;
|
||||
u32 *pkg11_magic_off;
|
||||
|
||||
//Enable clocks.
|
||||
bpmp_mmu_disable();
|
||||
bpmp_clk_rate_set(BPMP_CLK_NORMAL);
|
||||
|
||||
// Enable clocks.
|
||||
clock_enable_host1x();
|
||||
usleep(2);
|
||||
clock_enable_tsec();
|
||||
clock_enable_sor_safe();
|
||||
clock_enable_sor0();
|
||||
@ -118,7 +123,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
{
|
||||
// Init SMMU translation for TSEC.
|
||||
pdir = smmu_init_for_tsec();
|
||||
smmu_init(tsec_ctxt->secmon_base);
|
||||
smmu_init(0x4002B000);
|
||||
// Enable SMMU
|
||||
if (!smmu_is_used())
|
||||
smmu_enable();
|
||||
@ -149,7 +154,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
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);
|
||||
@ -161,7 +166,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
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));
|
||||
pkg11_magic_off = (u32 *)(iram + (0x7000 / 4));
|
||||
smmu_map(pdir, 0x40010000, (u32)iram, 0x30, _READABLE | _WRITABLE | _NONSECURE);
|
||||
|
||||
// Exception vectors
|
||||
@ -170,7 +175,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
}
|
||||
|
||||
//Execute firmware.
|
||||
HOST1X(0x3300) = 0x34C2E1DA;
|
||||
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA;
|
||||
TSEC(TSEC_STATUS) = 0;
|
||||
TSEC(TSEC_BOOTKEYVER) = 1; // HOS uses key version 1.
|
||||
TSEC(TSEC_BOOTVEC) = 0;
|
||||
@ -187,10 +192,11 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
{
|
||||
smmu_flush_all();
|
||||
|
||||
if (k == se[SE_KEYTABLE_DATA0_REG_OFFSET / 4])
|
||||
continue;
|
||||
k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4];
|
||||
key[kidx++] = k;
|
||||
if (k != se[SE_KEYTABLE_DATA0_REG_OFFSET / 4])
|
||||
{
|
||||
k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4];
|
||||
key[kidx++] = k;
|
||||
}
|
||||
|
||||
// Failsafe.
|
||||
if ((u32)get_tmr_us() - start > 125000)
|
||||
@ -210,7 +216,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
|
||||
memcpy(tsec_keys, &key, 0x20);
|
||||
memcpy(tsec_ctxt->pkg1, iram, 0x30000);
|
||||
|
||||
|
||||
smmu_deinit_for_tsec();
|
||||
|
||||
// for (int i = 0; i < kidx; i++)
|
||||
@ -246,7 +252,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
}
|
||||
|
||||
//Fetch result.
|
||||
HOST1X(0x3300) = 0;
|
||||
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 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);
|
||||
@ -271,7 +277,8 @@ out:;
|
||||
clock_disable_sor0();
|
||||
clock_disable_sor_safe();
|
||||
clock_disable_tsec();
|
||||
clock_disable_host1x();
|
||||
bpmp_mmu_enable();
|
||||
bpmp_clk_rate_set(BPMP_CLK_SUPER_BOOST);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -20,15 +20,31 @@
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
#define TSEC_KEY_DATA_ADDR 0x300
|
||||
|
||||
typedef struct _tsec_ctxt_t
|
||||
{
|
||||
void *fw;
|
||||
u32 size;
|
||||
void *pkg1;
|
||||
u32 pkg11_off;
|
||||
u32 secmon_base;
|
||||
} tsec_ctxt_t;
|
||||
|
||||
typedef struct _tsec_key_data_t
|
||||
{
|
||||
u8 debug_key[0x10];
|
||||
u8 blob0_auth_hash[0x10];
|
||||
u8 blob1_auth_hash[0x10];
|
||||
u8 blob2_auth_hash[0x10];
|
||||
u8 blob2_aes_iv[0x10];
|
||||
u8 hovi_eks_seed[0x10];
|
||||
u8 hovi_common_seed[0x10];
|
||||
u32 blob0_size;
|
||||
u32 blob1_size;
|
||||
u32 blob2_size;
|
||||
u32 blob3_size;
|
||||
u32 blob4_size;
|
||||
} tsec_key_data_t;
|
||||
|
||||
int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt);
|
||||
|
||||
#endif
|
||||
|
249
source/soc/bpmp.c
Normal file
249
source/soc/bpmp.c
Normal file
@ -0,0 +1,249 @@
|
||||
/*
|
||||
* BPMP-Lite Cache/MMU and Frequency driver for Tegra X1
|
||||
*
|
||||
* 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 "bpmp.h"
|
||||
#include "clock.h"
|
||||
#include "t210.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
#define BPMP_CACHE_CONFIG 0x0
|
||||
#define CFG_ENABLE (1 << 0)
|
||||
#define CFG_FORCE_WRITE_THROUGH (1 << 3)
|
||||
#define CFG_DISABLE_WRITE_BUFFER (1 << 10)
|
||||
#define CFG_DISABLE_READ_BUFFER (1 << 11)
|
||||
#define CFG_FULL_LINE_DIRTY (1 << 13)
|
||||
#define CFG_TAG_CHK_ABRT_ON_ERR (1 << 14)
|
||||
#define BPMP_CACHE_LOCK 0x4
|
||||
#define BPMP_CACHE_SIZE 0xC
|
||||
#define BPMP_CACHE_LFSR 0x10
|
||||
#define BPMP_CACHE_TAG_STATUS 0x14
|
||||
#define BPMP_CACHE_CLKEN_OVERRIDE 0x18
|
||||
#define BPMP_CACHE_MAINT_ADDR 0x20
|
||||
#define BPMP_CACHE_MAINT_DATA 0x24
|
||||
#define BPMP_CACHE_MAINT_REQ 0x28
|
||||
#define MAINT_REQ_WAY_BITMAP(x) ((x) << 8)
|
||||
|
||||
#define BPMP_CACHE_INT_MASK 0x40
|
||||
#define BPMP_CACHE_INT_CLEAR 0x44
|
||||
#define INT_CLR_MAINT_DONE (1 << 0)
|
||||
|
||||
#define BPMP_CACHE_INT_RAW_EVENT 0x48
|
||||
#define INT_RAW_EVENT_MAINT_DONE (1 << 0)
|
||||
#define BPMP_CACHE_INT_STATUS 0x4C
|
||||
|
||||
#define BPMP_CACHE_RB_CFG 0x80
|
||||
#define BPMP_CACHE_WB_CFG 0x84
|
||||
|
||||
#define BPMP_CACHE_MMU_FALLBACK_ENTRY 0xA0
|
||||
#define BPMP_CACHE_MMU_SHADOW_COPY_MASK 0xA4
|
||||
#define BPMP_CACHE_MMU_CFG 0xAC
|
||||
#define MMU_CFG_SEQ_EN (1 << 1)
|
||||
#define MMU_CFG_TLB_EN (1 << 2)
|
||||
#define MMU_CFG_ABORT_STORE_LAST (1 << 4)
|
||||
#define BPMP_CACHE_MMU_CMD 0xB0
|
||||
#define MMU_CMD_NOP 0
|
||||
#define MMU_CMD_INIT 1
|
||||
#define MMU_CMD_COPY_SHADOW 2
|
||||
#define BPMP_CACHE_MMU_ABORT_STAT 0xB4
|
||||
#define BPMP_CACHE_MMU_ABORT_ADDR 0xB8
|
||||
#define BPMP_CACHE_MMU_ACTIVE_ENTRIES 0xBC
|
||||
|
||||
#define BPMP_MMU_SHADOW_ENTRY_BASE (BPMP_CACHE_BASE + 0x400)
|
||||
#define BPMP_MMU_MAIN_ENTRY_BASE (BPMP_CACHE_BASE + 0x800)
|
||||
#define MMU_ENTRY_ADDR_MASK 0xFFFFFFE0
|
||||
|
||||
#define MMU_EN_CACHED (1 << 0)
|
||||
#define MMU_EN_EXEC (1 << 1)
|
||||
#define MMU_EN_READ (1 << 2)
|
||||
#define MMU_EN_WRITE (1 << 3)
|
||||
|
||||
bpmp_mmu_entry_t mmu_entries[] =
|
||||
{
|
||||
{ 0x80000000, 0xFFFFFFFF, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true },
|
||||
{ IPL_LOAD_ADDR, 0x40040000, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true }
|
||||
};
|
||||
|
||||
void bpmp_mmu_maintenance(u32 op)
|
||||
{
|
||||
if (!(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE))
|
||||
return;
|
||||
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = INT_CLR_MAINT_DONE;
|
||||
|
||||
// This is a blocking operation.
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MAINT_REQ) = MAINT_REQ_WAY_BITMAP(0xF) | op;
|
||||
|
||||
while(!(BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT) & INT_RAW_EVENT_MAINT_DONE))
|
||||
;
|
||||
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT);
|
||||
}
|
||||
|
||||
void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply)
|
||||
{
|
||||
if (idx > 31)
|
||||
return;
|
||||
|
||||
volatile bpmp_mmu_entry_t *mmu_entry = (bpmp_mmu_entry_t *)(BPMP_MMU_SHADOW_ENTRY_BASE + sizeof(bpmp_mmu_entry_t) * idx);
|
||||
|
||||
if (entry->enable)
|
||||
{
|
||||
mmu_entry->min_addr = entry->min_addr & MMU_ENTRY_ADDR_MASK;
|
||||
mmu_entry->max_addr = entry->max_addr & MMU_ENTRY_ADDR_MASK;
|
||||
mmu_entry->attr = entry->attr;
|
||||
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_SHADOW_COPY_MASK) |= (1 << idx);
|
||||
|
||||
if (apply)
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_COPY_SHADOW;
|
||||
}
|
||||
}
|
||||
|
||||
void bpmp_mmu_enable()
|
||||
{
|
||||
if (BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE)
|
||||
return;
|
||||
|
||||
// Init BPMP MMU.
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_INIT;
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_FALLBACK_ENTRY) = MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC; // RWX for non-defined regions.
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CFG) = MMU_CFG_SEQ_EN | MMU_CFG_TLB_EN | MMU_CFG_ABORT_STORE_LAST;
|
||||
|
||||
// Init BPMP MMU entries.
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_SHADOW_COPY_MASK) = 0;
|
||||
for (u32 idx = 0; idx < (sizeof(mmu_entries) / sizeof(bpmp_mmu_entry_t)); idx++)
|
||||
bpmp_mmu_set_entry(idx, &mmu_entries[idx], false);
|
||||
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_COPY_SHADOW;
|
||||
|
||||
// Invalidate cache.
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY);
|
||||
|
||||
// Enable cache.
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = CFG_ENABLE | CFG_FORCE_WRITE_THROUGH | CFG_TAG_CHK_ABRT_ON_ERR;
|
||||
|
||||
// HW bug. Invalidate cache again.
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY);
|
||||
}
|
||||
|
||||
void bpmp_mmu_disable()
|
||||
{
|
||||
if (!(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE))
|
||||
return;
|
||||
|
||||
// Clean and invalidate cache.
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY);
|
||||
|
||||
// Disable cache.
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = 0;
|
||||
|
||||
// HW bug. Invalidate cache again.
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY);
|
||||
}
|
||||
|
||||
const u8 pllc4_divn[] = {
|
||||
0, // BPMP_CLK_NORMAL: 408MHz 0% - 136MHz APB.
|
||||
85, // BPMP_CLK_LOW_BOOST: 544MHz 33% - 136MHz APB.
|
||||
90, // BPMP_CLK_MID_BOOST: 576MHz 41% - 144MHz APB.
|
||||
94 // BPMP_CLK_SUPER_BOOST: 602MHz 48% - 150MHz APB.
|
||||
//95 // BPMP_CLK_SUPER_BOOST: 608MHz 49% - 152MHz APB.
|
||||
};
|
||||
|
||||
bpmp_freq_t bpmp_clock_set = BPMP_CLK_NORMAL;
|
||||
|
||||
void bpmp_clk_rate_set(bpmp_freq_t fid)
|
||||
{
|
||||
if (fid > (BPMP_CLK_MAX - 1))
|
||||
fid = BPMP_CLK_MAX - 1;
|
||||
|
||||
if (bpmp_clock_set == fid)
|
||||
return;
|
||||
|
||||
if (fid)
|
||||
{
|
||||
if (bpmp_clock_set)
|
||||
{
|
||||
// Restore to PLLP source during PLLC4 configuration.
|
||||
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // PLLP_OUT.
|
||||
// Wait a bit for clock source change.
|
||||
msleep(10);
|
||||
}
|
||||
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLC4_MISC) = PLLC4_MISC_EN_LCKDET;
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) = 4 | (pllc4_divn[fid] << 8) | PLL_BASE_ENABLE; // DIVM: 4, DIVP: 1.
|
||||
|
||||
while (!(CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) & PLLC4_BASE_LOCK))
|
||||
;
|
||||
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLC4_OUT) = (1 << 8) | PLLC4_OUT3_CLKEN; // 1.5 div.
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLC4_OUT) |= PLLC4_OUT3_RSTN_CLR; // Get divider out of reset.
|
||||
|
||||
// Wait a bit for PLLC4 to stabilize.
|
||||
msleep(10);
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 3; // PCLK = HCLK / 4.
|
||||
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003323; // PLLC4_OUT3.
|
||||
|
||||
bpmp_clock_set = fid;
|
||||
}
|
||||
else
|
||||
{
|
||||
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // PLLP_OUT.
|
||||
|
||||
// Wait a bit for clock source change.
|
||||
msleep(10);
|
||||
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // PCLK = HCLK / 3.
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLL_BASE_ENABLE;
|
||||
bpmp_clock_set = BPMP_CLK_NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
// The following functions halt BPMP to reduce power while sleeping.
|
||||
// They are not as accurate as RTC at big values but they guarantee time+ delay.
|
||||
void bpmp_usleep(u32 us)
|
||||
{
|
||||
u32 delay;
|
||||
|
||||
// Each iteration takes 1us.
|
||||
while (us)
|
||||
{
|
||||
delay = (us > HALT_COP_MAX_CNT) ? HALT_COP_MAX_CNT : us;
|
||||
us -= delay;
|
||||
|
||||
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_USEC | delay;
|
||||
}
|
||||
}
|
||||
|
||||
void bpmp_msleep(u32 ms)
|
||||
{
|
||||
u32 delay;
|
||||
|
||||
// Iteration time is variable. ~200 - 1000us.
|
||||
while (ms)
|
||||
{
|
||||
delay = (ms > HALT_COP_MAX_CNT) ? HALT_COP_MAX_CNT : ms;
|
||||
ms -= delay;
|
||||
|
||||
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_MSEC | delay;
|
||||
}
|
||||
}
|
||||
|
||||
void bpmp_halt()
|
||||
{
|
||||
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_JTAG;
|
||||
}
|
54
source/soc/bpmp.h
Normal file
54
source/soc/bpmp.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* BPMP-Lite Cache/MMU and Frequency driver for Tegra X1
|
||||
*
|
||||
* 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 _BPMP_H_
|
||||
#define _BPMP_H_
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
#define BPMP_MMU_MAINT_CLEAN_WAY 17
|
||||
#define BPMP_MMU_MAINT_INVALID_WAY 18
|
||||
#define BPMP_MMU_MAINT_CLN_INV_WAY 19
|
||||
|
||||
typedef struct _bpmp_mmu_entry_t
|
||||
{
|
||||
u32 min_addr;
|
||||
u32 max_addr;
|
||||
u32 attr;
|
||||
u32 enable;
|
||||
} bpmp_mmu_entry_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BPMP_CLK_NORMAL, // 408MHz 0% - 136MHz APB.
|
||||
BPMP_CLK_LOW_BOOST, // 544MHz 33% - 136MHz APB.
|
||||
BPMP_CLK_MID_BOOST, // 576MHz 41% - 144MHz APB.
|
||||
BPMP_CLK_SUPER_BOOST, // 608MHz 49% - 152MHz APB.
|
||||
BPMP_CLK_MAX
|
||||
} bpmp_freq_t;
|
||||
|
||||
void bpmp_mmu_maintenance(u32 op);
|
||||
void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply);
|
||||
void bpmp_mmu_enable();
|
||||
void bpmp_mmu_disable();
|
||||
void bpmp_clk_rate_set(bpmp_freq_t fid);
|
||||
void bpmp_usleep(u32 us);
|
||||
void bpmp_msleep(u32 ms);
|
||||
void bpmp_halt();
|
||||
|
||||
#endif
|
@ -22,57 +22,58 @@
|
||||
/* 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, 2 },
|
||||
/* UART B */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, 7, 0, 2 },
|
||||
/* UART C */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, 23, 0, 2 },
|
||||
/* UART D */ { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_UARTD, 1, 0, 2 },
|
||||
/* UART E */ { CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE, 20, 0, 2 }
|
||||
};
|
||||
|
||||
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 },
|
||||
/* I2C1 */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, 12, 6, 0 }, // 0, 19 }, // 100KHz
|
||||
/* 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 },
|
||||
/* I2C5 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, 15, 6, 0 }, // 0, 4 }, // 400KHz
|
||||
/* 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
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_SE, 31, 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_tzram = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_NO_SOURCE, 30, 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
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, 28, 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
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_TSEC, 19, 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
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_NO_SOURCE, 30, 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
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_NO_SOURCE, 22, 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
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, 23, 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
|
||||
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_NO_SOURCE, 0x1B, 0, 0
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_W, CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_NO_SOURCE, 27, 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
|
||||
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
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, 17, 6, 4 // Freference: 6.2MHz.
|
||||
};
|
||||
|
||||
void clock_enable(const clock_t *clk)
|
||||
@ -123,9 +124,9 @@ void clock_enable_se()
|
||||
clock_enable(&_clock_se);
|
||||
}
|
||||
|
||||
void clock_enable_unk2()
|
||||
void clock_enable_tzram()
|
||||
{
|
||||
clock_enable(&_clock_unk2);
|
||||
clock_enable(&_clock_tzram);
|
||||
}
|
||||
|
||||
void clock_enable_host1x()
|
||||
@ -364,48 +365,50 @@ static void _clock_sdmmc_clear_enable(u32 id)
|
||||
|
||||
static u32 _clock_sdmmc_table[8] = { 0 };
|
||||
|
||||
#define PLLP_OUT0 0x0
|
||||
static int _clock_sdmmc_config_clock_source_inner(u32 *pout, u32 id, u32 val)
|
||||
{
|
||||
u32 divisor = 0;
|
||||
u32 source = 0;
|
||||
u32 source = PLLP_OUT0;
|
||||
|
||||
// Get IO clock divisor.
|
||||
switch (val)
|
||||
{
|
||||
case 25000:
|
||||
*pout = 24728;
|
||||
divisor = 31;
|
||||
divisor = 31; // 16.5 div.
|
||||
break;
|
||||
case 26000:
|
||||
*pout = 25500;
|
||||
divisor = 30;
|
||||
divisor = 30; // 16 div.
|
||||
break;
|
||||
case 40800:
|
||||
*pout = 40800;
|
||||
divisor = 18;
|
||||
divisor = 18; // 10 div.
|
||||
break;
|
||||
case 50000:
|
||||
*pout = 48000;
|
||||
divisor = 15;
|
||||
divisor = 15; // 8.5 div.
|
||||
break;
|
||||
case 52000:
|
||||
*pout = 51000;
|
||||
divisor = 14;
|
||||
divisor = 14; // 8 div.
|
||||
break;
|
||||
case 100000:
|
||||
*pout = 90667;
|
||||
divisor = 7;
|
||||
divisor = 7; // 4.5 div.
|
||||
break;
|
||||
case 200000:
|
||||
*pout = 163200;
|
||||
divisor = 3;
|
||||
divisor = 3; // 2.5 div.
|
||||
break;
|
||||
case 208000:
|
||||
*pout = 204000;
|
||||
divisor = 2;
|
||||
divisor = 2; // 2 div.
|
||||
break;
|
||||
default:
|
||||
*pout = 24728;
|
||||
divisor = 31;
|
||||
divisor = 31; // 16.5 div.
|
||||
}
|
||||
|
||||
_clock_sdmmc_table[2 * id] = val;
|
||||
@ -414,16 +417,16 @@ static int _clock_sdmmc_config_clock_source_inner(u32 *pout, u32 id, u32 val)
|
||||
switch (id)
|
||||
{
|
||||
case SDMMC_1:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1) = source | divisor;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1) = (source << 29) | divisor;
|
||||
break;
|
||||
case SDMMC_2:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2) = source | divisor;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2) = (source << 29) | divisor;
|
||||
break;
|
||||
case SDMMC_3:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3) = source | divisor;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3) = (source << 29) | divisor;
|
||||
break;
|
||||
case SDMMC_4:
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4) = source | divisor;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4) = (source << 29) | divisor;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,8 @@
|
||||
#define CLK_RST_CONTROLLER_PLLM_MISC2 0x9C
|
||||
#define CLK_RST_CONTROLLER_PLLP_BASE 0xA0
|
||||
#define CLK_RST_CONTROLLER_PLLD_BASE 0xD0
|
||||
#define CLK_RST_CONTROLLER_PLLD_MISC1 0xD8
|
||||
#define CLK_RST_CONTROLLER_PLLD_MISC 0xDC
|
||||
#define CLK_RST_CONTROLLER_PLLX_BASE 0xE0
|
||||
#define CLK_RST_CONTROLLER_PLLX_MISC 0xE4
|
||||
#define CLK_RST_CONTROLLER_PLLE_BASE 0xE8
|
||||
@ -50,6 +52,7 @@
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_PWM 0x110
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C1 0x124
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C5 0x128
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_DISP1 0x138
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_VI 0x148
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1 0x150
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2 0x154
|
||||
@ -57,11 +60,13 @@
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTA 0x178
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTB 0x17C
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X 0x180
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C2 0x198
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC 0x19C
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTC 0x1A0
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C3 0x1B8
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3 0x1BC
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTD 0x1C0
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_CSITE 0x1D4
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC 0x19C
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_TSEC 0x1F4
|
||||
#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X 0x280
|
||||
#define CLK_RST_CONTROLLER_CLK_ENB_X_SET 0x284
|
||||
@ -95,9 +100,12 @@
|
||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC 0x3A0
|
||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD 0x3A4
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT 0x3B4
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C4 0x3C4
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SYS 0x400
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SOR1 0x410
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SE 0x42C
|
||||
#define CLK_RST_CONTROLLER_CLK_ENB_V_SET 0x440
|
||||
#define CLK_RST_CONTROLLER_CLK_ENB_V_CLR 0x444
|
||||
#define CLK_RST_CONTROLLER_CLK_ENB_W_SET 0x448
|
||||
#define CLK_RST_CONTROLLER_CLK_ENB_W_CLR 0x44C
|
||||
#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET 0x450
|
||||
@ -108,16 +116,30 @@
|
||||
#define CLK_RST_CONTROLLER_PLLX_MISC_3 0x518
|
||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE 0x554
|
||||
#define CLK_RST_CONTROLLER_SPARE_REG0 0x55C
|
||||
#define CLK_RST_CONTROLLER_PLLC4_BASE 0x5A4
|
||||
#define CLK_RST_CONTROLLER_PLLC4_MISC 0x5A8
|
||||
#define CLK_RST_CONTROLLER_PLLC4_OUT 0x5E4
|
||||
#define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP 0x620
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C6 0x65C
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL 0x664
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIP_CAL 0x66C
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL 0x66C
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM 0x694
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_NVENC 0x6A0
|
||||
#define CLK_RST_CONTROLLER_SE_SUPER_CLK_DIVIDER 0x704
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE 0x710
|
||||
|
||||
#define CLK_NO_SOURCE 0x0
|
||||
|
||||
/*! PLL control and status bits */
|
||||
#define PLL_BASE_ENABLE (1 << 30)
|
||||
|
||||
#define PLLC4_MISC_EN_LCKDET (1 << 30)
|
||||
#define PLLC4_BASE_LOCK (1 << 27)
|
||||
#define PLLC4_BASE_IDDQ (1 << 18)
|
||||
#define PLLC4_OUT3_CLKEN (1 << 1)
|
||||
#define PLLC4_OUT3_RSTN_CLR (1 << 0)
|
||||
|
||||
/*! Generic clock descriptor. */
|
||||
typedef struct _clock_t
|
||||
{
|
||||
@ -139,7 +161,7 @@ void clock_enable_uart(u32 idx);
|
||||
void clock_enable_i2c(u32 idx);
|
||||
void clock_disable_i2c(u32 idx);
|
||||
void clock_enable_se();
|
||||
void clock_enable_unk2();
|
||||
void clock_enable_tzram();
|
||||
void clock_enable_host1x();
|
||||
void clock_disable_host1x();
|
||||
void clock_enable_tsec();
|
||||
|
@ -32,18 +32,21 @@ void _cluster_enable_power()
|
||||
// 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);
|
||||
MAX77621_AD_ENABLE | MAX77621_NFSR_ENABLE | MAX77621_SNS_ENABLE | MAX77621_RAMP_12mV_PER_US);
|
||||
// 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);
|
||||
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);
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V);
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V);
|
||||
}
|
||||
|
||||
int _cluster_pmc_enable_partition(u32 part, u32 toggle, bool enable)
|
||||
int _cluster_pmc_enable_partition(u32 part, int enable)
|
||||
{
|
||||
// Check if the partition has already been turned on.
|
||||
if (enable && PMC(APBDEV_PMC_PWRGATE_STATUS) & part)
|
||||
u32 part_mask = 1 << part;
|
||||
u32 desired_state = enable << part;
|
||||
|
||||
// Check if the partition has the state we want.
|
||||
if ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) == desired_state)
|
||||
return 1;
|
||||
|
||||
u32 i = 5001;
|
||||
@ -55,12 +58,13 @@ int _cluster_pmc_enable_partition(u32 part, u32 toggle, bool enable)
|
||||
return 0;
|
||||
}
|
||||
|
||||
PMC(APBDEV_PMC_PWRGATE_TOGGLE) = toggle | (enable ? 0x100 : 0);
|
||||
// Toggle power gating.
|
||||
PMC(APBDEV_PMC_PWRGATE_TOGGLE) = part | 0x100;
|
||||
|
||||
i = 5001;
|
||||
while (i > 0)
|
||||
{
|
||||
if (PMC(APBDEV_PMC_PWRGATE_STATUS) & part)
|
||||
if ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) == desired_state)
|
||||
break;
|
||||
usleep(1);
|
||||
i--;
|
||||
@ -103,11 +107,11 @@ void cluster_boot_cpu0(u32 entry)
|
||||
CLOCK(CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2) &= 0xFFFFF000;
|
||||
|
||||
// Enable CPU rail.
|
||||
_cluster_pmc_enable_partition(1, 0, true);
|
||||
_cluster_pmc_enable_partition(0, 1);
|
||||
// Enable cluster 0 non-CPU.
|
||||
_cluster_pmc_enable_partition(0x8000, 15, true);
|
||||
_cluster_pmc_enable_partition(15, 1);
|
||||
// Enable CE0.
|
||||
_cluster_pmc_enable_partition(0x4000, 14, true);
|
||||
_cluster_pmc_enable_partition(14, 1);
|
||||
|
||||
// Request and wait for RAM repair.
|
||||
FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) = 1;
|
||||
@ -117,10 +121,10 @@ void cluster_boot_cpu0(u32 entry)
|
||||
EXCP_VEC(EVP_CPU_RESET_VECTOR) = 0;
|
||||
|
||||
// Set reset vector.
|
||||
SB(SB_AA64_RESET_LOW) = entry | 1;
|
||||
SB(SB_AA64_RESET_LOW) = entry | SB_AA64_RST_AARCH64_MODE_EN;
|
||||
SB(SB_AA64_RESET_HIGH) = 0;
|
||||
// Non-secure reset vector write disable.
|
||||
SB(SB_CSR) = 2;
|
||||
SB(SB_CSR) = SB_CSR_NS_RST_VEC_WR_DIS;
|
||||
(void)SB(SB_CSR);
|
||||
|
||||
// Clear MSELECT reset.
|
||||
|
@ -19,19 +19,6 @@
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
/*! Flow controller registers. */
|
||||
#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
|
||||
#define FLOW_CTLR_CPU2_CSR 0x20
|
||||
#define FLOW_CTLR_CPU3_CSR 0x28
|
||||
#define FLOW_CTLR_RAM_REPAIR 0x40
|
||||
#define FLOW_CTLR_BPMP_CLUSTER_CONTROL 0x98
|
||||
|
||||
void cluster_boot_cpu0(u32 entry);
|
||||
|
||||
#endif
|
||||
|
@ -18,6 +18,14 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "hw_init.h"
|
||||
#include "bpmp.h"
|
||||
#include "clock.h"
|
||||
#include "fuse.h"
|
||||
#include "gpio.h"
|
||||
#include "i2c.h"
|
||||
#include "pinmux.h"
|
||||
#include "pmc.h"
|
||||
#include "t210.h"
|
||||
#include "../gfx/di.h"
|
||||
#include "../mem/mc.h"
|
||||
#include "../mem/sdram.h"
|
||||
@ -25,35 +33,42 @@
|
||||
#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 "../storage/sdmmc.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
extern sdmmc_t sd_sdmmc;
|
||||
extern boot_cfg_t b_cfg;
|
||||
|
||||
/*
|
||||
* CLK_OSC - 38.4 MHz crystal.
|
||||
* CLK_M - 19.2 MHz (osc/2).
|
||||
* CLK_S - 32.768 KHz (from PMIC).
|
||||
* SCLK - 204MHz init (-> 408MHz -> OC).
|
||||
* HCLK - 204MHz init (-> 408MHz -> OC).
|
||||
* PCLK - 68MHz init (-> 136MHz -> OC/4).
|
||||
*/
|
||||
|
||||
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;
|
||||
CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) = (CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) & 0xFFFFFFF3) | 4; // Set CLK_M_DIVISOR to 2.
|
||||
SYSCTR0(SYSCTR0_CNTFID0) = 19200000; // Set counter frequency.
|
||||
TMR(TIMERUS_USEC_CFG) = 0x45F; // For 19.2MHz clk_m.
|
||||
CLOCK(CLK_RST_CONTROLLER_OSC_CTRL) = 0x50000071; // Set OSC to 38.4MHz and drive strength.
|
||||
|
||||
PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFFFFF81) | 0xE; // Set LP0 OSC drive strength.
|
||||
PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFBFFFFF) | PMC_OSC_EDPD_OVER_OSC_CTRL_OVER;
|
||||
PMC(APBDEV_PMC_CNTRL2) = (PMC(APBDEV_PMC_CNTRL2) & 0xFFFFEFFF) | PMC_CNTRL2_HOLD_CKE_LOW_EN;
|
||||
PMC(APBDEV_PMC_SCRATCH188) = (PMC(APBDEV_PMC_SCRATCH188) & 0xFCFFFFFF) | (4 << 23); // LP0 EMC2TMC_CFG_XM2COMP_PU_VREF_SEL_RANGE.
|
||||
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 0x10; // Set HCLK div to 2 and PCLK div to 1.
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) &= 0xBFFFFFFF; // PLLMB disable.
|
||||
|
||||
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;
|
||||
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SYS) = 0; // Set SCLK div to 1.
|
||||
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20004444; // Set clk source to Run and PLLP_OUT2 (204MHz).
|
||||
CLOCK(CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER) = 0x80000000; // Enable SUPER_SDIV to 1.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // Set HCLK div to 1 and PCLK div to 3.
|
||||
}
|
||||
|
||||
void _config_gpios()
|
||||
@ -61,11 +76,22 @@ void _config_gpios()
|
||||
PINMUX_AUX(PINMUX_AUX_UART2_TX) = 0;
|
||||
PINMUX_AUX(PINMUX_AUX_UART3_TX) = 0;
|
||||
|
||||
// Set Joy-Con IsAttached direction.
|
||||
PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE;
|
||||
PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE;
|
||||
|
||||
// Set pin mode for Joy-Con IsAttached and UARTB/C TX pins.
|
||||
#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
|
||||
// Set Joy-Con IsAttached mode.
|
||||
gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_GPIO);
|
||||
gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_GPIO);
|
||||
|
||||
// Enable input logic for Joy-Con IsAttached and UARTB/C TX pins.
|
||||
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);
|
||||
@ -80,27 +106,36 @@ void _config_gpios()
|
||||
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);
|
||||
|
||||
// Configure HOME as inputs.
|
||||
// PINMUX_AUX(PINMUX_AUX_BUTTON_HOME) = PINMUX_PULL_UP | PINMUX_INPUT_ENABLE;
|
||||
// gpio_config(GPIO_PORT_Y, GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||
}
|
||||
|
||||
void _config_pmc_scratch()
|
||||
{
|
||||
PMC(APBDEV_PMC_SCRATCH20) &= 0xFFF3FFFF;
|
||||
PMC(APBDEV_PMC_SCRATCH190) &= 0xFFFFFFFE;
|
||||
PMC(APBDEV_PMC_SECURE_SCRATCH21) |= 0x10;
|
||||
PMC(APBDEV_PMC_SCRATCH20) &= 0xFFF3FFFF; // Unset Debug console from Customer Option.
|
||||
PMC(APBDEV_PMC_SCRATCH190) &= 0xFFFFFFFE; // Unset DATA_DQ_E_IVREF EMC_PMACRO_DATA_PAD_TX_CTRL
|
||||
PMC(APBDEV_PMC_SECURE_SCRATCH21) |= PMC_FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT;
|
||||
}
|
||||
|
||||
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_OUT_ENB_Y) |= (1 << 6); // Enable APE clock.
|
||||
|
||||
// Set mux output to SOR1 clock switch.
|
||||
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;
|
||||
// Enabled PLLD and set csi to PLLD for test pattern generation.
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) |= 0x40800000;
|
||||
|
||||
// Clear per-clock resets.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_CLR) = 0x40; // Clear reset APE.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_CLR) = 0x40000; // Clear reset VIC.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000; // Clear reset DISP1, HOST1X.
|
||||
usleep(2);
|
||||
|
||||
// I2S channels to master and disable SLCG.
|
||||
I2S(I2S1_CTRL) |= I2S_CTRL_MASTER_EN;
|
||||
I2S(I2S1_CG) &= ~I2S_CG_SLCG_ENABLE;
|
||||
I2S(I2S2_CTRL) |= I2S_CTRL_MASTER_EN;
|
||||
@ -111,30 +146,39 @@ void _mbist_workaround()
|
||||
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;
|
||||
|
||||
DISPLAY_A(_DIREG(DC_COM_DSC_TOP_CTL)) |= 4; // DSC_SLCG_OVERRIDE.
|
||||
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;
|
||||
// Set per-clock reset.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_SET) = 0x40; // Set reset APE.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000; // Set reset DISP1, HOST1x.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_SET) = 0x40000; // Set reset VIC.
|
||||
|
||||
// Enable specific clocks and disable all others.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = 0xC0; // Enable clock PMC, FUSE.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80000130; // Enable clock RTC, TMR, GPIO, BPMP_CACHE.
|
||||
//CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80400130; // Keep USB data ON.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) = 0x1F00200; // Enable clock CSITE, IRAMA, IRAMB, IRAMC, IRAMD, BPMP_CACHE_RAM.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = 0x80400808; // Enable clock MSELECT, APB2APE, SPDIF_DOUBLER, SE.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_W) = 0x402000FC; // Enable clock PCIERX0, PCIERX1, PCIERX2, PCIERX3, PCIERX4, PCIERX5, ENTROPY, MC1.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) = 0x23000780; // Enable clock MC_CAPA, MC_CAPB, MC_CPU, MC_BBC, DBGAPB, HPLL_ADSP, PLLG_REF.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) = 0x300; // Enable clock MC_CDPA, MC_CCPA.
|
||||
|
||||
// Disable clock gate overrides.
|
||||
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;
|
||||
|
||||
// Set child clock sources.
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) &= 0x1F7FFFFF; // Disable PLLD and set reference clock and csi clock.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) &= 0xFFFF3FFF; // Set SOR1 to automatic muxing of safe clock (24MHz) or SOR1 clk switch.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT.
|
||||
}
|
||||
|
||||
void _config_se_brom()
|
||||
@ -143,7 +187,7 @@ void _config_se_brom()
|
||||
if (!(b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN))
|
||||
{
|
||||
// Bootrom part we skipped.
|
||||
u32 sbk[4] = {
|
||||
u32 sbk[4] = {
|
||||
FUSE(FUSE_PRIVATE_KEY0),
|
||||
FUSE(FUSE_PRIVATE_KEY1),
|
||||
FUSE(FUSE_PRIVATE_KEY2),
|
||||
@ -170,13 +214,59 @@ void _config_se_brom()
|
||||
APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) = (APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) & 0xF0) | (7 << 10);
|
||||
}
|
||||
|
||||
void _config_regulators()
|
||||
{
|
||||
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) | (1 << 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+
|
||||
|
||||
// Set vdd_core voltage to 1.125V
|
||||
max77620_regulator_set_voltage(REGULATOR_SD0, 1125000);
|
||||
|
||||
// Fix CPU/GPU after a Linux warmboot.
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, 2);
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO6, 2);
|
||||
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_0_95V); // Disable power.
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_1_09V); // Enable DVS power.
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL1_REG, MAX77621_RAMP_50mV_PER_US);
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL2_REG,
|
||||
MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS |
|
||||
MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL);
|
||||
|
||||
i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_0_95V); // Disable power.
|
||||
i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_1_09V); // Enable DVS power.
|
||||
i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL1_REG, MAX77621_RAMP_50mV_PER_US);
|
||||
i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL2_REG,
|
||||
MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS |
|
||||
MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL);
|
||||
|
||||
// Disable low battery shutdown monitor.
|
||||
max77620_low_battery_monitor_config();
|
||||
}
|
||||
|
||||
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;
|
||||
SYSREG(AHB_AHB_SPARE_REG) &= 0xFFFFFF9F; // Unset APB2JTAG_OVERRIDE_EN and OBS_OVERRIDE_EN.
|
||||
PMC(APBDEV_PMC_SCRATCH49) = PMC(APBDEV_PMC_SCRATCH49) & 0xFFFFFFFC;
|
||||
|
||||
_mbist_workaround();
|
||||
clock_enable_se();
|
||||
@ -197,49 +287,29 @@ void config_hw()
|
||||
clock_enable_i2c(I2C_1);
|
||||
clock_enable_i2c(I2C_5);
|
||||
|
||||
clock_enable_unk2();
|
||||
clock_enable_tzram();
|
||||
|
||||
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);
|
||||
|
||||
// Disable low battery shutdown monitor.
|
||||
max77620_low_battery_monitor_config();
|
||||
_config_regulators();
|
||||
|
||||
_config_pmc_scratch(); // Missing from 4.x+
|
||||
|
||||
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = (CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) & 0xFFFF8888) | 0x3333;
|
||||
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // Set SCLK to PLLP_OUT (408MHz).
|
||||
|
||||
sdram_init();
|
||||
|
||||
bpmp_mmu_enable();
|
||||
mc_enable_ahb_redirect();
|
||||
}
|
||||
|
||||
void reconfig_hw_workaround(bool extra_reconfig, u32 magic)
|
||||
{
|
||||
// Flush and disable MMU.
|
||||
bpmp_mmu_disable();
|
||||
bpmp_clk_rate_set(BPMP_CLK_NORMAL);
|
||||
|
||||
// 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.
|
||||
|
@ -44,10 +44,10 @@ static int _i2c_send_pkt(u32 idx, u32 x, u8 *buf, u32 size)
|
||||
memcpy(&tmp, buf, size);
|
||||
|
||||
vu32 *base = (vu32 *)i2c_addrs[idx];
|
||||
base[I2C_CMD_ADDR0] = x << 1; //Set x (send mode).
|
||||
base[I2C_CMD_DATA1] = tmp; //Set value.
|
||||
base[I2C_CNFG] = (2 * size - 2) | 0x2800; //Set size and send mode.
|
||||
_i2c_wait(base); //Kick transaction.
|
||||
base[I2C_CMD_ADDR0] = x << 1; //Set x (send mode).
|
||||
base[I2C_CMD_DATA1] = tmp; //Set value.
|
||||
base[I2C_CNFG] = ((size - 1) << 1) | 0x2800; //Set size and send mode.
|
||||
_i2c_wait(base); //Kick transaction.
|
||||
|
||||
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200;
|
||||
while (base[I2C_STATUS] & 0x100)
|
||||
@ -65,9 +65,9 @@ static int _i2c_recv_pkt(u32 idx, u8 *buf, u32 size, u32 x)
|
||||
return 0;
|
||||
|
||||
vu32 *base = (vu32 *)i2c_addrs[idx];
|
||||
base[I2C_CMD_ADDR0] = (x << 1) | 1; // Set x (recv mode).
|
||||
base[I2C_CNFG] = (size - 1) << 1 | 0x2840; // Set size and recv mode.
|
||||
_i2c_wait(base); // Kick transaction.
|
||||
base[I2C_CMD_ADDR0] = (x << 1) | 1; // Set x (recv mode).
|
||||
base[I2C_CNFG] = ((size - 1) << 1) | 0x2840; // Set size and recv mode.
|
||||
_i2c_wait(base); // Kick transaction.
|
||||
|
||||
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200;
|
||||
while (base[I2C_STATUS] & 0x100)
|
||||
|
@ -26,31 +26,50 @@
|
||||
#define APB_MISC_GP_VGPIO_GPIO_MUX_SEL 0xB74
|
||||
|
||||
/*! Pinmux registers. */
|
||||
#define PINMUX_AUX_SDMMC1_CLK 0x00
|
||||
#define PINMUX_AUX_SDMMC1_CMD 0x04
|
||||
#define PINMUX_AUX_SDMMC1_DAT3 0x08
|
||||
#define PINMUX_AUX_SDMMC1_DAT2 0x0C
|
||||
#define PINMUX_AUX_SDMMC1_DAT1 0x10
|
||||
#define PINMUX_AUX_SDMMC1_DAT0 0x14
|
||||
#define PINMUX_AUX_SDMMC3_CLK 0x1C
|
||||
#define PINMUX_AUX_SDMMC3_CMD 0x20
|
||||
#define PINMUX_AUX_SDMMC3_DAT0 0x24
|
||||
#define PINMUX_AUX_SDMMC3_DAT1 0x28
|
||||
#define PINMUX_AUX_SDMMC3_DAT2 0x2C
|
||||
#define PINMUX_AUX_SDMMC3_DAT3 0x30
|
||||
#define PINMUX_AUX_DMIC3_CLK 0xB4
|
||||
#define PINMUX_AUX_UART2_TX 0xF4
|
||||
#define PINMUX_AUX_UART3_TX 0x104
|
||||
#define PINMUX_AUX_WIFI_EN 0x1B4
|
||||
#define PINMUX_AUX_WIFI_RST 0x1B8
|
||||
#define PINMUX_AUX_NFC_EN 0x1D0
|
||||
#define PINMUX_AUX_NFC_INT 0x1D4
|
||||
#define PINMUX_AUX_LCD_BL_PWM 0x1FC
|
||||
#define PINMUX_AUX_LCD_BL_EN 0x200
|
||||
#define PINMUX_AUX_LCD_RST 0x204
|
||||
#define PINMUX_AUX_GPIO_PE6 0x248
|
||||
#define PINMUX_AUX_GPIO_PH6 0x250
|
||||
#define PINMUX_AUX_GPIO_PZ1 0x280
|
||||
#define PINMUX_AUX_SDMMC1_CLK 0x00
|
||||
#define PINMUX_AUX_SDMMC1_CMD 0x04
|
||||
#define PINMUX_AUX_SDMMC1_DAT3 0x08
|
||||
#define PINMUX_AUX_SDMMC1_DAT2 0x0C
|
||||
#define PINMUX_AUX_SDMMC1_DAT1 0x10
|
||||
#define PINMUX_AUX_SDMMC1_DAT0 0x14
|
||||
#define PINMUX_AUX_SDMMC3_CLK 0x1C
|
||||
#define PINMUX_AUX_SDMMC3_CMD 0x20
|
||||
#define PINMUX_AUX_SDMMC3_DAT0 0x24
|
||||
#define PINMUX_AUX_SDMMC3_DAT1 0x28
|
||||
#define PINMUX_AUX_SDMMC3_DAT2 0x2C
|
||||
#define PINMUX_AUX_SDMMC3_DAT3 0x30
|
||||
#define PINMUX_AUX_SATA_LED_ACTIVE 0x4C
|
||||
#define PINMUX_AUX_DMIC3_CLK 0xB4
|
||||
#define PINMUX_AUX_DMIC3_DAT 0xB8
|
||||
#define PINMUX_AUX_CAM_I2C_SCL 0xD4
|
||||
#define PINMUX_AUX_CAM_I2C_SDA 0xD8
|
||||
#define PINMUX_AUX_UART2_TX 0xF4
|
||||
#define PINMUX_AUX_UART3_TX 0x104
|
||||
#define PINMUX_AUX_DAP4_DIN 0x148
|
||||
#define PINMUX_AUX_DAP4_SCLK 0x150
|
||||
#define PINMUX_AUX_GPIO_X1_AUD 0x18C
|
||||
#define PINMUX_AUX_GPIO_X3_AUD 0x190
|
||||
#define PINMUX_AUX_SPDIF_IN 0x1A4
|
||||
#define PINMUX_AUX_USB_VBUS_EN0 0x1A8
|
||||
#define PINMUX_AUX_USB_VBUS_EN1 0x1AC
|
||||
#define PINMUX_AUX_WIFI_EN 0x1B4
|
||||
#define PINMUX_AUX_WIFI_RST 0x1B8
|
||||
#define PINMUX_AUX_AP_WAKE_NFC 0x1CC
|
||||
#define PINMUX_AUX_NFC_EN 0x1D0
|
||||
#define PINMUX_AUX_NFC_INT 0x1D4
|
||||
#define PINMUX_AUX_CAM1_PWDN 0x1EC
|
||||
#define PINMUX_AUX_CAM2_PWDN 0x1F0
|
||||
#define PINMUX_AUX_LCD_BL_PWM 0x1FC
|
||||
#define PINMUX_AUX_LCD_BL_EN 0x200
|
||||
#define PINMUX_AUX_LCD_RST 0x204
|
||||
#define PINMUX_AUX_LCD_GPIO2 0x20C
|
||||
#define PINMUX_AUX_TOUCH_INT 0x220
|
||||
#define PINMUX_AUX_MOTION_INT 0x224
|
||||
#define PINMUX_AUX_BUTTON_HOME 0x240
|
||||
#define PINMUX_AUX_GPIO_PE6 0x248
|
||||
#define PINMUX_AUX_GPIO_PH6 0x250
|
||||
#define PINMUX_AUX_GPIO_PK3 0x260
|
||||
#define PINMUX_AUX_GPIO_PZ1 0x280
|
||||
/*! 0:UART-A, 1:UART-B, 3:UART-C, 3:UART-D */
|
||||
#define PINMUX_AUX_UARTX_TX(x) (0xE4 + 0x10 * (x))
|
||||
#define PINMUX_AUX_UARTX_RX(x) (0xE8 + 0x10 * (x))
|
||||
@ -78,7 +97,7 @@
|
||||
#define PINMUX_OPEN_DRAIN (1 << 11)
|
||||
#define PINMUX_SCHMT (1 << 12)
|
||||
|
||||
#define PINMUX_DRIVE_1X (0 << 13)
|
||||
#define PINMUX_DRIVE_1X (0 << 13)
|
||||
#define PINMUX_DRIVE_2X (1 << 13)
|
||||
#define PINMUX_DRIVE_3X (2 << 13)
|
||||
#define PINMUX_DRIVE_4X (3 << 13)
|
||||
|
@ -25,6 +25,7 @@
|
||||
#define APBDEV_PMC_PWRGATE_TOGGLE 0x30
|
||||
#define APBDEV_PMC_PWRGATE_STATUS 0x38
|
||||
#define APBDEV_PMC_NO_IOPOWER 0x44
|
||||
#define PMC_NO_IOPOWER_SDMMC1_IO_EN (1 << 12)
|
||||
#define APBDEV_PMC_SCRATCH0 0x50
|
||||
#define APBDEV_PMC_SCRATCH1 0x54
|
||||
#define APBDEV_PMC_SCRATCH20 0xA0
|
||||
@ -37,6 +38,7 @@
|
||||
#define APBDEV_PMC_SCRATCH33 0x120
|
||||
#define APBDEV_PMC_SCRATCH40 0x13C
|
||||
#define APBDEV_PMC_OSC_EDPD_OVER 0x1A4
|
||||
#define PMC_OSC_EDPD_OVER_OSC_CTRL_OVER 0x400000
|
||||
#define APBDEV_PMC_RST_STATUS 0x1B4
|
||||
#define APBDEV_PMC_IO_DPD_REQ 0x1B8
|
||||
#define APBDEV_PMC_IO_DPD2_REQ 0x1C0
|
||||
@ -51,9 +53,11 @@
|
||||
#define APBDEV_PMC_REG_SHORT 0x2CC
|
||||
#define APBDEV_PMC_SEC_DISABLE3 0x2D8
|
||||
#define APBDEV_PMC_SECURE_SCRATCH21 0x334
|
||||
#define PMC_FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT 0x10
|
||||
#define APBDEV_PMC_SECURE_SCRATCH32 0x360
|
||||
#define APBDEV_PMC_SECURE_SCRATCH49 0x3A4
|
||||
#define APBDEV_PMC_CNTRL2 0x440
|
||||
#define PMC_CNTRL2_HOLD_CKE_LOW_EN 0x1000
|
||||
#define APBDEV_PMC_IO_DPD3_REQ 0x45C
|
||||
#define APBDEV_PMC_IO_DPD4_REQ 0x464
|
||||
#define APBDEV_PMC_UTMIP_PAD_CFG1 0x4C4
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "../utils/types.h"
|
||||
|
||||
#define BOOTROM_BASE 0x100000
|
||||
#define IRAM_BASE 0x40000000
|
||||
#define HOST1X_BASE 0x50000000
|
||||
#define BPMP_CACHE_BASE 0x50040000
|
||||
#define DISPLAY_A_BASE 0x54200000
|
||||
@ -100,15 +101,22 @@
|
||||
#define CL_DVFS(off) _REG(CL_DVFS_BASE, off)
|
||||
#define TEST_REG(off) _REG(0x0, off)
|
||||
|
||||
/* HOST1X registers. */
|
||||
#define HOST1X_CH0_SYNC_BASE 0x2100
|
||||
#define HOST1X_CH0_SYNC_SYNCPT_9 (HOST1X_CH0_SYNC_BASE + 0xFA4)
|
||||
#define HOST1X_CH0_SYNC_SYNCPT_160 (HOST1X_CH0_SYNC_BASE + 0x1200)
|
||||
|
||||
/*! 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_HIDREV 0x804
|
||||
#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_EMMC4_PAD_PUPD_CFGPADCTRL 0xABC
|
||||
#define APB_MISC_GP_WIFI_EN_CFGPADCTRL 0xB64
|
||||
#define APB_MISC_GP_WIFI_RST_CFGPADCTRL 0xB68
|
||||
|
||||
@ -118,7 +126,10 @@
|
||||
|
||||
/*! Secure boot registers. */
|
||||
#define SB_CSR 0x0
|
||||
#define SB_CSR_NS_RST_VEC_WR_DIS (1 << 1)
|
||||
#define SB_CSR_PIROM_DISABLE (1 << 4)
|
||||
#define SB_AA64_RESET_LOW 0x30
|
||||
#define SB_AA64_RST_AARCH64_MODE_EN (1 << 0)
|
||||
#define SB_AA64_RESET_HIGH 0x34
|
||||
|
||||
/*! SOR registers. */
|
||||
@ -145,7 +156,7 @@
|
||||
#define SYSCTR0_COUNTERID7 0xFDC
|
||||
#define SYSCTR0_COUNTERID8 0xFF0
|
||||
#define SYSCTR0_COUNTERID9 0xFF4
|
||||
#define SYSCTR0_COUNTERID10 0xFF8
|
||||
#define SYSCTR0_COUNTERID10 0xFF8
|
||||
#define SYSCTR0_COUNTERID11 0xFFC
|
||||
|
||||
/*! TMR registers. */
|
||||
@ -182,10 +193,31 @@
|
||||
/*! PWM registers. */
|
||||
#define PWM_CONTROLLER_PWM_CSR_0 0x00
|
||||
#define PWM_CONTROLLER_PWM_CSR_1 0x10
|
||||
#define PWM_CSR_EN (1 << 31)
|
||||
|
||||
/*! Special registers. */
|
||||
#define EMC_SCRATCH0 0x324
|
||||
#define EMC_HEKA_UPD (1 << 30)
|
||||
#define EMC_SEPT_RUN (1 << 31)
|
||||
|
||||
/*! Flow controller registers. */
|
||||
#define FLOW_CTLR_HALT_COP_EVENTS 0x4
|
||||
#define HALT_COP_SEC (1 << 23)
|
||||
#define HALT_COP_MSEC (1 << 24)
|
||||
#define HALT_COP_USEC (1 << 25)
|
||||
#define HALT_COP_JTAG (1 << 28)
|
||||
#define HALT_COP_WAIT_EVENT (1 << 30)
|
||||
#define HALT_COP_WAIT_IRQ (1 << 31)
|
||||
#define HALT_COP_MAX_CNT 0xFF
|
||||
#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_CPU0_CSR 0x8
|
||||
#define FLOW_CTLR_CPU1_CSR 0x18
|
||||
#define FLOW_CTLR_CPU2_CSR 0x20
|
||||
#define FLOW_CTLR_CPU3_CSR 0x28
|
||||
#define FLOW_CTLR_RAM_REPAIR 0x40
|
||||
#define FLOW_CTLR_BPMP_CLUSTER_CONTROL 0x98
|
||||
|
||||
#endif
|
||||
|
266
source/storage/emummc.c
Normal file
266
source/storage/emummc.c
Normal file
@ -0,0 +1,266 @@
|
||||
/*
|
||||
* 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 <stdlib.h>
|
||||
|
||||
#include "emummc.h"
|
||||
#include "sdmmc.h"
|
||||
#include "../config/config.h"
|
||||
#include "../config/ini.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../utils/list.h"
|
||||
#include "../utils/types.h"
|
||||
|
||||
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();
|
||||
|
||||
bool emummc_load_cfg()
|
||||
{
|
||||
sd_mount();
|
||||
emu_cfg.enabled = 0;
|
||||
emu_cfg.path = NULL;
|
||||
emu_cfg.nintendo_path = NULL;
|
||||
emu_cfg.sector = 0;
|
||||
emu_cfg.id = 0;
|
||||
emu_cfg.file_based_part_size = 0;
|
||||
emu_cfg.active_part = 0;
|
||||
emu_cfg.fs_ver = 0;
|
||||
emu_cfg.emummc_file_based_path = (char *)malloc(0x80);
|
||||
|
||||
LIST_INIT(ini_sections);
|
||||
if (ini_parse(&ini_sections, "emuMMC/emummc.ini", false))
|
||||
{
|
||||
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
|
||||
{
|
||||
if (ini_sec->type == INI_CHOICE)
|
||||
{
|
||||
if (strcmp(ini_sec->name, "emummc"))
|
||||
continue;
|
||||
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
|
||||
{
|
||||
if (!strcmp("enabled", kv->key))
|
||||
emu_cfg.enabled = atoi(kv->val);
|
||||
else if (!strcmp("sector", kv->key))
|
||||
emu_cfg.sector = strtol(kv->val, NULL, 16);
|
||||
else if (!strcmp("id", kv->key))
|
||||
emu_cfg.id = strtol(kv->val, NULL, 16);
|
||||
else if (!strcmp("path", kv->key))
|
||||
emu_cfg.path = kv->val;
|
||||
else if (!strcmp("nintendo_path", kv->key))
|
||||
emu_cfg.nintendo_path = kv->val;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int emummc_raw_get_part_off(int part_idx)
|
||||
{
|
||||
switch (part_idx)
|
||||
{
|
||||
case 0:
|
||||
return 2;
|
||||
case 1:
|
||||
return 0;
|
||||
case 2:
|
||||
return 1;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc)
|
||||
{
|
||||
FILINFO fno;
|
||||
if (!sdmmc_storage_init_mmc(storage, sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
{
|
||||
EPRINTF("Failed to init eMMC.");
|
||||
|
||||
goto out;
|
||||
}
|
||||
if (h_cfg.emummc_force_disable)
|
||||
return 1;
|
||||
|
||||
emu_cfg.active_part = 0;
|
||||
if (!sd_mount())
|
||||
goto out;
|
||||
|
||||
if (emu_cfg.enabled && !emu_cfg.sector)
|
||||
{
|
||||
strcpy(emu_cfg.emummc_file_based_path, emu_cfg.path);
|
||||
strcat(emu_cfg.emummc_file_based_path, "/eMMC");
|
||||
|
||||
if (f_stat(emu_cfg.emummc_file_based_path, &fno))
|
||||
{
|
||||
EPRINTF("Failed to open eMMC folder.");
|
||||
goto out;
|
||||
}
|
||||
f_chmod(emu_cfg.emummc_file_based_path, AM_ARC, AM_ARC);
|
||||
|
||||
strcat(emu_cfg.emummc_file_based_path, "/00");
|
||||
if (f_stat(emu_cfg.emummc_file_based_path, &fno))
|
||||
{
|
||||
EPRINTF("Failed to open emuMMC rawnand.");
|
||||
goto out;
|
||||
}
|
||||
emu_cfg.file_based_part_size = fno.fsize >> 9;
|
||||
}
|
||||
return 1;
|
||||
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int emummc_storage_end(sdmmc_storage_t *storage)
|
||||
{
|
||||
sd_unmount();
|
||||
sdmmc_storage_end(storage);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int emummc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf)
|
||||
{
|
||||
FIL fp;
|
||||
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
|
||||
return sdmmc_storage_read(storage, sector, num_sectors, buf);
|
||||
else if (emu_cfg.sector)
|
||||
{
|
||||
sector += emu_cfg.sector;
|
||||
sector += emummc_raw_get_part_off(emu_cfg.active_part) * 0x2000;
|
||||
return sdmmc_storage_read(&sd_storage, sector, num_sectors, buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!emu_cfg.active_part)
|
||||
{
|
||||
u32 file_part = sector / emu_cfg.file_based_part_size;
|
||||
sector = sector % emu_cfg.file_based_part_size;
|
||||
if (file_part >= 10)
|
||||
itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 2, 10);
|
||||
else
|
||||
{
|
||||
emu_cfg.emummc_file_based_path[strlen(emu_cfg.emummc_file_based_path) - 2] = '0';
|
||||
itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 1, 10);
|
||||
}
|
||||
}
|
||||
if (f_open(&fp, emu_cfg.emummc_file_based_path, FA_READ))
|
||||
{
|
||||
EPRINTF("Failed to open emuMMC image.");
|
||||
return 0;
|
||||
}
|
||||
f_lseek(&fp, (u64)sector << 9);
|
||||
if (f_read(&fp, buf, (u64)num_sectors << 9, NULL))
|
||||
{
|
||||
EPRINTF("Failed to read emuMMC image.");
|
||||
f_close(&fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
f_close(&fp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int emummc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf)
|
||||
{
|
||||
FIL fp;
|
||||
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
|
||||
return sdmmc_storage_write(storage, sector, num_sectors, buf);
|
||||
else if (emu_cfg.sector)
|
||||
{
|
||||
sector += emu_cfg.sector;
|
||||
sector += emummc_raw_get_part_off(emu_cfg.active_part) * 0x2000;
|
||||
return sdmmc_storage_write(&sd_storage, sector, num_sectors, buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!emu_cfg.active_part)
|
||||
{
|
||||
u32 file_part = sector / emu_cfg.file_based_part_size;
|
||||
sector = sector % emu_cfg.file_based_part_size;
|
||||
if (file_part >= 10)
|
||||
itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 2, 10);
|
||||
else
|
||||
{
|
||||
emu_cfg.emummc_file_based_path[strlen(emu_cfg.emummc_file_based_path) - 2] = '0';
|
||||
itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 1, 10);
|
||||
}
|
||||
}
|
||||
if (f_open(&fp, emu_cfg.emummc_file_based_path, FA_WRITE))
|
||||
{
|
||||
gfx_printf("e5\n");
|
||||
return 0;
|
||||
}
|
||||
f_lseek(&fp, (u64)sector << 9);
|
||||
if (f_write(&fp, buf, (u64)num_sectors << 9, NULL))
|
||||
{
|
||||
gfx_printf("e6\n");
|
||||
f_close(&fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
f_close(&fp);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int emummc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition)
|
||||
{
|
||||
emu_cfg.active_part = partition;
|
||||
|
||||
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
|
||||
sdmmc_storage_set_mmc_partition(storage, partition);
|
||||
else if (emu_cfg.sector)
|
||||
return 1;
|
||||
else
|
||||
{
|
||||
strcpy(emu_cfg.emummc_file_based_path, emu_cfg.path);
|
||||
strcat(emu_cfg.emummc_file_based_path, "/eMMC");
|
||||
|
||||
switch (partition)
|
||||
{
|
||||
case 0:
|
||||
strcat(emu_cfg.emummc_file_based_path, "/00");
|
||||
break;
|
||||
case 1:
|
||||
strcat(emu_cfg.emummc_file_based_path, "/BOOT0");
|
||||
break;
|
||||
case 2:
|
||||
strcat(emu_cfg.emummc_file_based_path, "/BOOT1");
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
59
source/storage/emummc.h
Normal file
59
source/storage/emummc.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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 EMUMMC_H
|
||||
#define EMUMMC_H
|
||||
|
||||
#include "sdmmc.h"
|
||||
#include "../utils/types.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
EMUMMC_TYPE_NONE = 0,
|
||||
EMUMMC_TYPE_PARTITION = 1,
|
||||
EMUMMC_TYPE_FILES = 2,
|
||||
} emummc_type_t;
|
||||
|
||||
typedef enum {
|
||||
EMUMMC_MMC_NAND = 0,
|
||||
EMUMMC_MMC_SD = 1,
|
||||
EMUMMC_MMC_GC = 2,
|
||||
} emummc_mmc_t;
|
||||
|
||||
typedef struct _emummc_cfg_t
|
||||
{
|
||||
int enabled;
|
||||
u64 sector;
|
||||
u16 id;
|
||||
char *path;
|
||||
char *nintendo_path;
|
||||
// Internal.
|
||||
char *emummc_file_based_path;
|
||||
u32 file_based_part_size;
|
||||
u32 active_part;
|
||||
int fs_ver;
|
||||
} emummc_cfg_t;
|
||||
|
||||
emummc_cfg_t emu_cfg;
|
||||
|
||||
bool emummc_load_cfg();
|
||||
int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc);
|
||||
int emummc_storage_end(sdmmc_storage_t *storage);
|
||||
int emummc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf);
|
||||
int emummc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf);
|
||||
int emummc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition);
|
||||
|
||||
#endif
|
@ -17,6 +17,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "nx_emmc.h"
|
||||
#include "emummc.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../utils/list.h"
|
||||
|
||||
@ -24,7 +25,7 @@ void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage)
|
||||
{
|
||||
u8 *buf = (u8 *)malloc(NX_GPT_NUM_BLOCKS * NX_EMMC_BLOCKSIZE);
|
||||
|
||||
sdmmc_storage_read(storage, NX_GPT_FIRST_LBA, NX_GPT_NUM_BLOCKS, buf);
|
||||
emummc_storage_read(storage, NX_GPT_FIRST_LBA, NX_GPT_NUM_BLOCKS, buf);
|
||||
|
||||
gpt_header_t *hdr = (gpt_header_t *)buf;
|
||||
for (u32 i = 0; i < hdr->num_part_ents; i++)
|
||||
@ -65,7 +66,7 @@ int nx_emmc_part_read(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_of
|
||||
// The last LBA is inclusive.
|
||||
if (part->lba_start + sector_off > part->lba_end)
|
||||
return 0;
|
||||
return sdmmc_storage_read(storage, part->lba_start + sector_off, num_sectors, buf);
|
||||
return emummc_storage_read(storage, part->lba_start + sector_off, num_sectors, buf);
|
||||
}
|
||||
|
||||
int nx_emmc_part_write(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf)
|
||||
|
@ -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,
|
||||
@ -19,11 +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"
|
||||
#define DPRINTF(...) gfx_printf(__VA_ARGS__)*/
|
||||
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
|
||||
#define DPRINTF(...)
|
||||
|
||||
static inline u32 unstuff_bits(u32 *resp, u32 start, u32 size)
|
||||
@ -69,6 +69,7 @@ static int _sdmmc_storage_execute_cmd_type1_ex(sdmmc_storage_t *storage, u32 *re
|
||||
if (_sdmmc_storage_check_result(*resp))
|
||||
if (expected_state == 0x10 || R1_CURRENT_STATE(*resp) == expected_state)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -82,6 +83,7 @@ static int _sdmmc_storage_go_idle_state(sdmmc_storage_t *storage)
|
||||
{
|
||||
sdmmc_cmd_t cmd;
|
||||
sdmmc_init_cmd(&cmd, MMC_GO_IDLE_STATE, 0, SDMMC_RSP_TYPE_0, 0);
|
||||
|
||||
return sdmmc_execute_cmd(storage->sdmmc, &cmd, 0, 0);
|
||||
}
|
||||
|
||||
@ -91,7 +93,9 @@ static int _sdmmc_storage_get_cid(sdmmc_storage_t *storage, void *buf)
|
||||
sdmmc_init_cmd(&cmd, MMC_ALL_SEND_CID, 0, SDMMC_RSP_TYPE_2, 0);
|
||||
if (!sdmmc_execute_cmd(storage->sdmmc, &cmd, 0, 0))
|
||||
return 0;
|
||||
|
||||
sdmmc_get_rsp(storage->sdmmc, buf, 0x10, SDMMC_RSP_TYPE_2);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -106,7 +110,9 @@ static int _sdmmc_storage_get_csd(sdmmc_storage_t *storage, void *buf)
|
||||
sdmmc_init_cmd(&cmdbuf, MMC_SEND_CSD, storage->rca << 16, SDMMC_RSP_TYPE_2, 0);
|
||||
if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, 0, 0))
|
||||
return 0;
|
||||
|
||||
sdmmc_get_rsp(storage->sdmmc, buf, 0x10, SDMMC_RSP_TYPE_2);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -144,8 +150,10 @@ static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out
|
||||
u32 tmp = 0;
|
||||
sdmmc_stop_transmission(storage->sdmmc, &tmp);
|
||||
_sdmmc_storage_get_status(storage, &tmp, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -153,7 +161,9 @@ int sdmmc_storage_end(sdmmc_storage_t *storage)
|
||||
{
|
||||
if (!_sdmmc_storage_go_idle_state(storage))
|
||||
return 0;
|
||||
|
||||
sdmmc_end(storage->sdmmc);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -175,14 +185,16 @@ static int _sdmmc_storage_readwrite(sdmmc_storage_t *storage, u32 sector, u32 nu
|
||||
|
||||
msleep(100);
|
||||
} while (retries);
|
||||
|
||||
return 0;
|
||||
|
||||
out:;
|
||||
DPRINTF("readwrite: %08X\n", blkcnt);
|
||||
DPRINTF("readwrite: %08X\n", blkcnt);
|
||||
sector += blkcnt;
|
||||
num_sectors -= blkcnt;
|
||||
bbuf += 512 * blkcnt;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -233,14 +245,17 @@ static int _mmc_storage_get_op_cond(sdmmc_storage_t *storage, u32 power)
|
||||
u32 cond = 0;
|
||||
if (!_mmc_storage_get_op_cond_inner(storage, &cond, power))
|
||||
break;
|
||||
|
||||
if (cond & MMC_CARD_BUSY)
|
||||
{
|
||||
if (cond & 0x40000000)
|
||||
storage->has_sector_access = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
if (get_tmr_ms() > timeout)
|
||||
break;
|
||||
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
@ -370,6 +385,7 @@ static int _mmc_storage_switch_buswidth(sdmmc_storage_t *storage, u32 bus_width)
|
||||
if (_sdmmc_storage_check_status(storage))
|
||||
{
|
||||
sdmmc_set_bus_width(storage->sdmmc, bus_width);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -380,14 +396,19 @@ static int _mmc_storage_enable_HS(sdmmc_storage_t *storage, int check)
|
||||
{
|
||||
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS)))
|
||||
return 0;
|
||||
|
||||
if (check && !_sdmmc_storage_check_status(storage))
|
||||
return 0;
|
||||
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, 2))
|
||||
return 0;
|
||||
DPRINTF("[MMC] switched to HS\n");
|
||||
|
||||
DPRINTF("[MMC] switched to HS\n");
|
||||
storage->csd.busspeed = 52;
|
||||
|
||||
if (check || _sdmmc_storage_check_status(storage))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -395,12 +416,16 @@ static int _mmc_storage_enable_HS200(sdmmc_storage_t *storage)
|
||||
{
|
||||
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200)))
|
||||
return 0;
|
||||
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, 3))
|
||||
return 0;
|
||||
|
||||
if (!sdmmc_config_tuning(storage->sdmmc, 3, MMC_SEND_TUNING_BLOCK_HS200))
|
||||
return 0;
|
||||
DPRINTF("[MMC] switched to HS200\n");
|
||||
|
||||
DPRINTF("[MMC] switched to HS200\n");
|
||||
storage->csd.busspeed = 200;
|
||||
|
||||
return _sdmmc_storage_check_status(storage);
|
||||
}
|
||||
|
||||
@ -408,30 +433,36 @@ static int _mmc_storage_enable_HS400(sdmmc_storage_t *storage)
|
||||
{
|
||||
if (!_mmc_storage_enable_HS200(storage))
|
||||
return 0;
|
||||
|
||||
sdmmc_get_venclkctl(storage->sdmmc);
|
||||
|
||||
if (!_mmc_storage_enable_HS(storage, 0))
|
||||
return 0;
|
||||
|
||||
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_BUS_WIDTH, EXT_CSD_DDR_BUS_WIDTH_8)))
|
||||
return 0;
|
||||
|
||||
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400)))
|
||||
return 0;
|
||||
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, 4))
|
||||
return 0;
|
||||
DPRINTF("[MMC] switched to HS400\n");
|
||||
|
||||
DPRINTF("[MMC] switched to HS400\n");
|
||||
storage->csd.busspeed = 400;
|
||||
|
||||
return _sdmmc_storage_check_status(storage);
|
||||
}
|
||||
|
||||
static int _mmc_storage_enable_highspeed(sdmmc_storage_t *storage, u32 card_type, u32 type)
|
||||
{
|
||||
//TODO: this should be a config item.
|
||||
//---v
|
||||
// --v
|
||||
if (!1 || sdmmc_get_voltage(storage->sdmmc) != SDMMC_POWER_1_8)
|
||||
goto out;
|
||||
|
||||
if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 &&
|
||||
card_type & EXT_CSD_CARD_TYPE_HS400_1_8V &&
|
||||
type == 4)
|
||||
card_type & EXT_CSD_CARD_TYPE_HS400_1_8V && type == 4)
|
||||
return _mmc_storage_enable_HS400(storage);
|
||||
|
||||
if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 ||
|
||||
@ -443,6 +474,7 @@ static int _mmc_storage_enable_highspeed(sdmmc_storage_t *storage, u32 card_type
|
||||
out:;
|
||||
if (card_type & EXT_CSD_CARD_TYPE_HS_52)
|
||||
return _mmc_storage_enable_HS(storage, 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -450,6 +482,7 @@ static int _mmc_storage_enable_bkops(sdmmc_storage_t *storage)
|
||||
{
|
||||
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_SET_BITS, EXT_CSD_BKOPS_EN, EXT_CSD_BKOPS_LEVEL_2)))
|
||||
return 0;
|
||||
|
||||
return _sdmmc_storage_check_status(storage);
|
||||
}
|
||||
|
||||
@ -461,42 +494,42 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
||||
|
||||
if (!sdmmc_init(sdmmc, id, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_1, 0, 0))
|
||||
return 0;
|
||||
DPRINTF("[MMC] after init\n");
|
||||
DPRINTF("[MMC] after init\n");
|
||||
|
||||
usleep(1000 + (74000 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||
|
||||
if (!_sdmmc_storage_go_idle_state(storage))
|
||||
return 0;
|
||||
DPRINTF("[MMC] went to idle state\n");
|
||||
DPRINTF("[MMC] went to idle state\n");
|
||||
|
||||
if (!_mmc_storage_get_op_cond(storage, SDMMC_POWER_1_8))
|
||||
return 0;
|
||||
DPRINTF("[MMC] got op cond\n");
|
||||
DPRINTF("[MMC] got op cond\n");
|
||||
|
||||
if (!_sdmmc_storage_get_cid(storage, storage->raw_cid))
|
||||
return 0;
|
||||
DPRINTF("[MMC] got cid\n");
|
||||
DPRINTF("[MMC] got cid\n");
|
||||
|
||||
if (!_mmc_storage_set_relative_addr(storage))
|
||||
return 0;
|
||||
DPRINTF("[MMC] set relative addr\n");
|
||||
DPRINTF("[MMC] set relative addr\n");
|
||||
|
||||
if (!_sdmmc_storage_get_csd(storage, storage->raw_csd))
|
||||
return 0;
|
||||
DPRINTF("[MMC] got csd\n");
|
||||
DPRINTF("[MMC] got csd\n");
|
||||
_mmc_storage_parse_csd(storage);
|
||||
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, 1))
|
||||
return 0;
|
||||
DPRINTF("[MMC] after setup clock\n");
|
||||
DPRINTF("[MMC] after setup clock\n");
|
||||
|
||||
if (!_sdmmc_storage_select_card(storage))
|
||||
return 0;
|
||||
DPRINTF("[MMC] card selected\n");
|
||||
DPRINTF("[MMC] card selected\n");
|
||||
|
||||
if (!_sdmmc_storage_set_blocklen(storage, 512))
|
||||
return 0;
|
||||
DPRINTF("[MMC] set blocklen to 512\n");
|
||||
DPRINTF("[MMC] set blocklen to 512\n");
|
||||
|
||||
u32 *csd = (u32 *)storage->raw_csd;
|
||||
//Check system specification version, only version 4.0 and later support below features.
|
||||
@ -508,7 +541,7 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
||||
|
||||
if (!_mmc_storage_switch_buswidth(storage, bus_width))
|
||||
return 0;
|
||||
DPRINTF("[MMC] switched buswidth\n");
|
||||
DPRINTF("[MMC] switched buswidth\n");
|
||||
|
||||
u8 *ext_csd = (u8 *)malloc(512);
|
||||
if (!_mmc_storage_get_ext_csd(storage, ext_csd))
|
||||
@ -517,7 +550,7 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
||||
return 0;
|
||||
}
|
||||
free(ext_csd);
|
||||
DPRINTF("[MMC] got ext_csd\n");
|
||||
DPRINTF("[MMC] got ext_csd\n");
|
||||
_mmc_storage_parse_cid(storage); //This needs to be after csd and ext_csd
|
||||
//gfx_hexdump(0, ext_csd, 512);
|
||||
|
||||
@ -527,14 +560,16 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
||||
if (storage->ext_csd.bkops & 0x1 && !(storage->ext_csd.bkops_en & EXT_CSD_BKOPS_LEVEL_2) && 0)
|
||||
{
|
||||
_mmc_storage_enable_bkops(storage);
|
||||
DPRINTF("[MMC] BKOPS enabled\n");
|
||||
DPRINTF("[MMC] BKOPS enabled\n");
|
||||
}
|
||||
else
|
||||
DPRINTF("[MMC] BKOPS disabled\n");
|
||||
{
|
||||
DPRINTF("[MMC] BKOPS disabled\n");
|
||||
}
|
||||
|
||||
if (!_mmc_storage_enable_highspeed(storage, storage->ext_csd.card_type, type))
|
||||
return 0;
|
||||
DPRINTF("[MMC] succesfully switched to highspeed mode\n");
|
||||
DPRINTF("[MMC] succesfully switched to highspeed mode\n");
|
||||
|
||||
sdmmc_sd_clock_ctrl(storage->sdmmc, 1);
|
||||
|
||||
@ -545,8 +580,10 @@ int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition)
|
||||
{
|
||||
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_PART_CONFIG, partition)))
|
||||
return 0;
|
||||
|
||||
if (!_sdmmc_storage_check_status(storage))
|
||||
return 0;
|
||||
|
||||
storage->partition = partition;
|
||||
return 1;
|
||||
}
|
||||
@ -560,6 +597,7 @@ static int _sd_storage_execute_app_cmd(sdmmc_storage_t *storage, u32 expected_st
|
||||
u32 tmp;
|
||||
if (!_sdmmc_storage_execute_cmd_type1_ex(storage, &tmp, MMC_APP_CMD, storage->rca << 16, 0, expected_state, mask))
|
||||
return 0;
|
||||
|
||||
return sdmmc_execute_cmd(storage->sdmmc, cmd, req, blkcnt_out);
|
||||
}
|
||||
|
||||
@ -567,6 +605,7 @@ static int _sd_storage_execute_app_cmd_type1(sdmmc_storage_t *storage, u32 *resp
|
||||
{
|
||||
if (!_sdmmc_storage_execute_cmd_type1(storage, MMC_APP_CMD, storage->rca << 16, 0, R1_STATE_TRAN))
|
||||
return 0;
|
||||
|
||||
return _sdmmc_storage_execute_cmd_type1_ex(storage, resp, cmd, arg, check_busy, expected_state, 0);
|
||||
}
|
||||
|
||||
@ -598,6 +637,7 @@ static int _sd_storage_get_op_cond_once(sdmmc_storage_t *storage, u32 *cond, int
|
||||
sdmmc_init_cmd(&cmdbuf, SD_APP_OP_COND, arg, SDMMC_RSP_TYPE_3, 0);
|
||||
if (!_sd_storage_execute_app_cmd(storage, 0x10, is_version_1 ? 0x400000 : 0, &cmdbuf, 0, 0))
|
||||
return 0;
|
||||
|
||||
return sdmmc_get_rsp(storage->sdmmc, cond, 4, SDMMC_RSP_TYPE_3);
|
||||
}
|
||||
|
||||
@ -625,7 +665,7 @@ static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, i
|
||||
return 0;
|
||||
storage->is_low_voltage = 1;
|
||||
|
||||
DPRINTF("-> switched to low voltage\n");
|
||||
DPRINTF("-> switched to low voltage\n");
|
||||
}
|
||||
}
|
||||
|
||||
@ -704,7 +744,7 @@ int _sd_storage_get_scr(sdmmc_storage_t *storage, u8 *buf)
|
||||
|
||||
u32 tmp = 0;
|
||||
sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1);
|
||||
//Prepare buffer for unstuff_bits
|
||||
//Prepare buffer for unstuff_bits
|
||||
for (int i = 0; i < 8; i+=4)
|
||||
{
|
||||
storage->raw_scr[i + 3] = buf[i];
|
||||
@ -779,17 +819,17 @@ void _sd_storage_set_current_limit(sdmmc_storage_t *storage, u8 *buf)
|
||||
switch (pwr)
|
||||
{
|
||||
case SD_SET_CURRENT_LIMIT_800:
|
||||
DPRINTF("[SD] Power limit raised to 800mA\n");
|
||||
DPRINTF("[SD] Power limit raised to 800mA\n");
|
||||
break;
|
||||
case SD_SET_CURRENT_LIMIT_600:
|
||||
DPRINTF("[SD] Power limit raised to 600mA\n");
|
||||
DPRINTF("[SD] Power limit raised to 600mA\n");
|
||||
break;
|
||||
case SD_SET_CURRENT_LIMIT_400:
|
||||
DPRINTF("[SD] Power limit raised to 800mA\n");
|
||||
DPRINTF("[SD] Power limit raised to 800mA\n");
|
||||
break;
|
||||
default:
|
||||
case SD_SET_CURRENT_LIMIT_200:
|
||||
DPRINTF("[SD] Power limit defaulted to 200mA\n");
|
||||
DPRINTF("[SD] Power limit defaulted to 200mA\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -798,10 +838,12 @@ int _sd_storage_enable_highspeed(sdmmc_storage_t *storage, u32 hs_type, u8 *buf)
|
||||
{
|
||||
if (!_sd_storage_switch(storage, buf, SD_SWITCH_CHECK, 0, hs_type))
|
||||
return 0;
|
||||
DPRINTF("[SD] SD supports switch to (U)HS check\n");
|
||||
|
||||
u32 type_out = buf[16] & 0xF;
|
||||
if (type_out != hs_type)
|
||||
return 0;
|
||||
DPRINTF("[SD] SD supports selected (U)HS mode\n");
|
||||
|
||||
if ((((u16)buf[0] << 8) | buf[1]) < 0x320)
|
||||
{
|
||||
@ -830,31 +872,31 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8
|
||||
u32 hs_type = 0;
|
||||
switch (type)
|
||||
{
|
||||
case 11:
|
||||
case 11: // SDR104.
|
||||
// Fall through if not supported.
|
||||
if (buf[13] & SD_MODE_UHS_SDR104)
|
||||
{
|
||||
type = 11;
|
||||
hs_type = UHS_SDR104_BUS_SPEED;
|
||||
DPRINTF("[SD] Bus speed set to SDR104\n");
|
||||
DPRINTF("[SD] Bus speed set to SDR104\n");
|
||||
storage->csd.busspeed = 104;
|
||||
break;
|
||||
}
|
||||
//Fall through.
|
||||
case 10:
|
||||
case 10: // SDR50.
|
||||
if (buf[13] & SD_MODE_UHS_SDR50)
|
||||
{
|
||||
type = 10;
|
||||
hs_type = UHS_SDR50_BUS_SPEED;
|
||||
DPRINTF("[SD] Bus speed set to SDR50\n");
|
||||
DPRINTF("[SD] Bus speed set to SDR50\n");
|
||||
storage->csd.busspeed = 50;
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
case 8: // SDR12.
|
||||
if (!(buf[13] & SD_MODE_UHS_SDR12))
|
||||
return 0;
|
||||
type = 8;
|
||||
hs_type = UHS_SDR12_BUS_SPEED;
|
||||
DPRINTF("[SD] Bus speed set to SDR12\n");
|
||||
DPRINTF("[SD] Bus speed set to SDR12\n");
|
||||
storage->csd.busspeed = 12;
|
||||
break;
|
||||
default:
|
||||
@ -864,10 +906,13 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8
|
||||
|
||||
if (!_sd_storage_enable_highspeed(storage, hs_type, buf))
|
||||
return 0;
|
||||
DPRINTF("[SD] SD card accepted UHS\n");
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, type))
|
||||
return 0;
|
||||
DPRINTF("[SD] setup clock\n");
|
||||
if (!sdmmc_config_tuning(storage->sdmmc, type, MMC_SEND_TUNING_BLOCK))
|
||||
return 0;
|
||||
DPRINTF("[SD] config tuning\n");
|
||||
return _sdmmc_storage_check_status(storage);
|
||||
}
|
||||
|
||||
@ -876,13 +921,15 @@ int _sd_storage_enable_highspeed_high_volt(sdmmc_storage_t *storage, u8 *buf)
|
||||
if (!_sd_storage_switch_get(storage, buf))
|
||||
return 0;
|
||||
//gfx_hexdump(0, (u8 *)buf, 64);
|
||||
if (!(buf[13] & 2))
|
||||
if (!(buf[13] & SD_MODE_HIGH_SPEED))
|
||||
return 1;
|
||||
|
||||
if (!_sd_storage_enable_highspeed(storage, 1, buf))
|
||||
return 0;
|
||||
|
||||
if (!_sdmmc_storage_check_status(storage))
|
||||
return 0;
|
||||
|
||||
return sdmmc_setup_clock(storage->sdmmc, 7);
|
||||
}
|
||||
|
||||
@ -945,7 +992,7 @@ static int _sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf)
|
||||
|
||||
if (!(storage->csd.cmdclass & CCC_APP_SPEC))
|
||||
{
|
||||
DPRINTF("[SD] ssr: Card lacks mandatory SD Status function\n");
|
||||
DPRINTF("[SD] ssr: Card lacks mandatory SD Status function\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1007,44 +1054,54 @@ static void _sd_storage_parse_csd(sdmmc_storage_t *storage)
|
||||
}
|
||||
}
|
||||
|
||||
void sdmmc_storage_init_wait_sd()
|
||||
{
|
||||
u32 sd_poweroff_time = (u32)get_tmr_ms() - sd_power_cycle_time_start;
|
||||
if (sd_poweroff_time < 100)
|
||||
msleep(100 - sd_poweroff_time);
|
||||
}
|
||||
|
||||
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type)
|
||||
{
|
||||
int is_version_1 = 0;
|
||||
|
||||
// Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms.
|
||||
sdmmc_storage_init_wait_sd();
|
||||
|
||||
memset(storage, 0, sizeof(sdmmc_storage_t));
|
||||
storage->sdmmc = sdmmc;
|
||||
|
||||
if (!sdmmc_init(sdmmc, id, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, 5, 0))
|
||||
return 0;
|
||||
DPRINTF("[SD] after init\n");
|
||||
DPRINTF("[SD] after init\n");
|
||||
|
||||
usleep(1000 + (74000 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||
|
||||
if (!_sdmmc_storage_go_idle_state(storage))
|
||||
return 0;
|
||||
DPRINTF("[SD] went to idle state\n");
|
||||
DPRINTF("[SD] went to idle state\n");
|
||||
|
||||
is_version_1 = _sd_storage_send_if_cond(storage);
|
||||
if (is_version_1 == 2)
|
||||
return 0;
|
||||
DPRINTF("[SD] after send if cond\n");
|
||||
DPRINTF("[SD] after send if cond\n");
|
||||
|
||||
if (!_sd_storage_get_op_cond(storage, is_version_1, bus_width == SDMMC_BUS_WIDTH_4 && type == 11))
|
||||
return 0;
|
||||
DPRINTF("[SD] got op cond\n");
|
||||
DPRINTF("[SD] got op cond\n");
|
||||
|
||||
if (!_sdmmc_storage_get_cid(storage, storage->raw_cid))
|
||||
return 0;
|
||||
DPRINTF("[SD] got cid\n");
|
||||
DPRINTF("[SD] got cid\n");
|
||||
_sd_storage_parse_cid(storage);
|
||||
|
||||
if (!_sd_storage_get_rca(storage))
|
||||
return 0;
|
||||
DPRINTF("[SD] got rca (= %04X)\n", storage->rca);
|
||||
DPRINTF("[SD] got rca (= %04X)\n", storage->rca);
|
||||
|
||||
if (!_sdmmc_storage_get_csd(storage, storage->raw_csd))
|
||||
return 0;
|
||||
DPRINTF("[SD] got csd\n");
|
||||
DPRINTF("[SD] got csd\n");
|
||||
|
||||
//Parse CSD.
|
||||
_sd_storage_parse_csd(storage);
|
||||
@ -1057,7 +1114,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
||||
storage->sec_cnt = storage->csd.c_size << 10;
|
||||
break;
|
||||
default:
|
||||
DPRINTF("[SD] Unknown CSD structure %d\n", storage->csd.structure);
|
||||
DPRINTF("[SD] unknown CSD structure %d\n", storage->csd.structure);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1065,21 +1122,21 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
||||
{
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, 6))
|
||||
return 0;
|
||||
DPRINTF("[SD] after setup clock\n");
|
||||
DPRINTF("[SD] after setup clock\n");
|
||||
}
|
||||
|
||||
if (!_sdmmc_storage_select_card(storage))
|
||||
return 0;
|
||||
DPRINTF("[SD] card selected\n");
|
||||
DPRINTF("[SD] card selected\n");
|
||||
|
||||
if (!_sdmmc_storage_set_blocklen(storage, 512))
|
||||
return 0;
|
||||
DPRINTF("[SD] set blocklen to 512\n");
|
||||
DPRINTF("[SD] set blocklen to 512\n");
|
||||
|
||||
u32 tmp = 0;
|
||||
if (!_sd_storage_execute_app_cmd_type1(storage, &tmp, SD_APP_SET_CLR_CARD_DETECT, 0, 0, R1_STATE_TRAN))
|
||||
return 0;
|
||||
DPRINTF("[SD] cleared card detect\n");
|
||||
DPRINTF("[SD] cleared card detect\n");
|
||||
|
||||
u8 *buf = (u8 *)malloc(512);
|
||||
if (!_sd_storage_get_scr(storage, buf))
|
||||
@ -1087,9 +1144,9 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//gfx_hexdump(0, storage->raw_scr, 8);
|
||||
DPRINTF("[SD] got scr\n");
|
||||
DPRINTF("[SD] got scr\n");
|
||||
|
||||
// Check if card supports a wider bus and if it's not SD Version 1.X
|
||||
if (bus_width == SDMMC_BUS_WIDTH_4 && (storage->scr.bus_widths & 4) && (storage->scr.sda_vsn & 0xF))
|
||||
@ -1100,10 +1157,12 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
||||
return 0;
|
||||
}
|
||||
sdmmc_set_bus_width(storage->sdmmc, SDMMC_BUS_WIDTH_4);
|
||||
DPRINTF("[SD] switched to wide bus width\n");
|
||||
DPRINTF("[SD] switched to wide bus width\n");
|
||||
}
|
||||
else
|
||||
DPRINTF("[SD] SD does not support wide bus width\n");
|
||||
{
|
||||
DPRINTF("[SD] SD does not support wide bus width\n");
|
||||
}
|
||||
|
||||
if (storage->is_low_voltage)
|
||||
{
|
||||
@ -1112,7 +1171,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
DPRINTF("[SD] enabled highspeed (low voltage)\n");
|
||||
DPRINTF("[SD] enabled UHS\n");
|
||||
}
|
||||
else if (type != 6 && (storage->scr.sda_vsn & 0xF) != 0)
|
||||
{
|
||||
@ -1121,7 +1180,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
DPRINTF("[SD] enabled highspeed (high voltage)\n");
|
||||
DPRINTF("[SD] enabled HS\n");
|
||||
storage->csd.busspeed = 25;
|
||||
}
|
||||
|
||||
@ -1129,7 +1188,9 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
||||
|
||||
// Parse additional card info from sd status.
|
||||
if (_sd_storage_get_ssr(storage, buf))
|
||||
DPRINTF("[SD] got sd status\n");
|
||||
{
|
||||
DPRINTF("[SD] got sd status\n");
|
||||
}
|
||||
|
||||
free(buf);
|
||||
return 1;
|
||||
@ -1173,13 +1234,13 @@ int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc)
|
||||
|
||||
if (!sdmmc_init(sdmmc, SDMMC_2, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_8, 14, 0))
|
||||
return 0;
|
||||
DPRINTF("[gc] after init\n");
|
||||
DPRINTF("[gc] after init\n");
|
||||
|
||||
usleep(1000 + (10000 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||
|
||||
if (!sdmmc_config_tuning(storage->sdmmc, 14, MMC_SEND_TUNING_BLOCK_HS200))
|
||||
return 0;
|
||||
DPRINTF("[gc] after tuning\n");
|
||||
DPRINTF("[gc] after tuning\n");
|
||||
|
||||
sdmmc_sd_clock_ctrl(sdmmc, 1);
|
||||
|
||||
|
@ -21,6 +21,8 @@
|
||||
#include "../utils/types.h"
|
||||
#include "sdmmc_driver.h"
|
||||
|
||||
u32 sd_power_cycle_time_start;
|
||||
|
||||
typedef struct _mmc_cid
|
||||
{
|
||||
u32 manfid;
|
||||
@ -47,7 +49,7 @@ typedef struct _mmc_csd
|
||||
u32 read_blkbits;
|
||||
u32 write_blkbits;
|
||||
u32 capacity;
|
||||
u8 write_protect;
|
||||
u8 write_protect;
|
||||
u16 busspeed;
|
||||
} mmc_csd_t;
|
||||
|
||||
@ -107,6 +109,7 @@ int sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, vo
|
||||
int sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf);
|
||||
int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type);
|
||||
int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition);
|
||||
void sdmmc_storage_init_wait_sd();
|
||||
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type);
|
||||
int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc);
|
||||
|
||||
|
@ -17,18 +17,19 @@
|
||||
|
||||
#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/bpmp.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"
|
||||
#define DPRINTF(...) gfx_printf(__VA_ARGS__)*/
|
||||
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
|
||||
#define DPRINTF(...)
|
||||
|
||||
/*! SCMMC controller base addresses. */
|
||||
@ -76,7 +77,7 @@ static int _sdmmc_set_voltage(sdmmc_t *sdmmc, u32 power)
|
||||
{
|
||||
pwr |= TEGRA_MMC_PWRCTL_SD_BUS_POWER;
|
||||
sdmmc->regs->pwrcon = pwr;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -116,11 +117,12 @@ static int _sdmmc_config_ven_ceata_clk(sdmmc_t *sdmmc, u32 id)
|
||||
|
||||
if (id == 4)
|
||||
sdmmc->regs->venceatactl = (sdmmc->regs->venceatactl & 0xFFFFC0FF) | 0x2800;
|
||||
sdmmc->regs->field_1C0 &= 0xFFFDFFFF;
|
||||
sdmmc->regs->ventunctl0 &= 0xFFFDFFFF;
|
||||
if (id == 4)
|
||||
{
|
||||
if (!sdmmc->venclkctl_set)
|
||||
return 0;
|
||||
|
||||
tap_val = sdmmc->venclkctl_tap;
|
||||
}
|
||||
else
|
||||
@ -168,11 +170,11 @@ static int _sdmmc_wait_type4(sdmmc_t *sdmmc)
|
||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
}
|
||||
|
||||
sdmmc->regs->field_1B0 |= 0x80000000;
|
||||
sdmmc->regs->vendllcal |= 0x80000000;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
|
||||
u32 timeout = get_tmr_ms() + 5;
|
||||
while (sdmmc->regs->field_1B0 & 0x80000000)
|
||||
while (sdmmc->regs->vendllcal & 0x80000000)
|
||||
{
|
||||
if (get_tmr_ms() > timeout)
|
||||
{
|
||||
@ -182,7 +184,7 @@ static int _sdmmc_wait_type4(sdmmc_t *sdmmc)
|
||||
}
|
||||
|
||||
timeout = get_tmr_ms() + 10;
|
||||
while (sdmmc->regs->field_1BC & 0x80000000)
|
||||
while (sdmmc->regs->dllcfgstatus & 0x80000000)
|
||||
{
|
||||
if (get_tmr_ms() > timeout)
|
||||
{
|
||||
@ -199,7 +201,7 @@ out:;
|
||||
|
||||
int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type)
|
||||
{
|
||||
//Disable the SD clock if it was enabled, and reenable it later.
|
||||
// Disable the SD clock if it was enabled, and reenable it later.
|
||||
bool should_enable_sd_clock = false;
|
||||
if (sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)
|
||||
{
|
||||
@ -215,7 +217,7 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type)
|
||||
case 1:
|
||||
case 5:
|
||||
case 6:
|
||||
sdmmc->regs->hostctl &= 0xFB; //Should this be 0xFFFB (~4) ?
|
||||
sdmmc->regs->hostctl &= 0xFB; // Should this be 0xFFFB (~4) ?
|
||||
sdmmc->regs->hostctl2 &= SDHCI_CTRL_VDD_330;
|
||||
break;
|
||||
case 2:
|
||||
@ -231,7 +233,7 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type)
|
||||
sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180;
|
||||
break;
|
||||
case 4:
|
||||
//Non standard
|
||||
// Non standard.
|
||||
sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | HS400_BUS_SPEED;
|
||||
sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180;
|
||||
break;
|
||||
@ -240,7 +242,7 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type)
|
||||
sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180;
|
||||
break;
|
||||
case 10:
|
||||
//T210 Errata for SDR50, the host must be set to SDR104.
|
||||
// T210 Errata for SDR50, the host must be set to SDR104.
|
||||
sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR104_BUS_SPEED;
|
||||
sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180;
|
||||
break;
|
||||
@ -262,7 +264,7 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type)
|
||||
divisor = div >> 8;
|
||||
sdmmc->regs->clkcon = (sdmmc->regs->clkcon & 0x3F) | (div << 8) | (divisor << 6);
|
||||
|
||||
//Enable the SD clock again.
|
||||
// Enable the SD clock again.
|
||||
if (should_enable_sd_clock)
|
||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
|
||||
@ -383,7 +385,7 @@ int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type)
|
||||
|
||||
static void _sdmmc_reset(sdmmc_t *sdmmc)
|
||||
{
|
||||
sdmmc->regs->swrst |=
|
||||
sdmmc->regs->swrst |=
|
||||
TEGRA_MMC_SWRST_SW_RESET_FOR_CMD_LINE | TEGRA_MMC_SWRST_SW_RESET_FOR_DAT_LINE;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
u32 timeout = get_tmr_ms() + 2000;
|
||||
@ -396,7 +398,7 @@ static int _sdmmc_wait_prnsts_type0(sdmmc_t *sdmmc, u32 wait_dat)
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
|
||||
u32 timeout = get_tmr_ms() + 2000;
|
||||
while(sdmmc->regs->prnsts & 1) //CMD inhibit.
|
||||
while(sdmmc->regs->prnsts & 1) // CMD inhibit.
|
||||
if (get_tmr_ms() > timeout)
|
||||
{
|
||||
_sdmmc_reset(sdmmc);
|
||||
@ -406,7 +408,7 @@ static int _sdmmc_wait_prnsts_type0(sdmmc_t *sdmmc, u32 wait_dat)
|
||||
if (wait_dat)
|
||||
{
|
||||
timeout = get_tmr_ms() + 2000;
|
||||
while (sdmmc->regs->prnsts & 2) //DAT inhibit.
|
||||
while (sdmmc->regs->prnsts & 2) // DAT inhibit.
|
||||
if (get_tmr_ms() > timeout)
|
||||
{
|
||||
_sdmmc_reset(sdmmc);
|
||||
@ -422,7 +424,7 @@ static int _sdmmc_wait_prnsts_type1(sdmmc_t *sdmmc)
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
|
||||
u32 timeout = get_tmr_ms() + 2000;
|
||||
while (!(sdmmc->regs->prnsts & 0x100000)) //DAT0 line level.
|
||||
while (!(sdmmc->regs->prnsts & 0x100000)) // DAT0 line level.
|
||||
if (get_tmr_ms() > timeout)
|
||||
{
|
||||
_sdmmc_reset(sdmmc);
|
||||
@ -454,7 +456,7 @@ static int _sdmmc_setup_read_small_block(sdmmc_t *sdmmc)
|
||||
static int _sdmmc_parse_cmdbuf(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, bool is_data_present)
|
||||
{
|
||||
u16 cmdflags = 0;
|
||||
|
||||
|
||||
switch (cmd->rsp_type)
|
||||
{
|
||||
case SDMMC_RSP_TYPE_0:
|
||||
@ -509,13 +511,17 @@ static int _sdmmc_config_tuning_once(sdmmc_t *sdmmc, u32 cmd)
|
||||
return 0;
|
||||
|
||||
_sdmmc_setup_read_small_block(sdmmc);
|
||||
|
||||
sdmmc->regs->norintstsen |= TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY;
|
||||
sdmmc->regs->norintsts = sdmmc->regs->norintsts;
|
||||
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
|
||||
_sdmmc_parse_cmd_48(sdmmc, cmd);
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
usleep(1);
|
||||
|
||||
_sdmmc_reset(sdmmc);
|
||||
|
||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
|
||||
@ -531,10 +537,13 @@ static int _sdmmc_config_tuning_once(sdmmc_t *sdmmc, u32 cmd)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
_sdmmc_reset(sdmmc);
|
||||
|
||||
sdmmc->regs->norintstsen &= 0xFFDF;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
usleep((1000 * 8 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -561,9 +570,9 @@ int sdmmc_config_tuning(sdmmc_t *sdmmc, u32 type, u32 cmd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
sdmmc->regs->field_1C0 = (sdmmc->regs->field_1C0 & 0xFFFF1FFF) | flag;
|
||||
sdmmc->regs->field_1C0 = (sdmmc->regs->field_1C0 & 0xFFFFE03F) | 0x40;
|
||||
sdmmc->regs->field_1C0 |= 0x20000;
|
||||
sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFF1FFF) | flag; // Tries.
|
||||
sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFFE03F) | 0x40; // Multiplier.
|
||||
sdmmc->regs->ventunctl0 |= 0x20000;
|
||||
sdmmc->regs->hostctl2 |= SDHCI_CTRL_EXEC_TUNING;
|
||||
|
||||
for (u32 i = 0; i < max; i++)
|
||||
@ -575,6 +584,7 @@ int sdmmc_config_tuning(sdmmc_t *sdmmc, u32 type, u32 cmd)
|
||||
|
||||
if (sdmmc->regs->hostctl2 & SDHCI_CTRL_TUNED_CLK)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -664,7 +674,7 @@ static void _sdmmc_autocal_execute(sdmmc_t *sdmmc, u32 power)
|
||||
{
|
||||
if (get_tmr_ms() > timeout)
|
||||
{
|
||||
//In case autocalibration fails, we load suggested standard values.
|
||||
// In case autocalibration fails, we load suggested standard values.
|
||||
_sdmmc_pad_config_fallback(sdmmc, power);
|
||||
sdmmc->regs->autocalcfg &= 0xDFFFFFFF;
|
||||
break;
|
||||
@ -701,7 +711,7 @@ static int _sdmmc_check_mask_interrupt(sdmmc_t *sdmmc, u16 *pout, u16 mask)
|
||||
if (pout)
|
||||
*pout = norintsts;
|
||||
|
||||
//Check for error interrupt.
|
||||
// Check for error interrupt.
|
||||
if (norintsts & TEGRA_MMC_NORINTSTS_ERR_INTERRUPT)
|
||||
{
|
||||
sdmmc->regs->errintsts = errintsts;
|
||||
@ -712,7 +722,7 @@ static int _sdmmc_check_mask_interrupt(sdmmc_t *sdmmc, u16 *pout, u16 mask)
|
||||
sdmmc->regs->norintsts = norintsts & mask;
|
||||
return SDMMC_MASKINT_MASKED;
|
||||
}
|
||||
|
||||
|
||||
return SDMMC_MASKINT_NOERROR;
|
||||
}
|
||||
|
||||
@ -744,18 +754,22 @@ static int _sdmmc_stop_transmission_inner(sdmmc_t *sdmmc, u32 *rsp)
|
||||
return 0;
|
||||
|
||||
_sdmmc_enable_interrupts(sdmmc);
|
||||
|
||||
cmd.cmd = MMC_STOP_TRANSMISSION;
|
||||
cmd.arg = 0;
|
||||
cmd.rsp_type = SDMMC_RSP_TYPE_1;
|
||||
cmd.check_busy = 1;
|
||||
|
||||
_sdmmc_parse_cmdbuf(sdmmc, &cmd, false);
|
||||
|
||||
int res = _sdmmc_wait_request(sdmmc);
|
||||
_sdmmc_mask_interrupts(sdmmc);
|
||||
|
||||
if (!res)
|
||||
return 0;
|
||||
|
||||
|
||||
_sdmmc_cache_rsp(sdmmc, rsp, 4, SDMMC_RSP_TYPE_1);
|
||||
|
||||
return _sdmmc_wait_prnsts_type1(sdmmc);
|
||||
}
|
||||
|
||||
@ -775,6 +789,7 @@ int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp)
|
||||
|
||||
int res = _sdmmc_stop_transmission_inner(sdmmc, rsp);
|
||||
usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||
|
||||
if (should_disable_sd_clock)
|
||||
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
|
||||
@ -791,7 +806,7 @@ static int _sdmmc_config_dma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req)
|
||||
blkcnt = 0xFFFF;
|
||||
u32 admaaddr = (u32)req->buf;
|
||||
|
||||
//Check alignment.
|
||||
// Check alignment.
|
||||
if (admaaddr << 29)
|
||||
return 0;
|
||||
|
||||
@ -815,7 +830,7 @@ static int _sdmmc_config_dma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req)
|
||||
trnmode |= TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ;
|
||||
if (req->is_auto_cmd12)
|
||||
trnmode = (trnmode & 0xFFF3) | TEGRA_MMC_TRNMOD_AUTO_CMD12;
|
||||
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY);
|
||||
sdmmc->regs->trnmod = trnmode;
|
||||
|
||||
return 1;
|
||||
@ -834,15 +849,18 @@ static int _sdmmc_update_dma(sdmmc_t *sdmmc)
|
||||
while (1)
|
||||
{
|
||||
u16 intr = 0;
|
||||
res = _sdmmc_check_mask_interrupt(sdmmc, &intr,
|
||||
res = _sdmmc_check_mask_interrupt(sdmmc, &intr,
|
||||
TEGRA_MMC_NORINTSTS_XFER_COMPLETE | TEGRA_MMC_NORINTSTS_DMA_INTERRUPT);
|
||||
if (res < 0)
|
||||
break;
|
||||
if (intr & TEGRA_MMC_NORINTSTS_XFER_COMPLETE)
|
||||
return 1; //Transfer complete.
|
||||
{
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY);
|
||||
return 1; // Transfer complete.
|
||||
}
|
||||
if (intr & TEGRA_MMC_NORINTSTS_DMA_INTERRUPT)
|
||||
{
|
||||
//Update DMA.
|
||||
// Update DMA.
|
||||
sdmmc->regs->admaaddr = sdmmc->dma_addr_next;
|
||||
sdmmc->regs->admaaddr_hi = 0;
|
||||
sdmmc->dma_addr_next += 0x80000;
|
||||
@ -883,7 +901,7 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_
|
||||
_sdmmc_parse_cmdbuf(sdmmc, cmd, is_data_present);
|
||||
|
||||
int res = _sdmmc_wait_request(sdmmc);
|
||||
DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", res,
|
||||
DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", res,
|
||||
sdmmc->regs->rspreg0, sdmmc->regs->rspreg1, sdmmc->regs->rspreg2, sdmmc->regs->rspreg3);
|
||||
if (res)
|
||||
{
|
||||
@ -904,6 +922,7 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_
|
||||
{
|
||||
if (blkcnt_out)
|
||||
*blkcnt_out = blkcnt;
|
||||
|
||||
if (req->is_auto_cmd12)
|
||||
sdmmc->rsp3 = sdmmc->regs->rspreg3;
|
||||
}
|
||||
@ -917,12 +936,14 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_
|
||||
|
||||
static int _sdmmc_config_sdmmc1()
|
||||
{
|
||||
//Configure SD card detect.
|
||||
// Configure SD card detect.
|
||||
PINMUX_AUX(PINMUX_AUX_GPIO_PZ1) = PINMUX_INPUT_ENABLE | PINMUX_PULL_UP | 1; //GPIO control, pull up.
|
||||
APB_MISC(APB_MISC_GP_VGPIO_GPIO_MUX_SEL) = 0;
|
||||
gpio_config(GPIO_PORT_Z, GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||
gpio_output_enable(GPIO_PORT_Z, GPIO_PIN_1, GPIO_OUTPUT_DISABLE);
|
||||
usleep(100);
|
||||
|
||||
// Check if SD card is inserted.
|
||||
if(!!gpio_read(GPIO_PORT_Z, GPIO_PIN_1))
|
||||
return 0;
|
||||
|
||||
@ -935,8 +956,8 @@ static int _sdmmc_config_sdmmc1()
|
||||
* APB_MISC_GP_SDMMCx_CLK_LPBK_CONTROL = SDMMCx_CLK_PAD_E_LPBK for CLK
|
||||
*/
|
||||
|
||||
//Configure SDMMC1 pinmux.
|
||||
APB_MISC(APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL) = 1;
|
||||
// Configure SDMMC1 pinmux.
|
||||
APB_MISC(APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL) = 1; // Enable deep loopback for SDMMC1 CLK pad.
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED;
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_CMD) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP;
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT3) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP;
|
||||
@ -944,12 +965,12 @@ static int _sdmmc_config_sdmmc1()
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP;
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP;
|
||||
|
||||
//Make sure the SDMMC1 controller is powered.
|
||||
// Make sure the SDMMC1 controller is powered.
|
||||
PMC(APBDEV_PMC_NO_IOPOWER) &= ~(1 << 12);
|
||||
//Assume 3.3V SD card voltage.
|
||||
// Assume 3.3V SD card voltage.
|
||||
PMC(APBDEV_PMC_PWR_DET_VAL) |= (1 << 12);
|
||||
|
||||
//Set enable SD card power.
|
||||
// Set enable SD card power.
|
||||
PINMUX_AUX(PINMUX_AUX_DMIC3_CLK) = PINMUX_INPUT_ENABLE | PINMUX_PULL_DOWN | 1; //GPIO control, pull down.
|
||||
gpio_config(GPIO_PORT_E, GPIO_PIN_4, GPIO_MODE_GPIO);
|
||||
gpio_write(GPIO_PORT_E, GPIO_PIN_4, GPIO_HIGH);
|
||||
@ -957,13 +978,13 @@ static int _sdmmc_config_sdmmc1()
|
||||
|
||||
usleep(1000);
|
||||
|
||||
//Enable SD card power.
|
||||
// Enable SD card power.
|
||||
max77620_regulator_set_voltage(REGULATOR_LDO2, 3300000);
|
||||
max77620_regulator_enable(REGULATOR_LDO2, 1);
|
||||
|
||||
usleep(1000);
|
||||
|
||||
//For good measure.
|
||||
// For good measure.
|
||||
APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = 0x10000000;
|
||||
|
||||
usleep(1000);
|
||||
@ -1000,25 +1021,30 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int n
|
||||
sdmmc->clock_stopped = 0;
|
||||
|
||||
//TODO: make this skip-able.
|
||||
sdmmc->regs->field_1F0 |= 0x80000;
|
||||
sdmmc->regs->field_1AC &= 0xFFFFFFFB;
|
||||
sdmmc->regs->iospare |= 0x80000;
|
||||
sdmmc->regs->veniotrimctl &= 0xFFFFFFFB;
|
||||
static const u32 trim_values[] = { 2, 8, 3, 8 };
|
||||
sdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & 0xE0FFFFFF) | (trim_values[sdmmc->id] << 24);
|
||||
sdmmc->regs->sdmemcmppadctl = (sdmmc->regs->sdmemcmppadctl & 0xF) | 7;
|
||||
if (!_sdmmc_autocal_config_offset(sdmmc, power))
|
||||
return 0;
|
||||
|
||||
_sdmmc_autocal_execute(sdmmc, power);
|
||||
|
||||
if (_sdmmc_enable_internal_clock(sdmmc))
|
||||
{
|
||||
sdmmc_set_bus_width(sdmmc, bus_width);
|
||||
_sdmmc_set_voltage(sdmmc, power);
|
||||
|
||||
if (sdmmc_setup_clock(sdmmc, type))
|
||||
{
|
||||
sdmmc_sd_clock_ctrl(sdmmc, no_sd);
|
||||
_sdmmc_sd_clock_enable(sdmmc);
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
@ -1029,14 +1055,16 @@ void sdmmc_end(sdmmc_t *sdmmc)
|
||||
if (!sdmmc->clock_stopped)
|
||||
{
|
||||
_sdmmc_sd_clock_disable(sdmmc);
|
||||
// Disable SDMMC power.
|
||||
// Disable SDMMC power.
|
||||
_sdmmc_set_voltage(sdmmc, SDMMC_POWER_OFF);
|
||||
|
||||
// Disable SD card power.
|
||||
if (sdmmc->id == SDMMC_1)
|
||||
{
|
||||
gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_DISABLE);
|
||||
msleep(1); // To power cycle min 1ms without power is needed.
|
||||
max77620_regulator_enable(REGULATOR_LDO2, 0);
|
||||
sd_power_cycle_time_start = get_tmr_ms(); // Some sandisc U1 cards need 100ms for a power cycle.
|
||||
usleep(1000); // To power cycle, min 1ms without power is needed.
|
||||
}
|
||||
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
@ -1058,7 +1086,7 @@ int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *b
|
||||
if (!sdmmc->sd_clock_enabled)
|
||||
return 0;
|
||||
|
||||
//Recalibrate periodically for SDMMC1.
|
||||
// Recalibrate periodically for SDMMC1.
|
||||
if (sdmmc->id == SDMMC_1 && sdmmc->no_sd)
|
||||
_sdmmc_autocal_execute(sdmmc, sdmmc_get_voltage(sdmmc));
|
||||
|
||||
@ -1073,6 +1101,7 @@ int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *b
|
||||
|
||||
int res = _sdmmc_execute_cmd_inner(sdmmc, cmd, req, blkcnt_out);
|
||||
usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||
|
||||
if (should_disable_sd_clock)
|
||||
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
|
||||
@ -1089,6 +1118,14 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc)
|
||||
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
|
||||
// Enable schmitt trigger for better duty cycle and low jitter clock.
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) |= PINMUX_SCHMT;
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_CMD) |= PINMUX_SCHMT;
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT3) |= PINMUX_SCHMT;
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT2) |= PINMUX_SCHMT;
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) |= PINMUX_SCHMT;
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) |= PINMUX_SCHMT;
|
||||
|
||||
max77620_regulator_set_voltage(REGULATOR_LDO2, 1800000);
|
||||
PMC(APBDEV_PMC_PWR_DET_VAL) &= ~(1 << 12);
|
||||
|
||||
@ -1097,12 +1134,12 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc)
|
||||
_sdmmc_set_voltage(sdmmc, SDMMC_POWER_1_8);
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
msleep(5);
|
||||
|
||||
|
||||
if (sdmmc->regs->hostctl2 & SDHCI_CTRL_VDD_180)
|
||||
{
|
||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
msleep(1);
|
||||
usleep(1000);
|
||||
if ((sdmmc->regs->prnsts & 0xF00000) == 0xF00000)
|
||||
return 1;
|
||||
}
|
||||
|
@ -115,18 +115,18 @@ typedef struct _t210_sdmmc_t
|
||||
vu32 vendebouncecnt;
|
||||
vu32 venmiscctl;
|
||||
vu32 res6[34];
|
||||
vu32 field_1AC;
|
||||
vu32 field_1B0;
|
||||
vu32 veniotrimctl;
|
||||
vu32 vendllcal;
|
||||
vu8 res7[8];
|
||||
vu32 field_1BC;
|
||||
vu32 field_1C0;
|
||||
vu32 dllcfgstatus;
|
||||
vu32 ventunctl0;
|
||||
vu32 field_1C4;
|
||||
vu8 field_1C8[24];
|
||||
vu32 sdmemcmppadctl;
|
||||
vu32 autocalcfg;
|
||||
vu32 autocalintval;
|
||||
vu32 autocalsts;
|
||||
vu32 field_1F0;
|
||||
vu32 iospare;
|
||||
} t210_sdmmc_t;
|
||||
|
||||
#endif
|
||||
|
@ -29,7 +29,7 @@ u8 btn_read()
|
||||
res |= BTN_VOL_DOWN;
|
||||
if (!gpio_read(GPIO_PORT_X, GPIO_PIN_6))
|
||||
res |= BTN_VOL_UP;
|
||||
if (i2c_recv_byte(4, MAX77620_I2C_ADDR, 0x15) & 0x4)
|
||||
if (i2c_recv_byte(4, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFSTAT) & 0x4)
|
||||
res |= BTN_POWER;
|
||||
return res;
|
||||
}
|
||||
|
94
source/utils/dirlist.c
Normal file
94
source/utils/dirlist.c
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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 "../libs/fatfs/ff.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../utils/types.h"
|
||||
|
||||
char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles)
|
||||
{
|
||||
u8 max_entries = 61;
|
||||
|
||||
int res = 0;
|
||||
u32 i = 0, j = 0, k = 0;
|
||||
DIR dir;
|
||||
FILINFO fno;
|
||||
|
||||
char *dir_entries = (char *)calloc(max_entries, 256);
|
||||
char *temp = (char *)calloc(1, 256);
|
||||
|
||||
if (!pattern && !f_opendir(&dir, directory))
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
res = f_readdir(&dir, &fno);
|
||||
if (res || !fno.fname[0])
|
||||
break;
|
||||
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++;
|
||||
if (k > (max_entries - 1))
|
||||
break;
|
||||
}
|
||||
}
|
||||
f_closedir(&dir);
|
||||
}
|
||||
else if (pattern && !f_findfirst(&dir, &fno, directory, pattern) && fno.fname[0])
|
||||
{
|
||||
do
|
||||
{
|
||||
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++;
|
||||
if (k > (max_entries - 1))
|
||||
break;
|
||||
}
|
||||
res = f_findnext(&dir, &fno);
|
||||
} while (fno.fname[0] && !res);
|
||||
f_closedir(&dir);
|
||||
}
|
||||
|
||||
if (!k)
|
||||
{
|
||||
free(temp);
|
||||
free(dir_entries);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Reorder ini files by ASCII ordering.
|
||||
for (i = 0; i < k - 1 ; i++)
|
||||
{
|
||||
for (j = i + 1; j < k; j++)
|
||||
{
|
||||
if (strcmp(&dir_entries[i * 256], &dir_entries[j * 256]) > 0)
|
||||
{
|
||||
memcpy(temp, &dir_entries[i * 256], strlen(&dir_entries[i * 256]) + 1);
|
||||
memcpy(&dir_entries[i * 256], &dir_entries[j * 256], strlen(&dir_entries[j * 256]) + 1);
|
||||
memcpy(&dir_entries[j * 256], temp, strlen(temp) + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(temp);
|
||||
|
||||
return dir_entries;
|
||||
}
|
19
source/utils/dirlist.h
Normal file
19
source/utils/dirlist.h
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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 "../utils/types.h"
|
||||
|
||||
char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles);
|
123
source/utils/sprintf.c
Normal file
123
source/utils/sprintf.c
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (c) 2019 shchmue
|
||||
*
|
||||
* 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 "sprintf.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
static void _putc(char *buffer, const char c) {
|
||||
*buffer = c;
|
||||
}
|
||||
|
||||
static u32 _puts(char *buffer, const char *s) {
|
||||
u32 count = 0;
|
||||
for (; *s; s++, count++)
|
||||
_putc(buffer + count, *s);
|
||||
return count;
|
||||
}
|
||||
|
||||
static u32 _putn(char *buffer, u32 v, int base, char fill, int fcnt) {
|
||||
char buf[0x121];
|
||||
static const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
char *p;
|
||||
int c = fcnt;
|
||||
|
||||
if (base > 36)
|
||||
return 0;
|
||||
|
||||
p = buf + 0x120;
|
||||
*p = 0;
|
||||
do {
|
||||
c--;
|
||||
*--p = digits[v % base];
|
||||
v /= base;
|
||||
} while (v);
|
||||
|
||||
if (fill != 0) {
|
||||
while (c > 0) {
|
||||
*--p = fill;
|
||||
c--;
|
||||
}
|
||||
}
|
||||
|
||||
return _puts(buffer, p);
|
||||
}
|
||||
|
||||
u32 sprintf(char *buffer, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
int fill, fcnt;
|
||||
u32 count = 0;
|
||||
|
||||
va_start(ap, fmt);
|
||||
while(*fmt) {
|
||||
if (*fmt == '%') {
|
||||
fmt++;
|
||||
fill = 0;
|
||||
fcnt = 0;
|
||||
if ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ') {
|
||||
fcnt = *fmt;
|
||||
fmt++;
|
||||
if (*fmt >= '0' && *fmt <= '9') {
|
||||
fill = fcnt;
|
||||
fcnt = *fmt - '0';
|
||||
fmt++;
|
||||
} else {
|
||||
fill = ' ';
|
||||
fcnt -= '0';
|
||||
}
|
||||
}
|
||||
switch (*fmt) {
|
||||
case 'c':
|
||||
_putc(buffer + count, va_arg(ap, u32));
|
||||
count++;
|
||||
break;
|
||||
case 's':
|
||||
count += _puts(buffer + count, va_arg(ap, char *));
|
||||
break;
|
||||
case 'd':
|
||||
count += _putn(buffer + count, va_arg(ap, u32), 10, fill, fcnt);
|
||||
break;
|
||||
case 'p':
|
||||
case 'P':
|
||||
case 'x':
|
||||
case 'X':
|
||||
count += _putn(buffer + count, va_arg(ap, u32), 16, fill, fcnt);
|
||||
break;
|
||||
case '%':
|
||||
_putc(buffer + count, '%');
|
||||
count++;
|
||||
break;
|
||||
case '\0':
|
||||
goto out;
|
||||
default:
|
||||
_putc(buffer + count, '%');
|
||||
count++;
|
||||
_putc(buffer + count, *fmt);
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
_putc(buffer + count, *fmt);
|
||||
count++;
|
||||
}
|
||||
fmt++;
|
||||
}
|
||||
|
||||
out:
|
||||
buffer[count] = 0;
|
||||
va_end(ap);
|
||||
return count;
|
||||
}
|
24
source/utils/sprintf.h
Normal file
24
source/utils/sprintf.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2019 shchmue
|
||||
*
|
||||
* 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 _SPRINTF_H_
|
||||
#define _SPRINTF_H_
|
||||
|
||||
#include "types.h"
|
||||
|
||||
u32 sprintf(char *buffer, const char *fmt, ...);
|
||||
|
||||
#endif
|
@ -34,7 +34,9 @@
|
||||
#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 KB_FIRMWARE_VERSION_810 8
|
||||
#define KB_FIRMWARE_VERSION_900 9
|
||||
#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_900
|
||||
|
||||
#define HOS_PKG11_MAGIC 0x31314B50
|
||||
|
||||
@ -66,6 +68,8 @@ typedef volatile unsigned char vu8;
|
||||
typedef volatile unsigned short vu16;
|
||||
typedef volatile unsigned int vu32;
|
||||
|
||||
static const u32 colors[6] = {COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_GREEN, COLOR_BLUE, COLOR_VIOLET};
|
||||
|
||||
typedef int bool;
|
||||
#define true 1
|
||||
#define false 0
|
||||
@ -74,13 +78,22 @@ typedef int bool;
|
||||
#define BOOT_CFG_FROM_LAUNCH (1 << 1)
|
||||
#define BOOT_CFG_SEPT_RUN (1 << 7)
|
||||
|
||||
#define EXTRA_CFG_DUMP_EMUMMC (1 << 0)
|
||||
|
||||
typedef struct __attribute__((__packed__)) _boot_cfg_t
|
||||
{
|
||||
u8 boot_cfg;
|
||||
u8 autoboot;
|
||||
u8 autoboot_list;
|
||||
u8 extra_cfg;
|
||||
u8 rsvd[128];
|
||||
u8 boot_cfg;
|
||||
u8 autoboot;
|
||||
u8 autoboot_list;
|
||||
u8 extra_cfg;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
char id[8];
|
||||
};
|
||||
u8 xt_str[0x80];
|
||||
};
|
||||
} boot_cfg_t;
|
||||
|
||||
typedef struct __attribute__((__packed__)) _reloc_meta_t
|
||||
|
@ -19,10 +19,13 @@
|
||||
#include "../gfx/di.h"
|
||||
#include "../power/max77620.h"
|
||||
#include "../rtc/max77620-rtc.h"
|
||||
#include "../soc/bpmp.h"
|
||||
#include "../soc/i2c.h"
|
||||
#include "../soc/pmc.h"
|
||||
#include "../soc/t210.h"
|
||||
|
||||
#define USE_RTC_TIMER
|
||||
|
||||
extern void sd_unmount();
|
||||
|
||||
u32 get_tmr_s()
|
||||
@ -34,7 +37,7 @@ u32 get_tmr_ms()
|
||||
{
|
||||
// The registers must be read with the following order:
|
||||
// RTC_MILLI_SECONDS (0x10) -> RTC_SHADOW_SECONDS (0xC)
|
||||
return (RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10));
|
||||
return (RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000));
|
||||
}
|
||||
|
||||
u32 get_tmr_us()
|
||||
@ -42,19 +45,32 @@ u32 get_tmr_us()
|
||||
return TMR(TIMERUS_CNTR_1US); //TIMERUS_CNTR_1US
|
||||
}
|
||||
|
||||
void msleep(u32 milliseconds)
|
||||
void msleep(u32 ms)
|
||||
{
|
||||
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)
|
||||
#ifdef USE_RTC_TIMER
|
||||
u32 start = RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000);
|
||||
// Casting to u32 is important!
|
||||
while (((u32)(RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000)) - start) <= ms)
|
||||
;
|
||||
#else
|
||||
bpmp_msleep(ms);
|
||||
#endif
|
||||
}
|
||||
|
||||
void usleep(u32 microseconds)
|
||||
void usleep(u32 us)
|
||||
{
|
||||
#ifdef USE_RTC_TIMER
|
||||
u32 start = TMR(TIMERUS_CNTR_1US);
|
||||
// Casting to u32 is important!
|
||||
while ((u32)(TMR(TIMERUS_CNTR_1US) - start) <= microseconds)
|
||||
;
|
||||
|
||||
// Check if timer is at upper limits and use BPMP sleep so it doesn't wake up immediately.
|
||||
if ((start + us) < start)
|
||||
bpmp_usleep(us);
|
||||
else
|
||||
while ((u32)(TMR(TIMERUS_CNTR_1US) - start) <= us) // Casting to u32 is important!
|
||||
;
|
||||
#else
|
||||
bpmp_usleep(us);
|
||||
#endif
|
||||
}
|
||||
|
||||
void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops)
|
||||
@ -72,12 +88,15 @@ void panic(u32 val)
|
||||
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)
|
||||
;
|
||||
|
||||
while (true)
|
||||
usleep(1);
|
||||
}
|
||||
|
||||
void reboot_normal()
|
||||
{
|
||||
bpmp_mmu_disable();
|
||||
|
||||
sd_unmount();
|
||||
display_end();
|
||||
|
||||
@ -86,6 +105,8 @@ void reboot_normal()
|
||||
|
||||
void reboot_rcm()
|
||||
{
|
||||
bpmp_mmu_disable();
|
||||
|
||||
sd_unmount();
|
||||
display_end();
|
||||
|
||||
@ -93,58 +114,19 @@ void reboot_rcm()
|
||||
PMC(APBDEV_PMC_CNTRL) |= PMC_CNTRL_MAIN_RST;
|
||||
|
||||
while (true)
|
||||
usleep(1);
|
||||
bpmp_halt();
|
||||
}
|
||||
|
||||
void power_off()
|
||||
{
|
||||
sd_unmount();
|
||||
display_end();
|
||||
|
||||
// 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)
|
||||
{
|
||||
const u8 *cbuf = (const u8 *)buf;
|
||||
u32 crc = 0xFFFFFFFF;
|
||||
while (len--)
|
||||
{
|
||||
crc ^= *cbuf++;
|
||||
for (int i = 0; i < 8; i++)
|
||||
crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLY : crc >> 1;
|
||||
}
|
||||
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;
|
||||
|
||||
while (true)
|
||||
bpmp_halt();
|
||||
}
|
||||
|
@ -32,17 +32,12 @@ typedef struct _cfg_op_t
|
||||
u32 get_tmr_us();
|
||||
u32 get_tmr_ms();
|
||||
u32 get_tmr_s();
|
||||
void usleep(u32 ticks);
|
||||
void msleep(u32 milliseconds);
|
||||
void usleep(u32 us);
|
||||
void msleep(u32 ms);
|
||||
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
|
||||
|
Reference in New Issue
Block a user