Compare commits

..

49 Commits
1.5.0 ... 2.0.1

Author SHA1 Message Date
Such Meme, Many Skill
00a58f12ec Bump version 2020-05-04 20:49:23 +02:00
Such Meme, Many Skill
74ba5bb776 Fix broken menus 2020-05-04 20:48:23 +02:00
Such Meme, Many Skill
a9ea9725d4 Speed up copy & formats 2020-05-04 20:30:51 +02:00
Such Meme, Many Skill
9799e2b47e Small optimizations 2020-05-04 13:55:26 +02:00
Such Meme, Many Skill
6681a35b2c Revert some changes 2020-05-03 13:22:37 +02:00
Such Meme, Many Skill
22ecb34fec Bump version 2020-05-03 02:17:36 +02:00
Such Meme, Many Skill
cb46e4bc40 Add screenshot feature 2020-05-03 02:00:04 +02:00
Such Meme, Many Skill
6c2d0cf162 small fixes 2020-05-03 00:30:05 +02:00
Such Meme, Many Skill
4907afd9f3 forget to wait on user input on hidWaitMask 2020-05-02 23:51:16 +02:00
Such Meme, Many Skill
acb43b67db Improvements to script control 2020-05-02 23:35:25 +02:00
Such Meme, Many Skill
baac8dc2fb Fix deadlock in hexview
thanks huhen
2020-05-02 21:56:49 +02:00
Such Meme, Many Skill
7add4b6b13 Misc fixes, mostly related to no-joycon controls 2020-05-02 20:53:13 +02:00
Such Meme, Many Skill
a146a38af7 Increase accuracy of scrollbar 2020-05-02 19:51:04 +02:00
Such Meme, Many Skill
c45be1258a Add more invalid chars 2020-05-02 19:29:55 +02:00
suchmememanyskill
b9776882fd Merge pull request #19 from suchmememanyskill/Horizontal-2
Make TE Horizontal
2020-05-02 17:42:59 +02:00
Such Meme, Many Skill
b0f2ce4211 "reeeee indent"
thanks asp for spotting
2020-05-02 17:42:10 +02:00
Such Meme, Many Skill
f9cf371cf9 i have no brain and i must rename 2020-05-02 17:31:00 +02:00
Such Meme, Many Skill
b273b1e5ab Add renaming option 2020-05-02 16:40:40 +02:00
Such Meme, Many Skill
0bf3b35582 Combat menu breakage due to speedmode™️ 2020-05-02 14:20:55 +02:00
Such Meme, Many Skill
2cac144ba8 Change some more functions to accept the new input 2020-05-02 14:06:56 +02:00
Such Meme, Many Skill
0d98f65f99 Add script button stuff 2020-05-02 13:33:54 +02:00
Such Meme, Many Skill
83e6bf7090 I am speed 2020-05-02 13:05:06 +02:00
Such Meme, Many Skill
4aca6e5fcf Edit some more btn_waits() out 2020-05-02 02:05:37 +02:00
Such Meme, Many Skill
aa6d522c16 Update tools 2020-05-02 01:54:03 +02:00
Such Meme, Many Skill
2cced5bdac Ajust some gfx functions for joycon compatibility 2020-05-02 01:41:43 +02:00
Such Meme, Many Skill
9178813338 Change gui around 2020-05-02 00:50:08 +02:00
Such Meme, Many Skill
7ad77cffb0 Basic controller input 2020-05-01 22:42:49 +02:00
Such Meme, Many Skill
12c3ffc2e4 Merge hekate changes, sorta 2020-05-01 20:09:17 +02:00
Such Meme, Many Skill
305c372d8c Horizontal TE, proper edition
yes i can't git, shut
2020-04-30 23:40:26 +02:00
suchmememanyskill
931cbc829f Merge pull request #16 from bleck9999/master
Destenation. also fuk u
2020-04-28 21:03:52 +02:00
suchmememanyskill
87d4e4c5f1 Merge pull request #17 from LightSage/master
Spelling
2020-04-28 21:03:24 +02:00
bleck9999
6ee5c8cb5f destenation 2020-04-28 19:54:17 +01:00
bleck9999
a3d4636d84 destenation 2020-04-28 19:52:21 +01:00
Kag
52c6438e32 menus 2020-04-28 13:43:00 -05:00
bleck9999
ab4e88f1de destenation 2020-04-28 19:36:40 +01:00
bleck9999
0c039e03c3 destenation 2020-04-28 19:36:31 +01:00
Such Meme, Many Skill
adc9d2e5bf Bump version 2020-04-26 01:28:11 +02:00
Such Meme, Many Skill
317e4b2038 Reduce file size + cleanup + add coreboot.rom file booting 2020-04-26 01:20:26 +02:00
Such Meme, Many Skill
bd99e2a138 Optimise screen scroll a bit, Edit display of filesizes 2020-04-23 14:40:55 +02:00
Such Meme, Many Skill
4c4a6511f3 Merge hekate changes
25ff127404
2020-04-23 13:54:48 +02:00
Such Meme, Many Skill
2bbcf63bd9 Fix restore% on e(mu)mmc partition restores 2020-04-23 13:40:29 +02:00
Such Meme, Many Skill
78722d9a90 Fix calc bug in partition size calculation 2020-04-22 12:23:18 +02:00
Such Meme, Many Skill
e24f8ad722 [Script] Make printf accept multiple args 2020-04-15 22:02:19 +02:00
Such Meme, Many Skill
28fb01b155 See pkg1 version on biskey dump failure 2020-04-14 10:25:31 +02:00
Such Meme, Many Skill
b8b37e78ba Hotfix for 10.0.0 2020-04-14 09:40:37 +02:00
Such Meme, Many Skill
82a4d03985 Bump version 2020-04-12 22:22:40 +02:00
Such Meme, Many Skill
195d9797fe Add that inside functions no "" are required for <=>+-/* 2020-04-12 20:31:32 +02:00
Such Meme, Many Skill
15e1210179 [script] Remove jump list & add if_check that works like if(check()) 2020-04-12 19:21:09 +02:00
Such Meme, Many Skill
e892e69929 don't hardcode locations where info should be parsed from 2020-04-08 17:33:34 +02:00
112 changed files with 7305 additions and 3257 deletions

View File

@@ -8,10 +8,10 @@ include $(DEVKITARM)/base_rules
################################################################################ ################################################################################
IPL_LOAD_ADDR := 0x40003000 IPL_LOAD_ADDR := 0x40008000
LPVERSION_MAJOR := 2 LPVERSION_MAJOR := 3
LPVERSION_MINOR := 5 LPVERSION_MINOR := 0
LPVERSION_BUGFX := 0 LPVERSION_BUGFX := 1
################################################################################ ################################################################################

View File

@@ -5,7 +5,7 @@ A payload-based file explorer for your switch!
1. Get your favorite payload injector 1. Get your favorite payload injector
2. Inject TegraExplorer as a payload 2. Inject TegraExplorer as a payload
Navigate around the menu's using the vol+, vol- and power buttons Navigate around the menus using the vol+, vol- and power buttons
## Functions ## Functions
- Navigate the SD card - Navigate the SD card

View File

@@ -1,8 +1,8 @@
/* /*
* Common Gfx Header * Common Gfx Header
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (C) 2018 CTCaer * Copyright (c) 2018 CTCaer
* Copyright (C) 2018 M4xw * Copyright (c) 2018 M4xw
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,

View File

@@ -1,6 +1,6 @@
/* /*
* Common Module Header * Common Module Header
* Copyright (C) 2018 M4xw * Copyright (c) 2018 M4xw
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,

View File

@@ -19,8 +19,8 @@
//#define IPL_STACK_TOP 0x4003FF00 //#define IPL_STACK_TOP 0x4003FF00
/* --- BIT/BCT: 0x40000000 - 0x40003000 --- */ /* --- BIT/BCT: 0x40000000 - 0x40003000 --- */
/* --- IPL: 0x40003000 - 0x40028000 --- */ /* --- IPL: 0x40008000 - 0x40028000 --- */
#define IPL_LOAD_ADDR 0x40003000 #define IPL_LOAD_ADDR 0x40008000
#define IPL_SZ_MAX 0x20000 // 128KB. #define IPL_SZ_MAX 0x20000 // 128KB.
//#define IRAM_LIB_ADDR 0x4002B000 //#define IRAM_LIB_ADDR 0x4002B000
#define SDRAM_PARAMS_ADDR 0x40030000 // SDRAM extraction buffer during sdram init. #define SDRAM_PARAMS_ADDR 0x40030000 // SDRAM extraction buffer during sdram init.
@@ -28,60 +28,74 @@
/* --- DRAM START --- */ /* --- DRAM START --- */
#define DRAM_START 0x80000000 #define DRAM_START 0x80000000
/* Do not write anything in this area */ #define HOS_RSVD 0x1000000 // Do not write anything in this area.
#define NYX_LOAD_ADDR 0x81000000
#define NYX_SZ_MAX 0x1000000
/* Stack theoretical max: 220MB */
#define IPL_STACK_TOP 0x90010000
#define IPL_HEAP_START 0x90020000
#define IPL_HEAP_SZ 0x24FE0000 // 592MB.
/* --- Gap: 0xB5000000 - 0xB5FFFFFF --- */
// SDMMC DMA buffers #define NYX_LOAD_ADDR 0x81000000
#define SDXC_BUF_ALIGNED 0xB6000000 #define NYX_SZ_MAX 0x1000000 // 16MB
#define MIXD_BUF_ALIGNED 0xB7000000 /* --- Gap: 0x82000000 - 0x82FFFFFF --- */
#define EMMC_BUF_ALIGNED MIXD_BUF_ALIGNED
#define SDMMC_DMA_BUF_SZ 0x1000000 // 16MB (4MB currently used). /* Stack theoretical max: 33MB */
#define SDMMC_UPPER_BUFFER 0xB8000000 #define IPL_STACK_TOP 0x83100000
#define SDMMC_UP_BUF_SZ 0x8000000 // 128MB. #define IPL_HEAP_START 0x84000000
#define IPL_HEAP_SZ 0x20000000 // 512MB.
/* --- Gap: 1040MB 0xA4000000 - 0xE4FFFFFF --- */
// Virtual disk / Chainloader buffers. // Virtual disk / Chainloader buffers.
#define RAM_DISK_ADDR 0xC1000000 #define RAM_DISK_ADDR 0xA4000000
#define RAM_DISK_SZ 0x20000000 #define RAM_DISK_SZ 0x41000000 // 1040MB.
//#define DRAM_LIB_ADDR 0xE0000000 //#define DRAM_LIB_ADDR 0xE0000000
/* --- Chnldr: 252MB 0xC03C0000 - 0xCFFFFFFF --- */ //! Only used when chainloading. /* --- Chnldr: 252MB 0xC03C0000 - 0xCFFFFFFF --- */ //! Only used when chainloading.
/* --- Gap: 464MB 0xD0000000 - 0xECFFFFFF --- */
// SDMMC DMA buffers 1
#define SDMMC_UPPER_BUFFER 0xE5000000
#define SDMMC_UP_BUF_SZ 0x8000000 // 128MB.
// Nyx buffers. // Nyx buffers.
#define NYX_STORAGE_ADDR 0xED000000 #define NYX_STORAGE_ADDR 0xED000000
#define NYX_RES_ADDR 0xEE000000 #define NYX_RES_ADDR 0xEE000000
#define NYX_RES_SZ 0x1000000 // 16MB.
// Framebuffer addresses. // SDMMC DMA buffers 2
#define IPL_FB_ADDRESS 0xF0000000 #define SDXC_BUF_ALIGNED 0xEF000000
#define IPL_FB_SZ 0x384000 // 720 x 1280 x 4. #define MIXD_BUF_ALIGNED 0xF0000000
#define LOG_FB_ADDRESS 0xF0400000 #define EMMC_BUF_ALIGNED MIXD_BUF_ALIGNED
#define LOG_FB_SZ 0x334000 // 1280 x 656 x 4. #define SDMMC_DMA_BUF_SZ 0x1000000 // 16MB (4MB currently used).
#define NYX_FB_ADDRESS 0xF0800000
#define NYX_FB_SZ 0x384000 // 1280 x 720 x 4.
// Nyx LvGL buffers. // Nyx LvGL buffers.
#define NYX_LV_VDB_ADR 0xF0C00000 #define NYX_LV_VDB_ADR 0xF1000000
#define NYX_FB_SZ 0x384000 // 1280 x 720 x 4. #define NYX_FB_SZ 0x384000 // 1280 x 720 x 4.
#define NYX_LV_MEM_ADR 0xF1000000 #define NYX_LV_MEM_ADR 0xF1400000
#define NYX_LV_MEM_SZ 0x8000000 #define NYX_LV_MEM_SZ 0x6600000 // 70MB.
// Framebuffer addresses.
#define IPL_FB_ADDRESS 0xF5A00000
#define IPL_FB_SZ 0x384000 // 720 x 1280 x 4.
#define LOG_FB_ADDRESS 0xF5E00000
#define LOG_FB_SZ 0x334000 // 1280 x 656 x 4.
#define NYX_FB_ADDRESS 0xF6200000
#define NYX_FB2_ADDRESS 0xF6600000
#define NYX_FB_SZ 0x384000 // 1280 x 720 x 4.
#define DRAM_MEM_HOLE_ADR 0xF6A00000
#define DRAM_MEM_HOLE_SZ 0x8140000
/* --- Hole: 129MB 0xF6A00000 - 0xFEB3FFFF --- */
#define DRAM_START2 0xFEB40000
// NX BIS driver sector cache. // NX BIS driver sector cache.
#define NX_BIS_CACHE_ADDR 0xF9000000 #define NX_BIS_CACHE_ADDR 0xFEE00000
#define NX_BIS_CACHE_SZ 0x8800 #define NX_BIS_CACHE_SZ 0x8800
/* --- Gap: 111MB 0xF9008800 - 0xFFFFFFFF --- */
// #define EXT_PAYLOAD_ADDR 0xC03C0000 // USB buffers.
// #define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)) #define USBD_ADDR 0xFEF00000
// #define COREBOOT_ADDR (0xD0000000 - 0x100000) #define USB_DESCRIPTOR_ADDR 0xFEF40000
#define USB_EP_CONTROL_BUF_ADDR 0xFEF80000
#define USB_EP_BULK_IN_BUF_ADDR 0xFF000000
#define USB_EP_BULK_OUT_BUF_ADDR 0xFF800000
#define USB_EP_BULK_OUT_MAX_XFER 0x800000
// NYX
// #define EXT_PAYLOAD_ADDR 0xC0000000 // #define EXT_PAYLOAD_ADDR 0xC0000000
// #define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)) // #define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10))
// #define COREBOOT_ADDR (0xD0000000 - 0x100000) // #define COREBOOT_ADDR (0xD0000000 - rom_size)
#endif #endif

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018-2019 CTCaer * Copyright (c) 2018-2020 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -23,26 +23,25 @@
#include "../gfx/tui.h" #include "../gfx/tui.h"
#include "../libs/fatfs/ff.h" #include "../libs/fatfs/ff.h"
#include "../soc/t210.h" #include "../soc/t210.h"
#include "../storage/nx_sd.h"
#include "../storage/sdmmc.h" #include "../storage/sdmmc.h"
#include "../utils/btn.h" #include "../utils/btn.h"
#include "../utils/list.h" #include "../utils/list.h"
#include "../utils/util.h" #include "../utils/util.h"
extern hekate_config h_cfg; extern hekate_config h_cfg;
extern bool sd_mount();
extern void sd_unmount();
void set_default_configuration() void set_default_configuration()
{ {
h_cfg.autoboot = 0; h_cfg.autoboot = 0;
h_cfg.autoboot_list = 0; h_cfg.autoboot_list = 0;
h_cfg.bootwait = 3; h_cfg.bootwait = 3;
h_cfg.verification = 1;
h_cfg.se_keygen_done = 0; h_cfg.se_keygen_done = 0;
h_cfg.sbar_time_keeping = 0; h_cfg.sbar_time_keeping = 0;
h_cfg.backlight = 100; h_cfg.backlight = 100;
h_cfg.autohosoff = 0; h_cfg.autohosoff = 0;
h_cfg.autonogc = 1; h_cfg.autonogc = 1;
h_cfg.updater2p = 0;
h_cfg.brand = NULL; h_cfg.brand = NULL;
h_cfg.tagline = NULL; h_cfg.tagline = NULL;
h_cfg.errors = 0; h_cfg.errors = 0;
@@ -50,7 +49,7 @@ void set_default_configuration()
h_cfg.rcm_patched = true; h_cfg.rcm_patched = true;
h_cfg.emummc_force_disable = false; h_cfg.emummc_force_disable = false;
sd_power_cycle_time_start = 0xFFFFFFF; sd_power_cycle_time_start = 0;
} }
int create_config_entry() int create_config_entry()
@@ -96,9 +95,6 @@ int create_config_entry()
f_puts("\nbootwait=", &fp); f_puts("\nbootwait=", &fp);
itoa(h_cfg.bootwait, lbuf, 10); itoa(h_cfg.bootwait, lbuf, 10);
f_puts(lbuf, &fp); f_puts(lbuf, &fp);
f_puts("\nverification=", &fp);
itoa(h_cfg.verification, lbuf, 10);
f_puts(lbuf, &fp);
f_puts("\nbacklight=", &fp); f_puts("\nbacklight=", &fp);
itoa(h_cfg.backlight, lbuf, 10); itoa(h_cfg.backlight, lbuf, 10);
f_puts(lbuf, &fp); f_puts(lbuf, &fp);
@@ -108,6 +104,9 @@ int create_config_entry()
f_puts("\nautonogc=", &fp); f_puts("\nautonogc=", &fp);
itoa(h_cfg.autonogc, lbuf, 10); itoa(h_cfg.autonogc, lbuf, 10);
f_puts(lbuf, &fp); f_puts(lbuf, &fp);
f_puts("\nupdater2p=", &fp);
itoa(h_cfg.updater2p, lbuf, 10);
f_puts(lbuf, &fp);
if (h_cfg.brand) if (h_cfg.brand)
{ {
f_puts("\nbrand=", &fp); f_puts("\nbrand=", &fp);
@@ -281,10 +280,11 @@ void config_autoboot()
LIST_INIT(ini_sections); LIST_INIT(ini_sections);
u8 max_entries = 30; u8 max_entries = 30;
u32 boot_text_size = 512;
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 5)); ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 5));
u32 *boot_values = (u32 *)malloc(sizeof(u32) * max_entries); u32 *boot_values = (u32 *)malloc(sizeof(u32) * max_entries);
char *boot_text = (char *)malloc(512 * max_entries); char *boot_text = (char *)malloc(boot_text_size * max_entries);
for (u32 j = 0; j < max_entries; j++) for (u32 j = 0; j < max_entries; j++)
boot_values[j] = j; boot_values[j] = j;
@@ -330,12 +330,12 @@ void config_autoboot()
else else
{ {
if (h_cfg.autoboot != (i - 4) || h_cfg.autoboot_list) if (h_cfg.autoboot != (i - 4) || h_cfg.autoboot_list)
boot_text[(i - 4) * 512] = ' '; boot_text[(i - 4) * boot_text_size] = ' ';
else else
boot_text[(i - 4) * 512] = '*'; boot_text[(i - 4) * boot_text_size] = '*';
strcpy(boot_text + (i - 4) * 512 + 1, ini_sec->name); strcpy(boot_text + (i - 4) * boot_text_size + 1, ini_sec->name);
ments[i].caption = &boot_text[(i - 4) * 512]; ments[i].caption = &boot_text[(i - 4) * boot_text_size];
} }
ments[i].type = ini_sec->type; ments[i].type = ini_sec->type;
ments[i].data = &boot_values[i - 4]; ments[i].data = &boot_values[i - 4];
@@ -391,10 +391,11 @@ void config_bootdelay()
gfx_con_setpos(0, 0); gfx_con_setpos(0, 0);
u32 delay_entries = 6; u32 delay_entries = 6;
u32 delay_text_size = 32;
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (delay_entries + 3)); ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (delay_entries + 3));
u32 *delay_values = (u32 *)malloc(sizeof(u32) * delay_entries); u32 *delay_values = (u32 *)malloc(sizeof(u32) * delay_entries);
char *delay_text = (char *)malloc(32 * delay_entries); char *delay_text = (char *)malloc(delay_text_size * delay_entries);
for (u32 j = 0; j < delay_entries; j++) for (u32 j = 0; j < delay_entries; j++)
delay_values[j] = j; delay_values[j] = j;
@@ -415,14 +416,14 @@ void config_bootdelay()
for (i = 1; i < delay_entries; i++) for (i = 1; i < delay_entries; i++)
{ {
if (h_cfg.bootwait != i) if (h_cfg.bootwait != i)
delay_text[i * 32] = ' '; delay_text[i * delay_text_size] = ' ';
else else
delay_text[i * 32] = '*'; delay_text[i * delay_text_size] = '*';
delay_text[i * 32 + 1] = i + '0'; delay_text[i * delay_text_size + 1] = i + '0';
strcpy(delay_text + i * 32 + 2, " seconds"); strcpy(delay_text + i * delay_text_size + 2, " seconds");
ments[i + 2].type = MENT_DATA; ments[i + 2].type = MENT_DATA;
ments[i + 2].caption = delay_text + i * 32; ments[i + 2].caption = delay_text + (i * delay_text_size);
ments[i + 2].data = &delay_values[i]; ments[i + 2].data = &delay_values[i];
} }
@@ -445,69 +446,17 @@ void config_bootdelay()
btn_wait(); btn_wait();
} }
void config_verification()
{
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6);
u32 *vr_values = (u32 *)malloc(sizeof(u32) * 3);
char *vr_text = (char *)malloc(64 * 3);
for (u32 j = 0; j < 3; j++)
{
vr_values[j] = j;
ments[j + 2].type = MENT_DATA;
ments[j + 2].data = &vr_values[j];
}
ments[0].type = MENT_BACK;
ments[0].caption = "Back";
ments[1].type = MENT_CHGLINE;
strcpy(vr_text, " Disable (Fastest - Unsafe)");
strcpy(vr_text + 64, " Sparse (Fast - Safe)");
strcpy(vr_text + 128, " Full (Slow - Safe)");
for (u32 i = 0; i < 3; i++)
{
if (h_cfg.verification != i)
vr_text[64 * i] = ' ';
else
vr_text[64 * i] = '*';
ments[2 + i].caption = vr_text + (i * 64);
}
memset(&ments[5], 0, sizeof(ment_t));
menu_t menu = {ments, "Backup & Restore verification", 0, 0};
u32 *temp_verification = (u32 *)tui_do_menu(&menu);
if (temp_verification != NULL)
{
h_cfg.verification = *(u32 *)temp_verification;
_save_config();
}
free(ments);
free(vr_values);
free(vr_text);
if (temp_verification == NULL)
return;
btn_wait();
}
void config_backlight() void config_backlight()
{ {
gfx_clear_grey(0x1B); gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0); gfx_con_setpos(0, 0);
u32 bri_text_size = 8;
u32 bri_entries = 11; u32 bri_entries = 11;
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (bri_entries + 3)); ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (bri_entries + 3));
u32 *bri_values = (u32 *)malloc(sizeof(u32) * bri_entries); u32 *bri_values = (u32 *)malloc(sizeof(u32) * bri_entries);
char *bri_text = (char *)malloc(8 * bri_entries); char *bri_text = (char *)malloc(bri_text_size * bri_entries);
for (u32 j = 1; j < bri_entries; j++) for (u32 j = 1; j < bri_entries; j++)
bri_values[j] = j * 10; bri_values[j] = j * 10;
@@ -521,20 +470,20 @@ void config_backlight()
for (i = 1; i < bri_entries; i++) for (i = 1; i < bri_entries; i++)
{ {
if ((h_cfg.backlight / 20) != i) if ((h_cfg.backlight / 20) != i)
bri_text[i * 32] = ' '; bri_text[i * bri_text_size] = ' ';
else else
bri_text[i * 32] = '*'; bri_text[i * bri_text_size] = '*';
if (i < 10) if (i < 10)
{ {
bri_text[i * 32 + 1] = i + '0'; bri_text[i * bri_text_size + 1] = i + '0';
strcpy(bri_text + i * 32 + 2, "0%"); strcpy(bri_text + i * bri_text_size + 2, "0%");
} }
else else
strcpy(bri_text + i * 32 + 1, "100%"); strcpy(bri_text + i * bri_text_size + 1, "100%");
ments[i + 1].type = MENT_DATA; ments[i + 1].type = MENT_DATA;
ments[i + 1].caption = bri_text + i * 32; ments[i + 1].caption = bri_text + (i * bri_text_size);
ments[i + 1].data = &bri_values[i]; ments[i + 1].data = &bri_values[i];
} }

View File

@@ -25,10 +25,10 @@ typedef struct _hekate_config
u32 autoboot; u32 autoboot;
u32 autoboot_list; u32 autoboot_list;
u32 bootwait; u32 bootwait;
u32 verification;
u32 backlight; u32 backlight;
u32 autohosoff; u32 autohosoff;
u32 autonogc; u32 autonogc;
u32 updater2p;
char *brand; char *brand;
char *tagline; char *tagline;
// Global temporary config. // Global temporary config.
@@ -40,16 +40,10 @@ typedef struct _hekate_config
u32 errors; u32 errors;
} hekate_config; } hekate_config;
typedef enum
{
ERR_LIBSYS_LP0 = (1 << 0),
} hsysmodule_t;
void set_default_configuration(); void set_default_configuration();
int create_config_entry(); int create_config_entry();
void config_autoboot(); void config_autoboot();
void config_bootdelay(); void config_bootdelay();
void config_verification();
void config_backlight(); void config_backlight();
void config_auto_hos_poweroff(); void config_auto_hos_poweroff();
void config_nogc(); void config_nogc();

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2019 CTCaer * Copyright (c) 2018-2020 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -44,7 +44,8 @@ static char *_strdup(char *str)
u32 _find_section_name(char *lbuf, u32 lblen, char schar) u32 _find_section_name(char *lbuf, u32 lblen, char schar)
{ {
u32 i; u32 i;
for (i = 0; i < lblen && lbuf[i] != schar && lbuf[i] != '\n' && lbuf[i] != '\r'; i++) // Depends on 'FF_USE_STRFUNC 2' that removes \r.
for (i = 0; i < lblen && lbuf[i] != schar && lbuf[i] != '\n'; i++)
; ;
lbuf[i] = 0; lbuf[i] = 0;
@@ -54,12 +55,9 @@ u32 _find_section_name(char *lbuf, u32 lblen, char schar)
ini_sec_t *_ini_create_section(link_t *dst, ini_sec_t *csec, char *name, u8 type) ini_sec_t *_ini_create_section(link_t *dst, ini_sec_t *csec, char *name, u8 type)
{ {
if (csec) if (csec)
{
list_append(dst, &csec->link); list_append(dst, &csec->link);
csec = NULL;
}
csec = (ini_sec_t *)malloc(sizeof(ini_sec_t)); csec = (ini_sec_t *)calloc(sizeof(ini_sec_t), 1);
csec->name = _strdup(name); csec->name = _strdup(name);
csec->type = type; csec->type = type;
@@ -123,8 +121,8 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
f_gets(lbuf, 512, &fp); f_gets(lbuf, 512, &fp);
lblen = strlen(lbuf); lblen = strlen(lbuf);
// Remove trailing newline. // Remove trailing newline. Depends on 'FF_USE_STRFUNC 2' that removes \r.
if (lbuf[lblen - 1] == '\n' || lbuf[lblen - 1] == '\r') if (lblen && lbuf[lblen - 1] == '\n')
lbuf[lblen - 1] = 0; lbuf[lblen - 1] = 0;
if (lblen > 2 && lbuf[0] == '[') // Create new section. if (lblen > 2 && lbuf[0] == '[') // Create new section.
@@ -134,28 +132,26 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CHOICE); csec = _ini_create_section(dst, csec, &lbuf[1], INI_CHOICE);
list_init(&csec->kvs); list_init(&csec->kvs);
} }
else if (lblen > 2 && lbuf[0] == '{') //Create new caption. else if (lblen > 1 && lbuf[0] == '{') // Create new caption. Support empty caption '{}'.
{ {
_find_section_name(lbuf, lblen, '}'); _find_section_name(lbuf, lblen, '}');
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CAPTION); csec = _ini_create_section(dst, csec, &lbuf[1], INI_CAPTION);
csec->color = 0xFF0AB9E6; csec->color = 0xFF0AB9E6;
} }
else if (lblen > 2 && lbuf[0] == '#') //Create empty lines and comments. else if (lblen > 2 && lbuf[0] == '#') // Create comment.
{ {
_find_section_name(lbuf, lblen, '\0');
csec = _ini_create_section(dst, csec, &lbuf[1], INI_COMMENT); csec = _ini_create_section(dst, csec, &lbuf[1], INI_COMMENT);
} }
else if (lblen < 2) else if (lblen < 2) // Create empty line.
{ {
csec = _ini_create_section(dst, csec, NULL, INI_NEWLINE); csec = _ini_create_section(dst, csec, NULL, INI_NEWLINE);
} }
else if (csec && csec->type == INI_CHOICE) //Extract key/value. else if (csec && csec->type == INI_CHOICE) // Extract key/value.
{ {
u32 i = _find_section_name(lbuf, lblen, '='); u32 i = _find_section_name(lbuf, lblen, '=');
ini_kv_t *kv = (ini_kv_t *)malloc(sizeof(ini_kv_t)); ini_kv_t *kv = (ini_kv_t *)calloc(sizeof(ini_kv_t), 1);
kv->key = _strdup(&lbuf[0]); kv->key = _strdup(&lbuf[0]);
kv->val = _strdup(&lbuf[i + 1]); kv->val = _strdup(&lbuf[i + 1]);
list_append(&csec->kvs, &kv->link); list_append(&csec->kvs, &kv->link);

233
source/exception_handlers.S Normal file
View File

@@ -0,0 +1,233 @@
/*
* 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/>.
*/
/*
* Armv7tdmi Status register.
*
* bit0: Mode 0.
* bit1: Mode 1.
* bit2: Mode 2.
* bit3: Mode 3.
* bit4: Mode 4.
* bit5: Thumb state.
* bit6: FIQ disable.
* bit7: IRQ disable.
* bit8-27: Reserved.
* bit28: Overflow condition.
* bit29: Carry/Borrow/Extend condition.
* bit30: Zero condition.
* bit31: Negative/Less than condition.
*
* M[4:0] | Mode | Visible Thumb-state registers | Visible ARM-state registers
* 10000 | USER | r0r7, SP, LR, PC, CPSR | r0r14, PC, CPSR
* 10001 | FIQ | r0r7, SP_fiq, LR_fiq, PC, CPSR, SPSR_fiq | r0r7, r8_fiqr14_fiq, PC, CPSR, SPSR_fiq
* 10010 | IRQ | r0r7, SP_irq, LR_irq, PC, CPSR, SPSR_irq | r0r12, r13_irq, r14_irq, PC, CPSR, SPSR_irq
* 10011 | SVC | r0r7, SP_svc, LR_svc, PC, CPSR, SPSR_svc | r0r12, r13_svc, r14_svc, PC, CPSR, SPSR_svc
* 10111 | ABRT | r0r7, SP_abt, LR_abt, PC, CPSR, SPSR_abt | r0r12, r13_abt, r14_abt, PC, CPSR, SPSR_abt
* 11011 | UNDF | r0r7, SP_und, LR_und, PC, CPSR, SPSR_und | r0r12, r13_und, r14_und, PC, CPSR, SPSR_und
* 11111 | SYS | r0r7, SP, LR, PC, CPSR | r0r14, PC, CPSR
*/
#define EXCP_EN_ADDR 0x4003FFFC
#define EXCP_TYPE_ADDR 0x4003FFF8
#define EXCP_LR_ADDR 0x4003FFF4
#define EXCP_VEC_BASE 0x6000F000
#define EVP_COP_RESET_VECTOR 0x200
#define EVP_COP_UNDEF_VECTOR 0x204
#define EVP_COP_SWI_VECTOR 0x208
#define EVP_COP_PREFETCH_ABORT_VECTOR 0x20C
#define EVP_COP_DATA_ABORT_VECTOR 0x210
#define EVP_COP_RSVD_VECTOR 0x214
#define EVP_COP_IRQ_VECTOR 0x218
#define EVP_COP_FIQ_VECTOR 0x21C
#define MODE_USR 0x10
#define MODE_FIQ 0x11
#define MODE_IRQ 0x12
#define MODE_SVC 0x13
#define MODE_ABT 0x17
#define MODE_UDF 0x1B
#define MODE_SYS 0x1F
#define MODE_MASK 0x1F
#define FIQ 0x40
#define IRQ 0x80
.section .text._irq_setup
.arm
.extern ipl_main
.type ipl_main, %function
.extern svc_handler
.type svc_handler, %function
.extern irq_handler
.type irq_handler, %function
.extern fiq_setup
.type fiq_setup, %function
.extern fiq_handler
.type fiq_handler, %function
.globl _irq_setup
.type _irq_setup, %function
_irq_setup:
MRS R0, CPSR
BIC R0, R0, #MODE_MASK /* Clear mode bits */
ORR R0, R0, #(MODE_SVC | IRQ | FIQ) /* SUPERVISOR mode, IRQ/FIQ disabled */
MSR CPSR, R0
/* Setup IRQ stack pointer */
MSR CPSR, #(MODE_IRQ | IRQ | FIQ) /* IRQ mode, IRQ/FIQ disabled */
LDR SP, =0x40040000
/* Setup SYS stack pointer */
MSR CPSR, #(MODE_SYS | IRQ | FIQ) /* SYSTEM mode, IRQ/FIQ disabled */
LDR SP, =0x4003FF00 /* Will be changed later to DRAM */
MOV LR, PC
BL setup_vectors
/*BL fiq_setup*/
/* Enable interrupts */
BL irq_enable_cpu_irq_exceptions
B ipl_main
B .
_reset:
LDR R0, =EXCP_EN_ADDR
LDR R1, =0x30505645 /* EVP0 */
STR R1, [R0] /* EVP0 in EXCP_EN_ADDR */
LDR R0, =EXCP_LR_ADDR
MOV R1, LR
STR R1, [R0] /* Save LR in EXCP_LR_ADDR */
LDR R0, =__bss_start
EOR R1, R1, R1
LDR R2, =__bss_end
SUB R2, R2, R0
BL memset
B _irq_setup
_reset_handler:
LDR R0, =EXCP_TYPE_ADDR
LDR R1, =0x545352 /* RST */
STR R1, [R0] /* RST in EXCP_TYPE_ADDR */
B _reset
_undefined_handler:
LDR R0, =EXCP_TYPE_ADDR
LDR R1, =0x464455 /* UDF */
STR R1, [R0] /* UDF in EXCP_TYPE_ADDR */
B _reset
_prefetch_abort_handler:
LDR R0, =EXCP_TYPE_ADDR
LDR R1, =0x54424150 /* PABT */
STR R1, [R0] /* PABT in EXCP_TYPE_ADDR */
B _reset
_data_abort_handler:
LDR R0, =EXCP_TYPE_ADDR
LDR R1, =0x54424144 /* DABT */
STR R1, [R0] /* DABT in EXCP_TYPE_ADDR */
B _reset
.globl irq_enable_cpu_irq_exceptions
.type irq_enable_cpu_irq_exceptions, %function
irq_enable_cpu_irq_exceptions:
MRS R12, CPSR
BIC R12, R12, #(IRQ | FIQ) /* IRQ/FIQ enabled */
MSR CPSR, R12
BX LR
.globl irq_disable_cpu_irq_exceptions
.type irq_disable_cpu_irq_exceptions, %function
irq_disable_cpu_irq_exceptions:
MRS R12, CPSR
ORR R12, R12, #(IRQ | FIQ) /* IRQ/FIQ disabled */
MSR CPSR, R12
BX LR
_irq_handler:
MOV R13, R0 /* Save R0 in R13_IRQ */
SUB R0, LR, #4 /* Put return address in R0_SYS */
MOV LR, R1 /* Save R1 in R14_IRQ (LR) */
MRS R1, SPSR /* Put the SPSR in R1_SYS */
MSR CPSR_c, #(MODE_SYS | IRQ) /* SYSTEM mode, IRQ disabled */
STMFD SP!, {R0, R1} /* SPSR and PC */
STMFD SP!, {R2-R3, R12, LR} /* AAPCS-clobbered registers */
MOV R0, SP /* Make SP_SYS visible to IRQ mode */
SUB SP, SP, #8 /* Make room for stacking R0 and R1 */
MSR CPSR_c, #(MODE_IRQ | IRQ) /* IRQ mode, IRQ disabled */
STMFD R0!, {R13, R14} /* Finish saving the context (R0, R1) */
MSR CPSR_c, #(MODE_SYS | IRQ) /* SYSTEM mode, IRQ disabled */
LDR R12, =irq_handler
MOV LR, PC /* Copy the return address to link register */
BX R12 /* Call the C IRQ handler (ARM/THUMB) */
MSR CPSR_c, #(MODE_SYS | IRQ | FIQ) /* SYSTEM mode, IRQ/FIQ disabled */
MOV R0, SP /* Make SP_SYS visible to IRQ mode */
ADD SP, SP, #32 /* Fake unstacking 8 registers from SP_SYS */
MSR CPSR_c, #(MODE_IRQ | IRQ | FIQ) /* IRQ mode, IRQ/FIQ disabled */
MOV SP, R0 /* Copy SP_SYS to SP_IRQ */
LDR R0, [SP, #28] /* Load the saved SPSR from the stack */
MSR SPSR_cxsf, R0 /* Copy it into SPSR_IRQ */
LDMFD SP, {R0-R3, R12, LR}^ /* Unstack all saved USER/SYSTEM registers */
NOP /* Cant access barked registers immediately */
LDR LR, [SP, #24] /* Load return address from the SYS stack */
MOVS PC, LR /* Return restoring CPSR from SPSR */
_fiq_handler:
BL fiq_handler
setup_vectors:
/* Setup vectors */
LDR R0, =EXCP_VEC_BASE
LDR R1, =_reset_handler
STR R1, [R0, #EVP_COP_RESET_VECTOR]
LDR R1, =_undefined_handler
STR R1, [R0, #EVP_COP_UNDEF_VECTOR]
LDR R1, =_reset_handler
STR R1, [R0, #EVP_COP_SWI_VECTOR]
LDR R1, =_prefetch_abort_handler
STR R1, [R0, #EVP_COP_PREFETCH_ABORT_VECTOR]
LDR R1, =_data_abort_handler
STR R1, [R0, #EVP_COP_DATA_ABORT_VECTOR]
LDR R1, =_reset_handler
STR R1, [R0, #EVP_COP_RSVD_VECTOR]
LDR R1, =_irq_handler
STR R1, [R0, #EVP_COP_IRQ_VECTOR]
LDR R1, =_fiq_handler
STR R1, [R0, #EVP_COP_FIQ_VECTOR]
BX LR

View File

@@ -21,6 +21,8 @@
#include "gfx.h" #include "gfx.h"
static const u8 _gfx_font[] = { static const u8 _gfx_font[] = {
0x00, 0x0C, 0x12, 0x7E, 0x42, 0x42, 0x7E, 0x00, // Char 030 (folder)
0x00, 0x0E, 0x12, 0x22, 0x22, 0x22, 0x3E, 0x00, // Char 031 (file)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Char 032 ( ) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Char 032 ( )
0x00, 0x30, 0x30, 0x18, 0x18, 0x00, 0x0C, 0x00, // Char 033 (!) 0x00, 0x30, 0x30, 0x18, 0x18, 0x00, 0x0C, 0x00, // Char 033 (!)
0x00, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, // Char 034 (") 0x00, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, // Char 034 (")
@@ -165,14 +167,14 @@ void gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol)
void gfx_con_getpos(u32 *x, u32 *y) void gfx_con_getpos(u32 *x, u32 *y)
{ {
*x = gfx_con.x; *x = YLEFT - gfx_con.y;
*y = gfx_con.y; *y = gfx_con.x;
} }
void gfx_con_setpos(u32 x, u32 y) void gfx_con_setpos(u32 x, u32 y)
{ {
gfx_con.x = x; gfx_con.x = y;
gfx_con.y = y; gfx_con.y = YLEFT - x;
} }
void gfx_putc(char c) void gfx_putc(char c)
@@ -181,9 +183,9 @@ void gfx_putc(char c)
switch (gfx_con.fntsz) switch (gfx_con.fntsz)
{ {
case 16: case 16:
if (c >= 32 && c <= 126) if (c >= 30 && c <= 126)
{ {
u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)]; u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 30)];
u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride; u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride;
for (u32 i = 0; i < 16; i+=2) for (u32 i = 0; i < 16; i+=2)
@@ -196,51 +198,60 @@ void gfx_putc(char c)
if (v & 1) if (v & 1)
{ {
*fb = gfx_con.fgcol; *fb = gfx_con.fgcol;
fb++; fb -= gfx_ctxt.stride;
*fb = gfx_con.fgcol; *fb = gfx_con.fgcol;
} }
else if (gfx_con.fillbg) else if (gfx_con.fillbg)
{ {
*fb = gfx_con.bgcol; *fb = gfx_con.bgcol;
fb++; fb -= gfx_ctxt.stride;
*fb = gfx_con.bgcol; *fb = gfx_con.bgcol;
} }
else else
fb++; fb -= gfx_ctxt.stride;
v >>= 1; v >>= 1;
fb++; fb -= gfx_ctxt.stride;
} }
fb += gfx_ctxt.stride - 16; //fb += gfx_ctxt.stride - 16;
//fb = fbtop + 2;
fb += (gfx_ctxt.stride * 16) + 1;
v = *cbuf; v = *cbuf;
} }
cbuf++; cbuf++;
} }
/*
gfx_con.x += 16; gfx_con.x += 16;
if (gfx_con.x >= gfx_ctxt.width - 16) { if (gfx_con.x >= gfx_ctxt.width - 16) {
gfx_con.x = 0; gfx_con.x = 0;
gfx_con.y += 16; gfx_con.y += 16;
} }
*/
gfx_con.y -= 16;
if (gfx_con.y < 16){
gfx_con.y = YLEFT;
gfx_con.x += 16;
}
} }
else if (c == '\n') else if (c == '\n')
{ {
gfx_con.x = 0; gfx_con.y = YLEFT;
gfx_con.y +=16; gfx_con.x += 16;
if (gfx_con.y > gfx_ctxt.height - 16) if (gfx_con.x > gfx_ctxt.width - 16)
gfx_con.y = 0; gfx_con.x = 0;
} }
else if (c == '\e') else if (c == '\e')
gfx_con.x = 672; gfx_con.y = 575;
else if (c == '\a') else if (c == '\a')
gfx_con.x = 608; gfx_con.y = 639;
else if (c == '\r') else if (c == '\r')
gfx_con.x = 0; gfx_con.y = YLEFT;
break; break;
case 8: case 8:
default: default:
if (c >= 32 && c <= 126) if (c >= 30 && c <= 126)
{ {
u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)]; u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 30)];
u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride; u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride;
for (u32 i = 0; i < 8; i++) for (u32 i = 0; i < 8; i++)
{ {
@@ -252,23 +263,31 @@ void gfx_putc(char c)
else if (gfx_con.fillbg) else if (gfx_con.fillbg)
*fb = gfx_con.bgcol; *fb = gfx_con.bgcol;
v >>= 1; v >>= 1;
fb++; fb -= gfx_ctxt.stride;
} }
fb += gfx_ctxt.stride - 8; fb += (gfx_ctxt.stride * 8) + 1;
} }
gfx_con.x += 8;
if (gfx_con.x >= gfx_ctxt.width - 8) { gfx_con.y -= 8;
gfx_con.x = 0; if (gfx_con.y < 8){
gfx_con.y += 8; gfx_con.y = YLEFT;
gfx_con.x += 8;
} }
} }
else if (c == '\n') else if (c == '\n')
{ {
gfx_con.x = 0; gfx_con.y = YLEFT;
gfx_con.y += 8; gfx_con.x += 8;
if (gfx_con.y > gfx_ctxt.height - 8) if (gfx_con.x > gfx_ctxt.width - 8)
gfx_con.y = 0; gfx_con.x = 0;
} }
else if (c == '\e')
gfx_con.y = 575;
else if (c == '\a')
gfx_con.y = 639;
else if (c == '\r')
gfx_con.y = YLEFT;
break; break;
} }
@@ -513,14 +532,34 @@ void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos
} }
} }
void gfx_boxGrey(int x0, int y0, int x1, int y1, u8 shade){
for (int y = (YLEFT - x0); y >= (YLEFT - x1); y--){
memset(gfx_ctxt.fb + y * gfx_ctxt.stride + y0, shade, (y1 - y0 + 1) * 4);
}
}
/*
void gfx_boxGrey_old(int x0, int y0, int x1, int y1, u8 shade){
for (int y = y0; y <= y1; y++){
memset(gfx_ctxt.fb + y * gfx_ctxt.stride + x0, shade, (x1 - x0) * 4);
}
}
*/
void gfx_box(int x0, int y0, int x1, int y1, u32 color){ void gfx_box(int x0, int y0, int x1, int y1, u32 color){
for (int y = (YLEFT - x0); y >= (YLEFT - x1); y--){
for (int x = y0; x <= y1; x++){
gfx_set_pixel(x, y, color);
}
}
}
/*
void gfx_box_old(int x0, int y0, int x1, int y1, u32 color){
for (int x = x0; x < x1 + 1; x++){ for (int x = x0; x < x1 + 1; x++){
for (int y = y0; y < y1 + 1; y++){ for (int y = y0; y < y1 + 1; y++){
gfx_set_pixel(x, y, color); gfx_set_pixel(x, y, color);
} }
} }
} }
*/
void gfx_set_rect_rgb(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)
{ {
u32 pos = 0; u32 pos = 0;

View File

@@ -27,6 +27,8 @@
#define WPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC) #define WPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC)
#define WPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC) #define WPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC)
#define YLEFT 1279
void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride); void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride);
void gfx_clear_grey(u8 color); void gfx_clear_grey(u8 color);
void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height); void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height);
@@ -50,6 +52,13 @@ void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_
void gfx_set_rect_argb(const u32 *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);
void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
void gfx_box(int x0, int y0, int x1, int y1, u32 color); void gfx_box(int x0, int y0, int x1, int y1, u32 color);
void gfx_boxGrey(int x0, int y0, int x1, int y1, u8 shade);
/*
#define GFX_SETPOSCORRECTED(x, y) gfx_con_setpos(y - YLEFT, x)
#define GFX_BOXCORRECTED(x0, y0, x1, y1, color) gfx_box_old((y0 - YLEFT), x0, (y1 - YLEFT), x1, color)
#define GFX_BOXGREYCORRECTED(x0, y0, x1, y1, shade) gfx_boxGrey((y0 - YLEFT), x0, (y1 - YLEFT), x1, shade)
*/
// Global gfx console and context. // Global gfx console and context.
gfx_ctxt_t gfx_ctxt; gfx_ctxt_t gfx_ctxt;

116
source/hid/hid.c Normal file
View File

@@ -0,0 +1,116 @@
#include "hid.h"
#include "joycon.h"
#include "../utils/btn.h"
#include "../gfx/gfx.h"
#include "../utils/types.h"
#include "../tegraexplorer/utils/utils.h"
static Inputs inputs = {0};
u16 LbaseX = 0, LbaseY = 0, RbaseX = 0, RbaseY = 0;
void hidInit(){
jc_init_hw();
}
Inputs *hidRead(){
jc_gamepad_rpt_t *controller = joycon_poll();
static bool errPrint = false;
if (controller->cap)
utils_takeScreenshot();
u8 btn = btn_read();
inputs.volp = (btn & BTN_VOL_UP) ? 1 : 0;
inputs.volm = (btn & BTN_VOL_DOWN) ? 1 : 0;
inputs.pow = (btn & BTN_POWER) ? 1 : 0;
inputs.a = controller->a;
inputs.b = controller->b;
inputs.x = controller->x;
inputs.y = controller->y;
inputs.r = controller->r;
inputs.l = controller->l;
inputs.zr = controller->zr;
inputs.zl = controller->zl;
inputs.minus = controller->minus;
inputs.plus = controller->plus;
inputs.home = controller->home;
inputs.cap = controller->cap;
if (controller->conn_l && controller->conn_r){
if (errPrint){
gfx_boxGrey(1008, 703, 1279, 719, 0xFF);
errPrint = false;
}
}
else {
u32 x, y;
gfx_con_getpos(&x, &y);
gfx_con_setpos(1008, 703);
gfx_printf("%k%K%s %s MISS%k%K", COLOR_DEFAULT, COLOR_WHITE, (controller->conn_l) ? " " : "JOYL", (controller->conn_r) ? " " : "JOYR", COLOR_WHITE, COLOR_DEFAULT);
gfx_con_setpos(x, y);
errPrint = true;
}
if (controller->conn_l){
if ((LbaseX == 0 || LbaseY == 0) || controller->l3){
LbaseX = controller->lstick_x;
LbaseY = controller->lstick_y;
}
inputs.Lup = (controller->up || (controller->lstick_y > LbaseY + 500)) ? 1 : 0;
inputs.Ldown = (controller->down || (controller->lstick_y < LbaseY - 500)) ? 1 : 0;
inputs.Lleft = (controller->left || (controller->lstick_x < LbaseX - 500)) ? 1 : 0;
inputs.Lright = (controller->right || (controller->lstick_x > LbaseX + 500)) ? 1 : 0;
}
else {
inputs.Lup = inputs.volp;
inputs.Ldown = inputs.volm;
}
if (controller->conn_r){
if ((RbaseX == 0 || RbaseY == 0) || controller->r3){
RbaseX = controller->rstick_x;
RbaseY = controller->rstick_y;
}
inputs.Rup = (controller->rstick_y > RbaseY + 500) ? 1 : 0;
inputs.Rdown = (controller->rstick_y < RbaseY - 500) ? 1 : 0;
inputs.Rleft = (controller->rstick_x < RbaseX - 500) ? 1 : 0;
inputs.Rright = (controller->rstick_x > RbaseX + 500) ? 1 : 0;
}
else
inputs.a = inputs.pow;
return &inputs;
}
Inputs *hidWaitMask(u32 mask){
Inputs *in = hidRead();
while (in->buttons & mask)
hidRead();
while (!(in->buttons & mask)){
hidRead();
}
return in;
}
Inputs *hidWait(){
Inputs *in = hidRead();
while (in->buttons)
hidRead();
while (!(in->buttons))
hidRead();
return in;
}
bool hidConnected(){
jc_gamepad_rpt_t *controller = joycon_poll();
return (controller->conn_l && controller->conn_r) ? 1 : 0;
}

59
source/hid/hid.h Normal file
View File

@@ -0,0 +1,59 @@
#pragma once
#include "../utils/types.h"
#define BIT(n) (1U << n)
#define KEY_A BIT(3)
#define KEY_B BIT(2)
#define KEY_Y BIT(0)
#define KEY_X BIT(1)
#define KEY_LUP BIT(18)
#define KEY_LDOWN BIT(17)
#define KEY_LRIGHT BIT(19)
#define KEY_LLEFT BIT(20)
#define KEY_RUP BIT(7)
#define KEY_RDOWN BIT(6)
#define KEY_VOLP BIT(14)
#define KEY_VOLM BIT(15)
#define KEY_POW BIT(16)
typedef struct _inputs {
union {
struct {
// Joy-Con (R).
u32 y:1;
u32 x:1;
u32 b:1;
u32 a:1;
u32 r:1;
u32 zr:1;
u32 Rdown:1;
u32 Rup:1;
u32 Rright:1;
u32 Rleft:1;
// Shared
u32 minus:1;
u32 plus:1;
u32 home:1;
u32 cap:1;
u32 volp:1;
u32 volm:1;
u32 pow:1;
// Joy-Con (L).
u32 Ldown:1;
u32 Lup:1;
u32 Lright:1;
u32 Lleft:1;
u32 l:1;
u32 zl:1;
};
u32 buttons;
};
} Inputs;
void hidInit();
Inputs *hidRead();
Inputs *hidWait();
Inputs *hidWaitMask(u32 mask);
bool hidConnected();

807
source/hid/joycon.c Normal file
View File

@@ -0,0 +1,807 @@
/*
* Joy-Con UART driver for Nintendo Switch
*
* 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 "joycon.h"
#include "../gfx/gfx.h"
#include "../power/max17050.h"
#include "../power/regulator_5v.h"
#include "../soc/bpmp.h"
#include "../soc/clock.h"
#include "../soc/gpio.h"
#include "../soc/pinmux.h"
#include "../soc/uart.h"
#include "../soc/t210.h"
#include "../utils/util.h"
// For disabling driver when logging is enabled.
// #include "../libs/lvgl/lvgl.h"
#define JC_WIRED_CMD 0x91
#define JC_WIRED_HID 0x92
#define JC_WIRED_INIT_REPLY 0x94
#define JC_INIT_HANDSHAKE 0xA5
#define JC_WIRED_CMD_MAC 0x01
#define JC_WIRED_CMD_10 0x10
#define JC_HID_OUTPUT_RPT 0x01
#define JC_HID_RUMBLE_RPT 0x10
#define JC_HID_INPUT_RPT 0x30
#define JC_HID_SUBMCD_RPT 0x21
#define JC_HID_SUBCMD_HCI_STATE 0x06
#define HCI_STATE_SLEEP 0x00
#define HCI_STATE_RECONNECT 0x01
#define HCI_STATE_PAIR 0x02
#define HCI_STATE_HOME 0x04
#define JC_HID_SUBCMD_SPI_READ 0x10
#define JC_HID_SUBCMD_RUMBLE_CTL 0x48
#define JC_HID_SUBCMD_SND_RUMBLE 0xFF
#define JC_BTN_MASK_L 0xFF2900 // 0xFFE900: with charge status.
#define JC_BTN_MASK_R 0x76FF
#define JC_ID_L 1
#define JC_ID_R 2
enum
{
JC_BATT_EMTPY = 0,
JC_BATT_CRIT = 2,
JC_BATT_LOW = 4,
JC_BATT_MID = 6,
JC_BATT_FULL = 8
};
static const u8 init_jc[] = {
0xA1, 0xA2, 0xA3, 0xA4
};
static const u8 init_handshake[] = {
0x19, 0x01, 0x03, 0x07, 0x00, // Uart header.
JC_INIT_HANDSHAKE, 0x02, // Wired cmd and wired subcmd.
0x01, 0x7E, 0x00, 0x00, 0x00 // Wired subcmd data.
};
static const u8 init_get_info[] = {
0x19, 0x01, 0x03, 0x07, 0x00, // Uart header.
JC_WIRED_CMD, JC_WIRED_CMD_MAC, // Wired cmd and subcmd.
0x00, 0x00, 0x00, 0x00, 0x24 // Wired subcmd data.
};
static const u8 init_finilize[] = {
0x19, 0x01, 0x03, 0x07, 0x00, // Uart header.
JC_WIRED_CMD, JC_WIRED_CMD_10, // Wired cmd and subcmd.
0x00, 0x00, 0x00, 0x00, 0x3D // Wired subcmd data.
};
static const u8 nx_pad_status[] = {
0x19, 0x01, 0x03, 0x08, 0x00, // Uart header.
JC_WIRED_HID, 0x00, // Wired cmd and hid cmd.
0x01, 0x00, 0x00, 0x69, 0x2D, 0x1F // hid data.
};
typedef struct _jc_uart_hdr_t
{
u8 magic[3];
u8 total_size_lsb;
u8 total_size_msb;
} jc_uart_hdr_t;
typedef struct _jc_wired_hdr_t
{
jc_uart_hdr_t uart_hdr;
u8 cmd;
u8 data[5];
u8 crc;
u8 payload[];
} jc_wired_hdr_t;
typedef struct _jc_hid_out_rpt_t
{
u8 cmd;
u8 pkt_id;
u8 rumble[8];
u8 subcmd;
u8 subcmd_data[];
} jc_hid_out_rpt_t;
typedef struct _jc_hid_out_spi_read_t
{
u32 addr;
u8 size;
} jc_hid_out_spi_read_t;
typedef struct _jc_hid_in_rpt_t
{
u8 cmd;
u8 pkt_id;
u8 conn_info:4;
u8 batt_info:4;
u8 btn_right;
u8 btn_shared;
u8 btn_left;
u8 stick_h_left;
u8 stick_m_left;
u8 stick_v_left;
u8 stick_h_right;
u8 stick_m_right;
u8 stick_v_right;
u8 vib_decider;
u8 submcd_ack;
u8 subcmd;
u8 subcmd_data[];
} jc_hid_in_rpt_t;
typedef struct _jc_hid_in_spi_read_t
{
u32 addr;
u8 size;
u8 data[];
} jc_hid_in_spi_read_t;
typedef struct _jc_hid_in_pair_data_t
{
u8 magic;
u8 size;
u16 checksum;
u8 mac[6];
u8 ltk[16];
u8 pad0[10];
u8 bt_caps; // bit3: Secure conn supported host, bit5: Paired to TBFC supported host, bit6: iTBFC page supported
u8 pad1;
} jc_hid_in_pair_data_t;
typedef struct _joycon_ctxt_t
{
u8 buf[0x100]; //FIXME: If heap is used, dumping breaks.
u8 uart;
u8 type;
u8 mac[6];
u32 hw_init_done;
u32 last_received_time;
u32 last_status_req_time;
u8 rumble_sent;
u8 connected;
} joycon_ctxt_t;
static joycon_ctxt_t jc_l;
static joycon_ctxt_t jc_r;
static bool jc_init_done = false;
static u32 hid_pkt_inc = 0;
static jc_gamepad_rpt_t jc_gamepad;
void jc_power_supply(u8 uart, bool enable);
void joycon_send_raw(u8 uart_port, const u8 *buf, u16 size)
{
uart_send(uart_port, buf, size);
uart_wait_idle(uart_port, UART_TX_IDLE);
}
static u16 jc_packet_add_uart_hdr(jc_wired_hdr_t *out, u8 wired_cmd, u8 *data, u16 size)
{
out->uart_hdr.magic[0] = 0x19;
out->uart_hdr.magic[1] = 0x01;
out->uart_hdr.magic[2] = 0x3;
out->uart_hdr.total_size_lsb = 7;
out->uart_hdr.total_size_msb = 0;
out->cmd = wired_cmd;
if (data)
memcpy(out->data, data, size);
out->crc = 0; // wired crc8ccit can be skipped.
return sizeof(jc_wired_hdr_t);
}
static u16 jc_hid_output_rpt_craft(jc_wired_hdr_t *rpt, u8 *payload, u16 size)
{
u16 pkt_size = jc_packet_add_uart_hdr(rpt, JC_WIRED_HID, NULL, 0);
pkt_size += size;
rpt->uart_hdr.total_size_lsb += size;
rpt->data[0] = size >> 8;
rpt->data[1] = size & 0xFF;
if (payload)
memcpy(rpt->payload, payload, size);
return pkt_size;
}
void jc_send_hid_output_rpt(u8 uart, u8 *payload, u16 size)
{
u8 rpt[0x50];
memset(rpt, 0, sizeof(rpt));
u32 rpt_size = jc_hid_output_rpt_craft((jc_wired_hdr_t *)rpt, payload, size);
joycon_send_raw(uart, rpt, rpt_size);
}
static u8 jc_hid_pkt_id_incr()
{
u8 curr_id = hid_pkt_inc;
hid_pkt_inc++;
return (curr_id & 0xF);
}
void jc_send_hid_cmd(u8 uart, u8 subcmd, u8 *data, u16 size)
{
u8 temp[0x30];
u8 rumble_neutral[8] = {0x00, 0x01, 0x40, 0x40, 0x00, 0x01, 0x40, 0x40};
u8 rumble_init[8] = {0xc2, 0xc8, 0x03, 0x72, 0xc2, 0xc8, 0x03, 0x72};
memset(temp, 0, sizeof(temp));
jc_hid_out_rpt_t *hid_pkt = (jc_hid_out_rpt_t *)temp;
memcpy(hid_pkt->rumble, rumble_neutral, sizeof(rumble_neutral));
if (subcmd == JC_HID_SUBCMD_SND_RUMBLE)
{
bool send_r_rumble = jc_r.connected && !jc_r.rumble_sent;
bool send_l_rumble = jc_l.connected && !jc_l.rumble_sent;
// Enable rumble.
hid_pkt->cmd = JC_HID_OUTPUT_RPT;
hid_pkt->pkt_id = jc_hid_pkt_id_incr();
hid_pkt->subcmd = JC_HID_SUBCMD_RUMBLE_CTL;
hid_pkt->subcmd_data[0] = 1;
if (send_r_rumble)
jc_send_hid_output_rpt(UART_B, (u8 *)hid_pkt, 0x10);
if (send_l_rumble)
jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, 0x10);
// Send rumble.
hid_pkt->cmd = JC_HID_RUMBLE_RPT;
hid_pkt->pkt_id = jc_hid_pkt_id_incr();
memcpy(hid_pkt->rumble, rumble_init, sizeof(rumble_init));
if (send_r_rumble)
jc_send_hid_output_rpt(UART_B, (u8 *)hid_pkt, 10);
if (send_l_rumble)
jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, 10);
msleep(15);
// Disable rumble.
hid_pkt->cmd = JC_HID_OUTPUT_RPT;
hid_pkt->pkt_id = jc_hid_pkt_id_incr();
hid_pkt->subcmd = JC_HID_SUBCMD_RUMBLE_CTL;
hid_pkt->subcmd_data[0] = 0;
memcpy(hid_pkt->rumble, rumble_neutral, sizeof(rumble_neutral));
if (send_r_rumble)
jc_send_hid_output_rpt(UART_B, (u8 *)hid_pkt, 0x10);
if (send_l_rumble)
jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, 0x10);
}
else
{
hid_pkt->cmd = JC_HID_OUTPUT_RPT;
hid_pkt->pkt_id = jc_hid_pkt_id_incr();
hid_pkt->subcmd = subcmd;
if (data)
memcpy(hid_pkt->subcmd_data, data, size);
u8 pkt_size = sizeof(jc_hid_out_rpt_t) + size;
if (subcmd != JC_HID_SUBCMD_SPI_READ)
jc_send_hid_output_rpt(uart, (u8 *)hid_pkt, pkt_size);
else
{
jc_send_hid_output_rpt(UART_B, (u8 *)hid_pkt, pkt_size);
jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, pkt_size);
}
}
}
static void jc_charging_decider(u8 batt, u8 uart)
{
u32 system_batt_enough = max17050_get_cached_batt_volt() > 4000;
// Power supply control based on battery levels and charging.
if ((batt >> 1 << 1) < JC_BATT_LOW) // Level without checking charging.
jc_power_supply(uart, true);
else if (batt > (system_batt_enough ? JC_BATT_FULL : JC_BATT_MID)) // Addresses the charging bit.
jc_power_supply(uart, false);
}
static void jc_parse_wired_hid(joycon_ctxt_t *jc, const u8* packet, u32 size)
{
u32 btn_tmp;
jc_hid_in_rpt_t *hid_pkt = (jc_hid_in_rpt_t *)packet;
switch (hid_pkt->cmd)
{
case JC_HID_INPUT_RPT:
btn_tmp = hid_pkt->btn_right | hid_pkt->btn_shared << 8 | hid_pkt->btn_left << 16;
if (jc->type & JC_ID_L)
{
jc_gamepad.buttons &= ~JC_BTN_MASK_L;
jc_gamepad.buttons |= (btn_tmp & JC_BTN_MASK_L);
jc_gamepad.lstick_x = hid_pkt->stick_h_left | ((hid_pkt->stick_m_left & 0xF) << 8);
jc_gamepad.lstick_y = (hid_pkt->stick_m_left >> 4) | (hid_pkt->stick_v_left << 4);
jc_gamepad.batt_info_l = hid_pkt->batt_info;
}
else if (jc->type & JC_ID_R)
{
jc_gamepad.buttons &= ~JC_BTN_MASK_R;
jc_gamepad.buttons |= (btn_tmp & JC_BTN_MASK_R);
jc_gamepad.rstick_x = hid_pkt->stick_h_right | ((hid_pkt->stick_m_right & 0xF) << 8);
jc_gamepad.rstick_y = (hid_pkt->stick_m_right >> 4) | (hid_pkt->stick_v_right << 4);
jc_gamepad.batt_info_r = hid_pkt->batt_info;
}
jc_gamepad.conn_l = jc_l.connected;
jc_gamepad.conn_r = jc_r.connected;
jc_charging_decider(hid_pkt->batt_info, jc->uart);
break;
case JC_HID_SUBMCD_RPT:
if (hid_pkt->subcmd == JC_HID_SUBCMD_SPI_READ)
{
jc_bt_conn_t *bt_conn;
if (jc->type & JC_ID_L)
bt_conn = &jc_gamepad.bt_conn_l;
else
bt_conn = &jc_gamepad.bt_conn_r;
jc_hid_in_spi_read_t *spi_info = (jc_hid_in_spi_read_t *)hid_pkt->subcmd_data;
jc_hid_in_pair_data_t *pair_data = (jc_hid_in_pair_data_t *)spi_info->data;
// Check if we reply is pairing info.
if (spi_info->addr == 0x2000 && spi_info->size == 0x1A && pair_data->magic == 0x95)
{
bt_conn->type = jc->type;
memcpy(bt_conn->mac, jc->mac, 6);
memcpy(bt_conn->host_mac, pair_data->mac, 6);
for (u32 i = 16; i > 0; i--)
bt_conn->ltk[16 - i] = pair_data->ltk[i - 1];
}
}
break;
default:
break;
}
jc->last_received_time = get_tmr_ms();
}
static void jc_parse_wired_init(joycon_ctxt_t *jc, const u8* data, u32 size)
{
switch (data[0])
{
case JC_WIRED_CMD_MAC:
for (int i = 12; i > 6; i--)
jc->mac[12 - i] = data[i];
jc->type = data[6];
jc->connected = true;
default:
break;
}
}
static void jc_uart_pkt_parse(joycon_ctxt_t *jc, const u8* packet, size_t size)
{
jc_wired_hdr_t *pkt = (jc_wired_hdr_t *)packet;
switch (pkt->cmd)
{
case JC_WIRED_HID:
jc_parse_wired_hid(jc, pkt->payload, (pkt->data[0] << 8) | pkt->data[1]);
break;
case JC_WIRED_INIT_REPLY:
jc_parse_wired_init(jc, pkt->data, size - sizeof(jc_uart_hdr_t) - 1);
break;
default:
break;
}
}
static void jc_rcv_pkt(joycon_ctxt_t *jc)
{
if (gpio_read(GPIO_PORT_E, GPIO_PIN_6) && jc->uart == UART_C)
return;
else if (gpio_read(GPIO_PORT_H, GPIO_PIN_6) && jc->uart == UART_B)
return;
// Check if device stopped sending data.
u32 uart_irq = uart_get_IIR(jc->uart);
if ((uart_irq & 0x8) != 0x8)
return;
u32 len = uart_recv(jc->uart, (u8 *)jc->buf, 0);
// Check valid size and uart reply magic.
if (len > 7 && !memcmp(jc->buf, "\x19\x81\x03", 3))
{
jc_wired_hdr_t *pkt = (jc_wired_hdr_t *)(jc->buf);
jc_uart_pkt_parse(jc, jc->buf, pkt->uart_hdr.total_size_lsb + sizeof(jc_uart_hdr_t));
}
}
static bool jc_send_init_rumble(joycon_ctxt_t *jc)
{
// Send init rumble or request nx pad status report.
if ((jc_r.connected && !jc_r.rumble_sent) || (jc_l.connected && !jc_l.rumble_sent))
{
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
jc_send_hid_cmd(jc->uart, JC_HID_SUBCMD_SND_RUMBLE, NULL, 0);
if (jc_l.connected)
jc_l.rumble_sent = true;
if (jc_r.connected)
jc_r.rumble_sent = true;
if (jc->uart != UART_B)
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO);
else
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO);
return 1;
}
return 0;
}
static void jc_req_nx_pad_status(joycon_ctxt_t *jc)
{
bool sent_rumble = jc_send_init_rumble(jc);
if (sent_rumble)
return;
if (jc->last_status_req_time > get_tmr_ms() || !jc->connected)
return;
// Turn off Joy-Con detect.
if (jc->uart == UART_B)
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);
else
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
joycon_send_raw(jc->uart, nx_pad_status, sizeof(nx_pad_status));
// Turn Joy-Con detect on.
if (jc->uart == UART_B)
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO);
else
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO);
jc->last_status_req_time = get_tmr_ms() + 15;
}
jc_gamepad_rpt_t *jc_get_bt_pairing_info()
{
u8 retries;
jc_bt_conn_t *bt_conn;
bt_conn = &jc_gamepad.bt_conn_l;
memset(bt_conn->host_mac, 0, 6);
memset(bt_conn->ltk, 0, 16);
bt_conn = &jc_gamepad.bt_conn_r;
memset(bt_conn->host_mac, 0, 6);
memset(bt_conn->ltk, 0, 16);
while (jc_l.last_status_req_time > get_tmr_ms())
{
jc_rcv_pkt(&jc_r);
jc_rcv_pkt(&jc_l);
}
jc_hid_in_spi_read_t subcmd_data;
subcmd_data.addr = 0x2000;
subcmd_data.size = 0x1A;
// Turn off Joy-Con detect.
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
bool jc_r_found = jc_r.connected ? false : true;
bool jc_l_found = jc_l.connected ? false : true;
u32 total_retries = 5;
retry:
retries = 10;
while (retries)
{
if (jc_l.last_status_req_time < get_tmr_ms())
{
jc_send_hid_cmd(0, JC_HID_SUBCMD_SPI_READ, (u8 *)&subcmd_data, 5);
jc_l.last_status_req_time = get_tmr_ms() + 15;
jc_r.last_status_req_time = get_tmr_ms() + 15;
retries--;
}
if (!jc_r_found)
{
memset(jc_r.buf, 0, 0x100);
jc_rcv_pkt(&jc_r);
}
if (!jc_l_found)
{
memset(jc_l.buf, 0, 0x100);
jc_rcv_pkt(&jc_l);
}
}
if (jc_l.connected &&
memcmp(&jc_gamepad.bt_conn_l.ltk[0], "\x00\x00\x00\x00", 4) &&
memcmp(&jc_gamepad.bt_conn_l.ltk[8], "\x00\x00\x00\x00", 4))
jc_l_found = true;
if (jc_r.connected &&
memcmp(&jc_gamepad.bt_conn_r.ltk[0], "\x00\x00\x00\x00", 4) &&
memcmp(&jc_gamepad.bt_conn_r.ltk[8], "\x00\x00\x00\x00", 4))
jc_r_found = true;
if (total_retries && (!jc_l_found || !jc_r_found))
{
total_retries--;
goto retry;
}
// Turn Joy-Con detect on.
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO);
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO);
return &jc_gamepad;
}
void jc_deinit()
{
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
u8 data = HCI_STATE_SLEEP;
if (jc_r.connected)
{
jc_send_hid_cmd(UART_B, JC_HID_SUBCMD_HCI_STATE, &data, 1);
msleep(1);
jc_rcv_pkt(&jc_r);
}
if (jc_l.connected)
{
jc_send_hid_cmd(UART_C, JC_HID_SUBCMD_HCI_STATE, &data, 1);
msleep(1);
jc_rcv_pkt(&jc_l);
}
jc_power_supply(UART_B, false);
jc_power_supply(UART_C, false);
}
static void jc_init_conn(joycon_ctxt_t *jc)
{
if (((u32)get_tmr_ms() - jc->last_received_time) > 1000)
{
jc_power_supply(jc->uart, true);
// Turn off Joy-Con detect.
if (jc->uart == UART_B)
{
jc_gamepad.buttons &= ~JC_BTN_MASK_R;
jc_gamepad.conn_r = false;
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);
}
else
{
jc_gamepad.buttons &= ~JC_BTN_MASK_L;
jc_gamepad.conn_l = false;
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
}
uart_init(jc->uart, 1000000);
uart_invert(jc->uart, true, UART_INVERT_TXD);
uart_set_IIR(jc->uart);
joycon_send_raw(jc->uart, init_jc, 4);
joycon_send_raw(jc->uart, init_handshake, sizeof(init_handshake));
msleep(5);
jc_rcv_pkt(jc);
joycon_send_raw(jc->uart, init_get_info, sizeof(init_get_info));
msleep(5);
jc_rcv_pkt(jc);
joycon_send_raw(jc->uart, init_finilize, sizeof(init_finilize));
msleep(5);
jc_rcv_pkt(jc);
// Turn Joy-Con detect on.
if (jc->uart == UART_B)
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO);
else
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO);
jc->last_received_time = get_tmr_ms();
if (jc->connected)
jc_power_supply(jc->uart, false);
}
}
static void jc_conn_check()
{
// Check if a Joy-Con was disconnected.
if (gpio_read(GPIO_PORT_E, GPIO_PIN_6))
{
jc_power_supply(UART_C, false);
hid_pkt_inc = 0;
jc_l.connected = false;
jc_l.rumble_sent = false;
jc_gamepad.buttons &= ~JC_BTN_MASK_L;
jc_gamepad.conn_l = false;
jc_gamepad.batt_info_l = 0;
jc_gamepad.bt_conn_l.type = 0;
}
if (gpio_read(GPIO_PORT_H, GPIO_PIN_6))
{
jc_power_supply(UART_B, false);
hid_pkt_inc = 0;
jc_r.connected = false;
jc_r.rumble_sent = false;
jc_gamepad.buttons &= ~JC_BTN_MASK_R;
jc_gamepad.conn_r = false;
jc_gamepad.batt_info_r = 0;
jc_gamepad.bt_conn_r.type = 0;
}
}
void jc_power_supply(u8 uart, bool enable)
{
if (enable)
{
if (regulator_get_5v_dev_enabled(1 << uart))
return;
regulator_enable_5v(1 << uart);
if (jc_init_done)
{
if (uart == UART_C)
gpio_write(GPIO_PORT_CC, GPIO_PIN_3, GPIO_HIGH);
else
gpio_write(GPIO_PORT_K, GPIO_PIN_3, GPIO_HIGH);
return;
}
if (uart == UART_C)
{
// Joy-Con(L) Charge Detect.
PINMUX_AUX(PINMUX_AUX_SPDIF_IN) = PINMUX_PULL_DOWN | 1;
gpio_config(GPIO_PORT_CC, GPIO_PIN_3, GPIO_MODE_GPIO);
gpio_output_enable(GPIO_PORT_CC, GPIO_PIN_3, GPIO_OUTPUT_ENABLE);
gpio_write(GPIO_PORT_CC, GPIO_PIN_3, GPIO_HIGH);
}
else
{
// Joy-Con(R) Charge Detect.
PINMUX_AUX(PINMUX_AUX_GPIO_PK3) = PINMUX_DRIVE_4X | PINMUX_PULL_DOWN | 2;
gpio_config(GPIO_PORT_K, GPIO_PIN_3, GPIO_MODE_GPIO);
gpio_output_enable(GPIO_PORT_K, GPIO_PIN_3, GPIO_OUTPUT_ENABLE);
gpio_write(GPIO_PORT_K, GPIO_PIN_3, GPIO_HIGH);
}
}
else
{
if (!regulator_get_5v_dev_enabled(1 << uart))
return;
regulator_disable_5v(1 << uart);
if (uart == UART_C)
gpio_write(GPIO_PORT_CC, GPIO_PIN_3, GPIO_LOW);
else
gpio_write(GPIO_PORT_K, GPIO_PIN_3, GPIO_LOW);
}
}
void jc_init_hw()
{
jc_l.uart = UART_C;
jc_r.uart = UART_B;
#if (LV_LOG_PRINTF != 1)
jc_power_supply(UART_C, true);
jc_power_supply(UART_B, true);
// Joy-Con (R) IsAttached.
PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;
gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_GPIO);
// Joy-Con (L) IsAttached.
PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;
gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_GPIO);
// Configure pinmuxing for UART B and C.
pinmux_config_uart(UART_B);
pinmux_config_uart(UART_C);
// Ease the stress to APB.
bpmp_clk_rate_set(BPMP_CLK_NORMAL);
// Enable UART B and C clocks.
clock_enable_uart(UART_B);
clock_enable_uart(UART_C);
// Restore OC.
bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST);
// Turn Joy-Con detect on.
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO);
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO);
jc_init_done = true;
#endif
}
jc_gamepad_rpt_t *joycon_poll()
{
if (!jc_init_done)
return NULL;
if (!gpio_read(GPIO_PORT_H, GPIO_PIN_6))
jc_init_conn(&jc_r);
if (!gpio_read(GPIO_PORT_E, GPIO_PIN_6))
jc_init_conn(&jc_l);
if (!gpio_read(GPIO_PORT_H, GPIO_PIN_6))
jc_req_nx_pad_status(&jc_r);
if (!gpio_read(GPIO_PORT_E, GPIO_PIN_6))
jc_req_nx_pad_status(&jc_l);
if (!gpio_read(GPIO_PORT_H, GPIO_PIN_6))
jc_rcv_pkt(&jc_r);
if (!gpio_read(GPIO_PORT_E, GPIO_PIN_6))
jc_rcv_pkt(&jc_l);
jc_conn_check();
return &jc_gamepad;
}

98
source/hid/joycon.h Normal file
View File

@@ -0,0 +1,98 @@
/*
* Ambient light sensor driver for Nintendo Switch's Rohm BH1730
*
* 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 __JOYCON_H_
#define __JOYCON_H_
#include "../utils/types.h"
#define JC_BTNS_DIRECTION_PAD 0xF0000
#define JC_BTNS_PREV_NEXT 0x800080
#define JC_BTNS_ENTER 0x400008
#define JC_BTNS_ESC 0x4
#define JC_BTNS_ALL (JC_BTNS_PREV_NEXT | JC_BTNS_ENTER | JC_BTNS_DIRECTION_PAD | JC_BTNS_ESC)
typedef struct _jc_bt_conn_t
{
u8 type;
u8 mac[6];
u8 host_mac[6];
u8 ltk[16];
} jc_bt_conn_t;
typedef struct _jc_gamepad_rpt_t
{
union
{
struct
{
// Joy-Con (R).
u32 y:1;
u32 x:1;
u32 b:1;
u32 a:1;
u32 sr_r:1;
u32 sl_r:1;
u32 r:1;
u32 zr:1;
// Shared
u32 minus:1;
u32 plus:1;
u32 r3:1;
u32 l3:1;
u32 home:1;
u32 cap:1;
u32 pad:1;
u32 wired:1;
// Joy-Con (L).
u32 down:1;
u32 up:1;
u32 right:1;
u32 left:1;
u32 sr_l:1;
u32 sl_l:1;
u32 l:1;
u32 zl:1;
};
u32 buttons;
};
u16 lstick_x;
u16 lstick_y;
u16 rstick_x;
u16 rstick_y;
bool center_stick_l;
bool center_stick_r;
bool conn_l;
bool conn_r;
u8 batt_info_l;
u8 batt_info_r;
jc_bt_conn_t bt_conn_l;
jc_bt_conn_t bt_conn_r;
} jc_gamepad_rpt_t;
void jc_power_supply(u8 uart, bool enable);
void jc_init_hw();
void jc_deinit();
jc_gamepad_rpt_t *joycon_poll();
jc_gamepad_rpt_t *jc_get_bt_pairing_info();
#endif

View File

@@ -25,7 +25,7 @@
#define HASH_ORDER_100_100 {2, 3, 4, 0, 5, 6, 1} #define HASH_ORDER_100_100 {2, 3, 4, 0, 5, 6, 1}
#define HASH_ORDER_200_510 {2, 3, 4, 0, 5, 7, 10, 12, 11, 6, 8, 1} #define HASH_ORDER_200_510 {2, 3, 4, 0, 5, 7, 10, 12, 11, 6, 8, 1}
#define HASH_ORDER_600_620 {6, 5, 10, 7, 8, 2, 3, 4, 0, 12, 11, 1} #define HASH_ORDER_600_620 {6, 5, 10, 7, 8, 2, 3, 4, 0, 12, 11, 1}
#define HASH_ORDER_700_9xx {6, 5, 10, 7, 8, 2, 3, 4, 0, 12, 11, 9, 1} #define HASH_ORDER_700_10x {6, 5, 10, 7, 8, 2, 3, 4, 0, 12, 11, 9, 1}
static const pkg1_id_t _pkg1_ids[] = { static const pkg1_id_t _pkg1_ids[] = {
{ "20161121183008", 0, {0x1b517, 0x125bc2, 1, 16, 6, HASH_ORDER_100_100, 0, 0x449dc} }, //1.0.0 { "20161121183008", 0, {0x1b517, 0x125bc2, 1, 16, 6, HASH_ORDER_100_100, 0, 0x449dc} }, //1.0.0
@@ -36,12 +36,13 @@ static const pkg1_id_t _pkg1_ids[] = {
{ "20180220163747", 4, {0x1f3b4, 0x465b, 0, 16, 11, HASH_ORDER_200_510, 0x5a63, 0x37901} }, //5.0.0 - 5.1.0 { "20180220163747", 4, {0x1f3b4, 0x465b, 0, 16, 11, HASH_ORDER_200_510, 0x5a63, 0x37901} }, //5.0.0 - 5.1.0
{ "20180802162753", 5, {0x27350, 0x17ff5, 1, 8, 11, HASH_ORDER_600_620, 0x5674, 0x1d5be} }, //6.0.0 - 6.1.0 { "20180802162753", 5, {0x27350, 0x17ff5, 1, 8, 11, HASH_ORDER_600_620, 0x5674, 0x1d5be} }, //6.0.0 - 6.1.0
{ "20181107105733", 6, {0x27350, 0x17ff5, 1, 8, 11, HASH_ORDER_600_620, 0x5674, 0x1d5be} }, //6.2.0 { "20181107105733", 6, {0x27350, 0x17ff5, 1, 8, 11, HASH_ORDER_600_620, 0x5674, 0x1d5be} }, //6.2.0
{ "20181218175730", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //7.0.0 { "20181218175730", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_10x, 0x5563, 0x1d437} }, //7.0.0
{ "20190208150037", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //7.0.1 { "20190208150037", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_10x, 0x5563, 0x1d437} }, //7.0.1
{ "20190314172056", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //8.0.0 - 8.0.1 { "20190314172056", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_10x, 0x5563, 0x1d437} }, //8.0.0 - 8.0.1
{ "20190531152432", 8, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //8.1.0 { "20190531152432", 8, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_10x, 0x5563, 0x1d437} }, //8.1.0
{ "20190809135709", 9, {0x2ec10, 0x5573, 0, 1, 12, HASH_ORDER_700_9xx, 0x6495, 0x1d807} }, //9.0.0 - 9.0.1 { "20190809135709", 9, {0x2ec10, 0x5573, 0, 1, 12, HASH_ORDER_700_10x, 0x6495, 0x1d807} }, //9.0.0 - 9.0.1
{ "20191021113848", 10,{0x2ec10, 0x5573, 0, 1, 12, HASH_ORDER_700_9xx, 0x6495, 0x1d807} }, //9.1.0 { "20191021113848", 10,{0x2ec10, 0x5573, 0, 1, 12, HASH_ORDER_700_10x, 0x6495, 0x1d807} }, //9.1.0
{ "20200303104606", 10,{0x30ea0, 0x5e4b, 0, 1, 12, HASH_ORDER_700_10x, 0x663c, 0x1d9a4} }, //10.0.0
{ NULL } //End. { NULL } //End.
}; };

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2019 CTCaer * Copyright (c) 2018-2020 CTCaer
* Copyright (c) 2018 Atmosphère-NX * Copyright (c) 2018 Atmosphère-NX
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
@@ -41,14 +41,34 @@ static u32 _pkg2_calc_kip1_size(pkg2_kip1_t *kip1)
void pkg2_get_newkern_info(u8 *kern_data) void pkg2_get_newkern_info(u8 *kern_data)
{ {
u32 info_op = *(u32 *)(kern_data + PKG2_NEWKERN_GET_INI1); u32 pkg2_newkern_ini1_off = 0;
pkg2_newkern_ini1_val = ((info_op & 0xFFFF) >> 3) + PKG2_NEWKERN_GET_INI1; // Parse ADR and PC. pkg2_newkern_ini1_start = 0;
// Find static OP offset that is close to INI1 offset.
u32 counter_ops = 0x100;
while (counter_ops)
{
if (*(u32 *)(kern_data + 0x100 - counter_ops) == PKG2_NEWKERN_GET_INI1_HEURISTIC)
{
pkg2_newkern_ini1_off = 0x100 - counter_ops + 12; // OP found. Add 12 for the INI1 offset.
break;
}
counter_ops -= 4;
}
// Offset not found?
if (!counter_ops)
return;
u32 info_op = *(u32 *)(kern_data + pkg2_newkern_ini1_off);
pkg2_newkern_ini1_val = ((info_op & 0xFFFF) >> 3) + pkg2_newkern_ini1_off; // Parse ADR and PC.
pkg2_newkern_ini1_start = *(u32 *)(kern_data + pkg2_newkern_ini1_val); pkg2_newkern_ini1_start = *(u32 *)(kern_data + pkg2_newkern_ini1_val);
pkg2_newkern_ini1_end = *(u32 *)(kern_data + pkg2_newkern_ini1_val + 0x8); 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) bool pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2)
{ {
u8 *ptr; u8 *ptr;
// Check for new pkg2 type. // Check for new pkg2 type.
@@ -56,6 +76,9 @@ void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2)
{ {
pkg2_get_newkern_info(pkg2->data); pkg2_get_newkern_info(pkg2->data);
if (!pkg2_newkern_ini1_start)
return false;
ptr = pkg2->data + pkg2_newkern_ini1_start; ptr = pkg2->data + pkg2_newkern_ini1_start;
*new_pkg2 = true; *new_pkg2 = true;
} }
@@ -75,6 +98,8 @@ void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2)
ptr += ki->size; ptr += ki->size;
DPRINTF(" kip1 %d:%s @ %08X (%08X)\n", i, kip1->name, (u32)kip1, ki->size); DPRINTF(" kip1 %d:%s @ %08X (%08X)\n", i, kip1->name, (u32)kip1, ki->size);
} }
return true;
} }
int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp) int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp)

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (C) 2018-2019 CTCaer * Copyright (C) 2018-2020 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -26,7 +26,7 @@
#define PKG2_SEC_KERNEL 0 #define PKG2_SEC_KERNEL 0
#define PKG2_SEC_INI1 1 #define PKG2_SEC_INI1 1
#define PKG2_NEWKERN_GET_INI1 0x44 #define PKG2_NEWKERN_GET_INI1_HEURISTIC 0xD2800015 // Offset of OP + 12 is the INI1 offset.
u32 pkg2_newkern_ini1_val; u32 pkg2_newkern_ini1_val;
u32 pkg2_newkern_ini1_start; u32 pkg2_newkern_ini1_start;
@@ -87,7 +87,7 @@ typedef struct _pkg2_kip1_info_t
link_t link; link_t link;
} pkg2_kip1_info_t; } pkg2_kip1_info_t;
void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2); bool pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2);
int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp); int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp);
pkg2_hdr_t *pkg2_decrypt(void *data); pkg2_hdr_t *pkg2_decrypt(void *data);

View File

@@ -18,21 +18,18 @@
#include <string.h> #include <string.h>
#include "ianos.h" #include "ianos.h"
#include "../utils/types.h"
#include "../libs/elfload/elfload.h"
#include "../../common/common_module.h" #include "../../common/common_module.h"
#include "../mem/heap.h"
#include "../gfx/gfx.h" #include "../gfx/gfx.h"
#include "../libs/elfload/elfload.h"
#include "../mem/heap.h"
#include "../storage/nx_sd.h"
#include "../utils/types.h"
#define IRAM_LIB_ADDR 0x4002B000 #define IRAM_LIB_ADDR 0x4002B000
#define DRAM_LIB_ADDR 0xE0000000 #define DRAM_LIB_ADDR 0xE0000000
extern heap_t _heap; extern heap_t _heap;
extern void *sd_file_read(const char *path, u32 *fsize);
extern bool sd_mount();
extern void sd_unmount();
void *elfBuf = NULL; void *elfBuf = NULL;
void *fileBuf = NULL; void *fileBuf = NULL;

View File

@@ -5629,7 +5629,8 @@ FRESULT f_forward (
} }
#endif /* FF_USE_FORWARD */ #endif /* FF_USE_FORWARD */
#pragma GCC push_options
#pragma GCC optimize ("Os")
#if FF_USE_MKFS && !FF_FS_READONLY #if FF_USE_MKFS && !FF_FS_READONLY
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
@@ -6094,7 +6095,7 @@ FRESULT f_mkfs (
LEAVE_MKFS(FR_OK); LEAVE_MKFS(FR_OK);
} }
#pragma GCC pop_options
#if FF_MULTI_PARTITION #if FF_MULTI_PARTITION
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/

View File

@@ -6,6 +6,7 @@ SECTIONS {
.text : { .text : {
*(.text._start); *(.text._start);
*(._boot_cfg); *(._boot_cfg);
*(.text._irq_setup);
*(.text*); *(.text*);
} }
.data : { .data : {

View File

@@ -39,6 +39,8 @@
#include "utils/sprintf.h" #include "utils/sprintf.h"
#include "utils/util.h" #include "utils/util.h"
#include "tegraexplorer/mainmenu.h" #include "tegraexplorer/mainmenu.h"
#include "tegraexplorer/gfx/gfxutils.h"
#include "storage/nx_sd.h"
//#include "keys/keys.h" //#include "keys/keys.h"
@@ -50,6 +52,7 @@ volatile nyx_storage_t *nyx_str = (nyx_storage_t *)NYX_STORAGE_ADDR;
hekate_config h_cfg; hekate_config h_cfg;
boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg; boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg;
/*
bool sd_mount() bool sd_mount()
{ {
if (sd_mounted) if (sd_mounted)
@@ -131,17 +134,20 @@ int sd_save_to_file(void *buf, u32 size, const char *filename)
return 0; return 0;
} }
*/
// This is a safe and unused DRAM region for our payloads. // This is a safe and unused DRAM region for our payloads.
#define RELOC_META_OFF 0x7C #define RELOC_META_OFF 0x7C
#define PATCHED_RELOC_SZ 0x94 #define PATCHED_RELOC_SZ 0x94
#define PATCHED_RELOC_STACK 0x40007000 #define PATCHED_RELOC_STACK 0x40007000
#define PATCHED_RELOC_ENTRY 0x40010000 #define PATCHED_RELOC_ENTRY 0x40010000
#define EXT_PAYLOAD_ADDR 0xC03C0000 #define EXT_PAYLOAD_ADDR 0xC0000000
#define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)) #define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10))
#define COREBOOT_ADDR (0xD0000000 - 0x100000) #define COREBOOT_END_ADDR 0xD0000000
#define CBFS_DRAM_EN_ADDR 0x4003e000 #define CBFS_DRAM_EN_ADDR 0x4003e000
#define CBFS_DRAM_MAGIC 0x4452414D // "DRAM" #define CBFS_DRAM_MAGIC 0x4452414D // "DRAM"
static void *coreboot_addr;
void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size) void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size)
{ {
@@ -156,7 +162,7 @@ void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size)
if (payload_size == 0x7000) if (payload_size == 0x7000)
{ {
memcpy((u8 *)(payload_src + ALIGN(PATCHED_RELOC_SZ, 0x10)), (u8 *)COREBOOT_ADDR, 0x7000); //Bootblock memcpy((u8 *)(payload_src + ALIGN(PATCHED_RELOC_SZ, 0x10)), coreboot_addr, 0x7000); //Bootblock
*(vu32 *)CBFS_DRAM_EN_ADDR = CBFS_DRAM_MAGIC; *(vu32 *)CBFS_DRAM_EN_ADDR = CBFS_DRAM_MAGIC;
} }
} }
@@ -186,7 +192,10 @@ int launch_payload(char *path)
if (size < 0x30000) if (size < 0x30000)
buf = (void *)RCM_PAYLOAD_ADDR; buf = (void *)RCM_PAYLOAD_ADDR;
else else
buf = (void *)COREBOOT_ADDR; {
coreboot_addr = (void *)(COREBOOT_END_ADDR - size);
buf = coreboot_addr;
}
if (f_read(&fp, buf, size, NULL)) if (f_read(&fp, buf, size, NULL))
{ {
@@ -224,6 +233,7 @@ int launch_payload(char *path)
return 1; return 1;
} }
/*
void launch_tools() void launch_tools()
{ {
u8 max_entries = 61; u8 max_entries = 61;
@@ -342,7 +352,7 @@ void dump_sysnand()
{ {
h_cfg.emummc_force_disable = true; h_cfg.emummc_force_disable = true;
b_cfg.extra_cfg &= ~EXTRA_CFG_DUMP_EMUMMC; b_cfg.extra_cfg &= ~EXTRA_CFG_DUMP_EMUMMC;
dump_keys(); //dump_keys();
} }
void dump_emunand() void dump_emunand()
@@ -351,7 +361,7 @@ void dump_emunand()
return; return;
emu_cfg.enabled = 1; emu_cfg.enabled = 1;
b_cfg.extra_cfg |= EXTRA_CFG_DUMP_EMUMMC; b_cfg.extra_cfg |= EXTRA_CFG_DUMP_EMUMMC;
dump_keys(); //dump_keys();
} }
ment_t ment_top[] = { ment_t ment_top[] = {
@@ -398,9 +408,55 @@ void _get_key_generations(char *sysnand_label, char *emunand_label) {
free(pkg1); free(pkg1);
ment_top[1].caption = emunand_label; ment_top[1].caption = emunand_label;
} }
*/
#define IPL_STACK_TOP 0x90010000 #define EXCP_EN_ADDR 0x4003FFFC
#define IPL_HEAP_START 0x90020000 #define EXCP_MAGIC 0x30505645 // EVP0
#define EXCP_TYPE_ADDR 0x4003FFF8
#define EXCP_TYPE_RESET 0x545352 // RST
#define EXCP_TYPE_UNDEF 0x464455 // UDF
#define EXCP_TYPE_PABRT 0x54424150 // PABT
#define EXCP_TYPE_DABRT 0x54424144 // DABT
#define EXCP_LR_ADDR 0x4003FFF4
static void _show_errors(){
u32 *excp_enabled = (u32 *)EXCP_EN_ADDR;
u32 *excp_type = (u32 *)EXCP_TYPE_ADDR;
u32 *excp_lr = (u32 *)EXCP_LR_ADDR;
if (*excp_enabled == EXCP_MAGIC)
h_cfg.errors |= ERR_EXCEPT_ENB;
if (h_cfg.errors & ERR_EXCEPT_ENB){
gfx_clearscreen();
SWAPCOLOR(COLOR_ORANGE);
gfx_printf("\nAn exception has occured while running TegraExplorer!\n(LR %08X)\n\n", *excp_lr);
SWAPCOLOR(COLOR_VIOLET);
gfx_printf("Exception: ");
SWAPCOLOR(COLOR_YELLOW);
switch (*excp_type){
case EXCP_TYPE_RESET:
gfx_printf("Reset");
break;
case EXCP_TYPE_UNDEF:
gfx_printf("Undefined instruction");
break;
case EXCP_TYPE_PABRT:
gfx_printf("Prefetch abort");
break;
case EXCP_TYPE_DABRT:
gfx_printf("Data abort");
break;
}
RESETCOLOR;
gfx_printf("\n\nPress vol+/- or power to continue");
*excp_enabled = 0;
btn_wait();
}
}
extern void pivot_stack(u32 stack_top); extern void pivot_stack(u32 stack_top);
@@ -450,6 +506,8 @@ void ipl_main()
tui_do_menu(&menu_top); tui_do_menu(&menu_top);
*/ */
_show_errors();
te_main(); te_main();
while (true) while (true)

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2020 CTCaer
* Copyright (c) 2018 M4xw * Copyright (c) 2018 M4xw
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
@@ -29,7 +30,7 @@ static void _heap_create(heap_t *heap, u32 start)
// Node info is before node address. // Node info is before node address.
static u32 _heap_alloc(heap_t *heap, u32 size) static u32 _heap_alloc(heap_t *heap, u32 size)
{ {
hnode_t *node, *new; hnode_t *node, *new_node;
// Align to cache line size. // Align to cache line size.
size = ALIGN(size, sizeof(hnode_t)); size = ALIGN(size, sizeof(hnode_t));
@@ -49,22 +50,29 @@ static u32 _heap_alloc(heap_t *heap, u32 size)
node = heap->first; node = heap->first;
while (true) while (true)
{ {
// Check if there's available unused node.
if (!node->used && (size <= node->size)) if (!node->used && (size <= node->size))
{ {
// Size and offset of the new unused node.
u32 new_size = node->size - size; u32 new_size = node->size - size;
new = (hnode_t *)((u32)node + sizeof(hnode_t) + size); new_node = (hnode_t *)((u32)node + sizeof(hnode_t) + size);
// If there's aligned leftover space, create a new node. // If there's aligned unused space from the old node,
// create a new one and set the leftover size.
if (new_size >= (sizeof(hnode_t) << 2)) if (new_size >= (sizeof(hnode_t) << 2))
{ {
new->size = new_size - sizeof(hnode_t); new_node->size = new_size - sizeof(hnode_t);
new->used = 0; new_node->used = 0;
new->next = node->next; new_node->next = node->next;
new->next->prev = new;
new->prev = node; // Check that we are not on first node.
node->next = new; if (new_node->next)
new_node->next->prev = new_node;
new_node->prev = node;
node->next = new_node;
} }
else else // Unused node size is just enough.
size += new_size; size += new_size;
node->size = size; node->size = size;
@@ -72,20 +80,23 @@ static u32 _heap_alloc(heap_t *heap, u32 size)
return (u32)node + sizeof(hnode_t); return (u32)node + sizeof(hnode_t);
} }
// No unused node found, try the next one.
if (node->next) if (node->next)
node = node->next; node = node->next;
else else
break; break;
} }
new = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size); // No unused node found, create a new one.
new->used = 1; new_node = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size);
new->size = size; new_node->used = 1;
new->prev = node; new_node->size = size;
new->next = NULL; new_node->prev = node;
node->next = new; new_node->next = NULL;
node->next = new_node;
return (u32)new + sizeof(hnode_t); return (u32)new_node + sizeof(hnode_t);
} }
static void _heap_free(heap_t *heap, u32 addr) static void _heap_free(heap_t *heap, u32 addr)
@@ -101,6 +112,7 @@ static void _heap_free(heap_t *heap, u32 addr)
{ {
node->prev->size += node->size + sizeof(hnode_t); node->prev->size += node->size + sizeof(hnode_t);
node->prev->next = node->next; node->prev->next = node->next;
if (node->next) if (node->next)
node->next->prev = node->prev; node->next->prev = node->prev;
} }

View File

@@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2020 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,

View File

@@ -463,4 +463,54 @@
#define MC_ERR_APB_ASID_UPDATE_STATUS 0x9d0 #define MC_ERR_APB_ASID_UPDATE_STATUS 0x9d0
#define MC_DA_CONFIG0 0x9dc #define MC_DA_CONFIG0 0x9dc
// MC_SECURITY_CARVEOUTX_CFG0
// Mode of LOCK_MODE.
#define PROTECT_MODE_SHIFT 0
#define SEC_CARVEOUT_CFG_SECURE (0 << PROTECT_MODE_SHIFT0)
#define SEC_CARVEOUT_CFG_TZ_SECURE (1 << PROTECT_MODE_SHIFT0)
// Enables PROTECT_MODE.
#define LOCK_MODE_SHIFT 1
#define SEC_CARVEOUT_CFG_UNLOCKED (0 << LOCK_MODE_SHIFT)
#define SEC_CARVEOUT_CFG_LOCKED (1 << LOCK_MODE_SHIFT)
#define ADDRESS_TYPE_SHIFT 2
#define SEC_CARVEOUT_CFG_ANY_ADDRESS (0 << ADDRESS_TYPE_SHIFT)
#define SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY (1 << ADDRESS_TYPE_SHIFT)
#define READ_ACCESS_LEVEL_SHIFT 3
#define SEC_CARVEOUT_CFG_RD_ALL (1 << READ_ACCESS_LEVEL_SHIFT)
#define SEC_CARVEOUT_CFG_RD_UNK (2 << READ_ACCESS_LEVEL_SHIFT)
#define SEC_CARVEOUT_CFG_RD_FALCON_LS (4 << READ_ACCESS_LEVEL_SHIFT)
#define SEC_CARVEOUT_CFG_RD_FALCON_HS (8 << READ_ACCESS_LEVEL_SHIFT)
#define WRITE_ACCESS_LEVEL_SHIFT 7
#define SEC_CARVEOUT_CFG_WR_ALL (1 << WRITE_ACCESS_LEVEL_SHIFT)
#define SEC_CARVEOUT_CFG_WR_UNK (2 << WRITE_ACCESS_LEVEL_SHIFT)
#define SEC_CARVEOUT_CFG_WR_FALCON_LS (4 << WRITE_ACCESS_LEVEL_SHIFT)
#define SEC_CARVEOUT_CFG_WR_FALCON_HS (8 << WRITE_ACCESS_LEVEL_SHIFT)
#define SEC_CARVEOUT_CFG_APERTURE_ID_MASK (3 << 11)
#define DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT 14
#define SEC_CARVEOUT_CFG_DIS_RD_CHECK_L0 (1 << DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT)
#define SEC_CARVEOUT_CFG_DIS_RD_CHECK_L1 (2 << DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT)
#define SEC_CARVEOUT_CFG_DIS_RD_CHECK_L2 (4 << DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT)
#define SEC_CARVEOUT_CFG_DIS_RD_CHECK_L3 (8 << DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT)
#define DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT 18
#define SEC_CARVEOUT_CFG_DIS_WR_CHECK_L0 (1 << DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT)
#define SEC_CARVEOUT_CFG_DIS_WR_CHECK_L1 (2 << DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT)
#define SEC_CARVEOUT_CFG_DIS_WR_CHECK_L2 (4 << DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT)
#define SEC_CARVEOUT_CFG_DIS_WR_CHECK_L3 (8 << DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT)
#define SEC_CARVEOUT_CFG_SEND_CFG_TO_GPU (1 << 22)
#define SEC_CARVEOUT_CFG_TZ_GLOBAL_WR_EN_BYPASS_CHECK (1 << 23)
#define SEC_CARVEOUT_CFG_TZ_GLOBAL_RD_EN_BYPASS_CHECK (1 << 24)
#define SEC_CARVEOUT_CFG_ALLOW_APERTURE_ID_MISMATCH (1 << 25)
#define SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH (1 << 26)
#define SEC_CARVEOUT_CFG_IS_WPR (1 << 27)
#endif #endif

View File

@@ -34,9 +34,10 @@ u32 minerva_init()
minerva_cfg = NULL; minerva_cfg = NULL;
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
memset(mtc_cfg, 0, sizeof(mtc_config_t));
// Set table to nyx storage. // Set table to nyx storage.
mtc_cfg->mtc_table = (emc_table_t *)&nyx_str->mtc_table; mtc_cfg->mtc_table = (emc_table_t *)nyx_str->mtc_table;
mtc_cfg->sdram_id = (fuse_read_odm(4) >> 3) & 0x1F; mtc_cfg->sdram_id = (fuse_read_odm(4) >> 3) & 0x1F;
mtc_cfg->init_done = MTC_NEW_MAGIC; // Initialize mtc table. mtc_cfg->init_done = MTC_NEW_MAGIC; // Initialize mtc table.
@@ -46,6 +47,8 @@ u32 minerva_init()
// Ensure that Minerva is new. // Ensure that Minerva is new.
if (mtc_cfg->init_done == MTC_INIT_MAGIC) if (mtc_cfg->init_done == MTC_INIT_MAGIC)
minerva_cfg = (void *)ep_addr; minerva_cfg = (void *)ep_addr;
else
mtc_cfg->init_done = 0;
if (!minerva_cfg) if (!minerva_cfg)
return 1; return 1;

View File

@@ -1,7 +1,7 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018 balika011 * Copyright (c) 2018 balika011
* Copyright (c) 2019 CTCaer * Copyright (c) 2019-2020 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -16,6 +16,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <string.h>
#include "mc.h" #include "mc.h"
#include "emc.h" #include "emc.h"
#include "sdram_param_t210.h" #include "sdram_param_t210.h"
@@ -29,7 +31,7 @@
#include "../soc/t210.h" #include "../soc/t210.h"
#include "../utils/util.h" #include "../utils/util.h"
#define CONFIG_SDRAM_COMPRESS_CFG #define CONFIG_SDRAM_KEEP_ALIVE
#ifdef CONFIG_SDRAM_COMPRESS_CFG #ifdef CONFIG_SDRAM_COMPRESS_CFG
#include "../libs/compr/lz.h" #include "../libs/compr/lz.h"
@@ -40,13 +42,57 @@
static u32 _get_sdram_id() static u32 _get_sdram_id()
{ {
u32 sdram_id = (fuse_read_odm(4) & 0x38) >> 3; return ((fuse_read_odm(4) & 0x38) >> 3);
}
// Check if id is proper. static bool _sdram_wait_emc_status(u32 reg_offset, u32 bit_mask, bool updated_state, s32 emc_channel)
if (sdram_id > 7) {
sdram_id = 0; bool err = true;
return sdram_id; for (s32 i = 0; i < EMC_STATUS_UPDATE_TIMEOUT; i++)
{
if (emc_channel)
{
if (emc_channel != 1)
goto done;
if (((EMC_CH1(reg_offset) & bit_mask) != 0) == updated_state)
{
err = false;
break;
}
}
else if (((EMC(reg_offset) & bit_mask) != 0) == updated_state)
{
err = false;
break;
}
usleep(1);
}
done:
return err;
}
static void _sdram_req_mrr_data(u32 data, bool dual_channel)
{
EMC(EMC_MRR) = data;
_sdram_wait_emc_status(EMC_EMC_STATUS, EMC_STATUS_MRR_DIVLD, true, EMC_CHAN0);
if (dual_channel)
_sdram_wait_emc_status(EMC_EMC_STATUS, EMC_STATUS_MRR_DIVLD, true, EMC_CHAN1);
}
emc_mr_data_t sdram_read_mrx(emc_mr_t mrx)
{
emc_mr_data_t data;
_sdram_req_mrr_data((1 << 31) | (mrx << 16), EMC_CHAN0);
data.dev0_ch0 = EMC(EMC_MRR) & 0xFF;
data.dev0_ch1 = (EMC(EMC_MRR) & 0xFF00 >> 8);
_sdram_req_mrr_data((1 << 30) | (mrx << 16), EMC_CHAN1);
data.dev1_ch0 = EMC(EMC_MRR) & 0xFF;
data.dev1_ch1 = (EMC(EMC_MRR) & 0xFF00 >> 8);
return data;
} }
static void _sdram_config(const sdram_params_t *params) static void _sdram_config(const sdram_params_t *params)
@@ -73,10 +119,14 @@ static void _sdram_config(const sdram_params_t *params)
CLOCK(CLK_RST_CONTROLLER_PLLM_MISC1) = params->pllm_setup_control; CLOCK(CLK_RST_CONTROLLER_PLLM_MISC1) = params->pllm_setup_control;
CLOCK(CLK_RST_CONTROLLER_PLLM_MISC2) = 0; CLOCK(CLK_RST_CONTROLLER_PLLM_MISC2) = 0;
// u32 tmp = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | ((params->pllm_post_divider & 0xFFFF) << 20); #ifdef CONFIG_SDRAM_KEEP_ALIVE
// CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = tmp; CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) =
// CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = tmp | 0x40000000; (params->pllm_feedback_divider << 8) | params->pllm_input_divider | ((params->pllm_post_divider & 0xFFFF) << 20) | PLLCX_BASE_ENABLE;
CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | 0x40000000 | ((params->pllm_post_divider & 0xFFFF) << 20); #else
u32 pllm_div = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | ((params->pllm_post_divider & 0xFFFF) << 20);
CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = pllm_div;
CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = pllm_div | PLLCX_BASE_ENABLE;
#endif
u32 wait_end = get_tmr_us() + 300; u32 wait_end = get_tmr_us() + 300;
while (!(CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) & 0x8000000)) while (!(CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) & 0x8000000))
@@ -91,7 +141,7 @@ break_nosleep:
if (params->emc_clock_source_dll) if (params->emc_clock_source_dll)
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = params->emc_clock_source_dll; CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = params->emc_clock_source_dll;
if (params->clear_clock2_mc1) if (params->clear_clock2_mc1)
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = 0x40000000; CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = 0x40000000; // Clear Reset to MC1.
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x2000001; // Enable EMC and MEM clocks. CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x2000001; // Enable EMC and MEM clocks.
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x4000; // Enable EMC_DLL clock. CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x4000; // Enable EMC_DLL clock.
@@ -509,9 +559,9 @@ break_nosleep:
// ZQ CAL setup (not actually issuing ZQ CAL now). // ZQ CAL setup (not actually issuing ZQ CAL now).
if (params->emc_zcal_warm_cold_boot_enables & 1) if (params->emc_zcal_warm_cold_boot_enables & 1)
{ {
if (params->memory_type == 2) if (params->memory_type == MEMORY_TYPE_DDR3L)
EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt << 3; EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt << 3;
if (params->memory_type == 3) if (params->memory_type == MEMORY_TYPE_LPDDR4)
{ {
EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt; EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt;
EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd; EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd;
@@ -527,7 +577,7 @@ break_nosleep:
// Set clock enable signal. // Set clock enable signal.
u32 pin_gpio_cfg = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12); u32 pin_gpio_cfg = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12);
if (params->memory_type == 2 || params->memory_type == 3) if (params->memory_type == MEMORY_TYPE_DDR3L || params->memory_type == MEMORY_TYPE_LPDDR4)
{ {
EMC(EMC_PIN) = pin_gpio_cfg; EMC(EMC_PIN) = pin_gpio_cfg;
(void)EMC(EMC_PIN); (void)EMC(EMC_PIN);
@@ -536,9 +586,9 @@ break_nosleep:
(void)EMC(EMC_PIN); (void)EMC(EMC_PIN);
} }
if (params->memory_type == 3) if (params->memory_type == MEMORY_TYPE_LPDDR4)
usleep(params->emc_pin_extra_wait + 2000); usleep(params->emc_pin_extra_wait + 2000);
else if (params->memory_type == 2) else if (params->memory_type == MEMORY_TYPE_DDR3L)
usleep(params->emc_pin_extra_wait + 500); usleep(params->emc_pin_extra_wait + 500);
// Enable clock enable signal. // Enable clock enable signal.
@@ -547,15 +597,15 @@ break_nosleep:
usleep(params->emc_pin_program_wait); usleep(params->emc_pin_program_wait);
// Send NOP (trigger just needs to be non-zero). // Send NOP (trigger just needs to be non-zero).
if (params->memory_type != 3) if (params->memory_type != MEMORY_TYPE_LPDDR4)
EMC(EMC_NOP) = (params->emc_dev_select << 30) + 1; EMC(EMC_NOP) = (params->emc_dev_select << 30) + 1;
// On coldboot w/LPDDR2/3, wait 200 uSec after asserting CKE high. // On coldboot w/LPDDR2/3, wait 200 uSec after asserting CKE high.
if (params->memory_type == 1) if (params->memory_type == MEMORY_TYPE_LPDDR2)
usleep(params->emc_pin_extra_wait + 200); usleep(params->emc_pin_extra_wait + 200);
// Init zq calibration, // Init zq calibration,
if (params->memory_type == 3) if (params->memory_type == MEMORY_TYPE_LPDDR4)
{ {
// Patch 6 using BCT spare variables. // Patch 6 using BCT spare variables.
if (params->emc_bct_spare10) if (params->emc_bct_spare10)
@@ -596,7 +646,7 @@ break_nosleep:
PMC(APBDEV_PMC_DDR_CFG) = params->pmc_ddr_cfg; PMC(APBDEV_PMC_DDR_CFG) = params->pmc_ddr_cfg;
// Start periodic ZQ calibration (LPDDRx only). // Start periodic ZQ calibration (LPDDRx only).
if (params->memory_type - 1 <= 2) if (params->memory_type && params->memory_type <= MEMORY_TYPE_LPDDR4)
{ {
EMC(EMC_ZCAL_INTERVAL) = params->emc_zcal_interval; EMC(EMC_ZCAL_INTERVAL) = params->emc_zcal_interval;
EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt; EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt;
@@ -641,18 +691,47 @@ break_nosleep:
MC(MC_SEC_CARVEOUT_REG_CTRL) = params->mc_sec_carveout_protect_write_access; MC(MC_SEC_CARVEOUT_REG_CTRL) = params->mc_sec_carveout_protect_write_access;
MC(MC_MTS_CARVEOUT_REG_CTRL) = params->mc_mts_carveout_reg_ctrl; MC(MC_MTS_CARVEOUT_REG_CTRL) = params->mc_mts_carveout_reg_ctrl;
//Disable write access to a bunch of EMC registers. // Disable write access to a bunch of EMC registers.
MC(MC_EMEM_CFG_ACCESS_CTRL) = 1; MC(MC_EMEM_CFG_ACCESS_CTRL) = 1;
} }
#ifndef CONFIG_SDRAM_COMPRESS_CFG
static void _sdram_patch_model_params(u32 dramid, u32 *params)
{
for (u32 i = 0; i < sizeof(sdram_cfg_vendor_patches) / sizeof(sdram_vendor_patch_t); i++)
if (sdram_cfg_vendor_patches[i].dramid & DRAM_ID(dramid))
params[sdram_cfg_vendor_patches[i].addr] = sdram_cfg_vendor_patches[i].val;
}
#endif
sdram_params_t *sdram_get_params() sdram_params_t *sdram_get_params()
{ {
// Check if id is proper.
u32 dramid = _get_sdram_id();
if (dramid > 6)
dramid = 0;
#ifdef CONFIG_SDRAM_COMPRESS_CFG #ifdef CONFIG_SDRAM_COMPRESS_CFG
u8 *buf = (u8 *)SDRAM_PARAMS_ADDR; u8 *buf = (u8 *)SDRAM_PARAMS_ADDR;
LZ_Uncompress(_dram_cfg_lz, buf, sizeof(_dram_cfg_lz)); LZ_Uncompress(_dram_cfg_lz, buf, sizeof(_dram_cfg_lz));
return (sdram_params_t *)&buf[sizeof(sdram_params_t) * _get_sdram_id()]; return (sdram_params_t *)&buf[sizeof(sdram_params_t) * dramid];
#else #else
return _dram_cfgs[_get_sdram_id()]; sdram_params_t *buf = (sdram_params_t *)SDRAM_PARAMS_ADDR;
memcpy(buf, &_dram_cfg_0_samsung_4gb, sizeof(sdram_params_t));
switch (dramid)
{
case DRAM_4GB_SAMSUNG_K4F6E304HB_MGCH:
case DRAM_4GB_MICRON_MT53B512M32D2NP_062_WT:
break;
case DRAM_4GB_HYNIX_H9HCNNNBPUMLHR_NLN:
case DRAM_4GB_COPPER_UNK_3:
case DRAM_6GB_SAMSUNG_K4FHE3D4HM_MFCH:
case DRAM_4GB_COPPER_UNK_5:
case DRAM_4GB_COPPER_UNK_6:
_sdram_patch_model_params(dramid, (u32 *)buf);
break;
}
return buf;
#endif #endif
} }
@@ -696,7 +775,6 @@ sdram_params_t *sdram_get_params_patched()
void sdram_init() void sdram_init()
{ {
//TODO: sdram_id should be in [0,4].
const sdram_params_t *params = (const sdram_params_t *)sdram_get_params(); const sdram_params_t *params = (const sdram_params_t *)sdram_get_params();
// Set DRAM voltage. // Set DRAM voltage.

View File

@@ -17,11 +17,13 @@
#ifndef _SDRAM_H_ #ifndef _SDRAM_H_
#define _SDRAM_H_ #define _SDRAM_H_
#include "emc.h"
#include "sdram_param_t210.h" #include "sdram_param_t210.h"
void sdram_init(); void sdram_init();
sdram_params_t *sdram_get_params(); sdram_params_t *sdram_get_params();
sdram_params_t *sdram_get_params_patched(); sdram_params_t *sdram_get_params_patched();
void sdram_lp0_save_params(const void *params); void sdram_lp0_save_params(const void *params);
emc_mr_data_t sdram_read_mrx(emc_mr_t mrx);
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@@ -26,12 +26,12 @@
#ifndef _SDRAM_PARAM_T210_H_ #ifndef _SDRAM_PARAM_T210_H_
#define _SDRAM_PARAM_T210_H_ #define _SDRAM_PARAM_T210_H_
#define MEMORY_TYPE_NONE 0 #define MEMORY_TYPE_NONE 0
#define MEMORY_TYPE_DDR 0 #define MEMORY_TYPE_DDR 0
#define MEMORY_TYPE_LPDDR 0 #define MEMORY_TYPE_LPDDR 0
#define MEMORY_TYPE_DDR2 0 #define MEMORY_TYPE_DDR2 0
#define MEMORY_TYPE_LPDDR2 1 #define MEMORY_TYPE_LPDDR2 1
#define MEMORY_TYPE_DDR3 2 #define MEMORY_TYPE_DDR3L 2
#define MEMORY_TYPE_LPDDR4 3 #define MEMORY_TYPE_LPDDR4 3
/** /**

170
source/power/bq24193.c Normal file
View File

@@ -0,0 +1,170 @@
/*
* 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"
#pragma GCC push_options
#pragma GCC optimize ("Os")
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 = 0;
*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 = 0;
*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 = 0;
*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);
}
#pragma GCC pop_options

119
source/power/bq24193.h Normal file
View File

@@ -0,0 +1,119 @@
/*
* 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_ */

View File

@@ -46,6 +46,12 @@
#pragma GCC push_options #pragma GCC push_options
#pragma GCC optimize ("Os") #pragma GCC optimize ("Os")
static u32 battery_voltage = 0;
u32 max17050_get_cached_batt_volt()
{
return battery_voltage;
}
int max17050_get_property(enum MAX17050_reg reg, int *value) int max17050_get_property(enum MAX17050_reg reg, int *value)
{ {
u16 data; u16 data;
@@ -74,6 +80,7 @@ int max17050_get_property(enum MAX17050_reg reg, int *value)
case MAX17050_VCELL: // Voltage now. case MAX17050_VCELL: // Voltage now.
i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_VCELL); i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_VCELL);
*value = data * 625 / 8 / 1000; *value = data * 625 / 8 / 1000;
battery_voltage = *value;
break; break;
case MAX17050_AvgVCELL: // Voltage avg. case MAX17050_AvgVCELL: // Voltage avg.
i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_AvgVCELL); i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_AvgVCELL);

View File

@@ -4,7 +4,7 @@
* *
* Copyright (c) 2011 Samsung Electronics * Copyright (c) 2011 Samsung Electronics
* MyungJoo Ham <myungjoo.ham@samsung.com> * MyungJoo Ham <myungjoo.ham@samsung.com>
* Copyright (c) 2018 CTCaer * Copyright (c) 2018-2020 CTCaer
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -24,6 +24,8 @@
#ifndef __MAX17050_H_ #ifndef __MAX17050_H_
#define __MAX17050_H_ #define __MAX17050_H_
#include "../utils/types.h"
#define MAX17050_STATUS_BattAbsent (1 << 3) #define MAX17050_STATUS_BattAbsent (1 << 3)
#define MAX17050_DEFAULT_SNS_RESISTOR 10000 #define MAX17050_DEFAULT_SNS_RESISTOR 10000
@@ -96,14 +98,17 @@ enum MAX17050_reg {
MAX17050_K_empty0 = 0x3B, MAX17050_K_empty0 = 0x3B,
MAX17050_TaskPeriod = 0x3C, MAX17050_TaskPeriod = 0x3C,
MAX17050_FSTAT = 0x3D, MAX17050_FSTAT = 0x3D,
MAX17050_TIMER = 0x3E,
MAX17050_SHDNTIMER = 0x3F, MAX17050_SHDNTIMER = 0x3F,
MAX17050_QRTbl30 = 0x42, MAX17050_QRTbl30 = 0x42,
MAX17050_dQacc = 0x45, MAX17050_dQacc = 0x45,
MAX17050_dPacc = 0x46, MAX17050_dPacc = 0x46,
MAX17050_VFSOC0 = 0x48, MAX17050_VFSOC0 = 0x48,
Max17050_QH0 = 0x4C,
MAX17050_QH = 0x4D, MAX17050_QH = 0x4D,
MAX17050_QL = 0x4E, MAX17050_QL = 0x4E,
@@ -111,6 +116,8 @@ enum MAX17050_reg {
MAX17050_MaxVolt = 0x51, // Custom ID. Not to be sent to i2c. MAX17050_MaxVolt = 0x51, // Custom ID. Not to be sent to i2c.
MAX17050_VFSOC0Enable = 0x60, MAX17050_VFSOC0Enable = 0x60,
MAX17050_MODELEnable1 = 0x62,
MAX17050_MODELEnable2 = 0x63,
MAX17050_MODELChrTbl = 0x80, MAX17050_MODELChrTbl = 0x80,
@@ -123,5 +130,6 @@ enum MAX17050_reg {
int max17050_get_property(enum MAX17050_reg reg, int *value); int max17050_get_property(enum MAX17050_reg reg, int *value);
int max17050_fix_configuration(); int max17050_fix_configuration();
u32 max17050_get_cached_batt_volt();
#endif /* __MAX17050_H_ */ #endif /* __MAX17050_H_ */

View File

@@ -137,6 +137,7 @@ int max77620_regulator_enable(u32 id, int enable)
return 1; return 1;
} }
// LDO only.
int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags) int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags)
{ {
if (id > REGULATOR_MAX) if (id > REGULATOR_MAX)
@@ -168,9 +169,9 @@ void max77620_config_default()
_max77620_try_set_reg(MAX77620_REG_SD_CFG2, 4); _max77620_try_set_reg(MAX77620_REG_SD_CFG2, 4);
} }
void max77620_low_battery_monitor_config() void max77620_low_battery_monitor_config(bool enable)
{ {
_max77620_try_set_reg(MAX77620_REG_CNFGGLBL1, _max77620_try_set_reg(MAX77620_REG_CNFGGLBL1,
MAX77620_CNFGGLBL1_LBDAC_EN | MAX77620_CNFGGLBL1_MPPLD | MAX77620_CNFGGLBL1_LBDAC_EN | (enable ? MAX77620_CNFGGLBL1_MPPLD : 0) |
MAX77620_CNFGGLBL1_LBHYST_200 | MAX77620_CNFGGLBL1_LBDAC_2800); MAX77620_CNFGGLBL1_LBHYST_200 | MAX77620_CNFGGLBL1_LBDAC_2800);
} }

View File

@@ -33,7 +33,7 @@
* ldo2 | SDMMC1 | 50000 | 800000 | 1800000 | 3300000 | * 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 | * ldo4 | RTC | 12500 | 800000 | 850000 | 850000 |
* ldo5 | GC ASIC | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv) * ldo5 | GC Card | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv)
* ldo6 | Touch, ALS | 50000 | 800000 | 2900000 | 2900000 | 2.9V * ldo6 | Touch, ALS | 50000 | 800000 | 2900000 | 2900000 | 2.9V
* ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 | * ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 |
* ldo8 | XUSB, DC | 50000 | 800000 | 1050000 | 1050000 | * ldo8 | XUSB, DC | 50000 | 800000 | 1050000 | 1050000 |
@@ -113,6 +113,6 @@ int max77620_regulator_set_voltage(u32 id, u32 mv);
int max77620_regulator_enable(u32 id, int enable); int max77620_regulator_enable(u32 id, int enable);
int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags); int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags);
void max77620_config_default(); void max77620_config_default();
void max77620_low_battery_monitor_config(); void max77620_low_battery_monitor_config(bool enable);
#endif #endif

View File

@@ -0,0 +1,76 @@
/*
* 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 "../soc/gpio.h"
#include "../soc/pinmux.h"
#include "../soc/pmc.h"
#include "../soc/t210.h"
#include "../utils/types.h"
static u8 reg_5v_dev = 0;
void regulator_enable_5v(u8 dev)
{
// The power supply selection from battery or USB is automatic.
if (!reg_5v_dev)
{
// Fan and Rail power from internal 5V regulator (battery).
PINMUX_AUX(PINMUX_AUX_SATA_LED_ACTIVE) = 1;
gpio_config(GPIO_PORT_A, GPIO_PIN_5, GPIO_MODE_GPIO);
gpio_output_enable(GPIO_PORT_A, GPIO_PIN_5, GPIO_OUTPUT_ENABLE);
gpio_write(GPIO_PORT_A, GPIO_PIN_5, GPIO_HIGH);
// Fan and Rail power from USB 5V VDD.
PINMUX_AUX(PINMUX_AUX_USB_VBUS_EN0) = PINMUX_LPDR | 1;
gpio_config(GPIO_PORT_CC, GPIO_PIN_4, GPIO_MODE_GPIO);
gpio_output_enable(GPIO_PORT_CC, GPIO_PIN_4, GPIO_OUTPUT_ENABLE);
gpio_write(GPIO_PORT_CC, GPIO_PIN_4, GPIO_HIGH);
// Make sure GPIO power is enabled.
PMC(APBDEV_PMC_NO_IOPOWER) &= ~PMC_NO_IOPOWER_GPIO_IO_EN;
// Override power detect for GPIO AO IO rails.
PMC(APBDEV_PMC_PWR_DET_VAL) &= ~PMC_PWR_DET_GPIO_IO_EN;
}
reg_5v_dev |= dev;
}
void regulator_disable_5v(u8 dev)
{
reg_5v_dev &= ~dev;
if (!reg_5v_dev)
{
// Rail power from internal 5V regulator (battery).
gpio_write(GPIO_PORT_A, GPIO_PIN_5, GPIO_LOW);
gpio_output_enable(GPIO_PORT_A, GPIO_PIN_5, GPIO_OUTPUT_DISABLE);
gpio_config(GPIO_PORT_A, GPIO_PIN_5, GPIO_MODE_SPIO);
PINMUX_AUX(PINMUX_AUX_SATA_LED_ACTIVE) = PINMUX_PARKED | PINMUX_INPUT_ENABLE;
// Rail power from USB 5V VDD.
gpio_write(GPIO_PORT_CC, GPIO_PIN_4, GPIO_LOW);
gpio_output_enable(GPIO_PORT_CC, GPIO_PIN_4, GPIO_OUTPUT_DISABLE);
gpio_config(GPIO_PORT_CC, GPIO_PIN_4, GPIO_MODE_SPIO);
PINMUX_AUX(PINMUX_AUX_USB_VBUS_EN0) = PINMUX_IO_HV | PINMUX_LPDR | PINMUX_PARKED | PINMUX_INPUT_ENABLE;
// GPIO AO IO rails.
PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_GPIO_IO_EN;
}
}
bool regulator_get_5v_dev_enabled(u8 dev)
{
return (reg_5v_dev & dev);
}

View File

@@ -0,0 +1,34 @@
/*
* 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 _REGULATOR_5V_H_
#define _REGULATOR_5V_H_
#include "../utils/types.h"
enum
{
REGULATOR_5V_FAN = (1 << 0),
REGULATOR_5V_JC_R = (1 << 1),
REGULATOR_5V_JC_L = (1 << 2),
REGULATOR_5V_ALL = 0xFF
};
void regulator_enable_5v(u8 dev);
void regulator_disable_5v(u8 dev);
bool regulator_get_5v_dev_enabled(u8 dev);
#endif

View File

@@ -1,7 +1,8 @@
/* /*
* PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC * PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC
* *
* 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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -34,10 +35,10 @@ void max77620_rtc_get_time(rtc_time_t *time)
// Get time. // Get time.
time->sec = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_SEC_REG) & 0x7F; time->sec = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_SEC_REG) & 0x7F;
time->min = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MIN_REG) & 0x7F; time->min = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MIN_REG) & 0x7F;
u8 hour = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_HOUR_REG);
time->hour = hour & 0x1F;
time->hour = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_HOUR_REG) & 0x1F; if (!(val & MAX77620_RTC_24H) && (hour & MAX77620_RTC_HOUR_PM_MASK))
if (!(val & MAX77620_RTC_24H) && time->hour & MAX77620_RTC_HOUR_PM_MASK)
time->hour = (time->hour & 0xF) + 12; time->hour = (time->hour & 0xF) + 12;
// Get day of week. 1: Monday to 7: Sunday. // Get day of week. 1: Monday to 7: Sunday.
@@ -75,3 +76,94 @@ void max77620_rtc_stop_alarm()
// Update RTC clock from RTC regs. // Update RTC clock from RTC regs.
i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_WRITE_UPDATE); i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_WRITE_UPDATE);
} }
void max77620_rtc_epoch_to_date(u32 epoch, rtc_time_t *time)
{
u32 tmp, edays, year, month, day;
// Set time.
time->sec = epoch % 60;
epoch /= 60;
time->min = epoch % 60;
epoch /= 60;
time->hour = epoch % 24;
epoch /= 24;
// Calculate base date values.
tmp = (u32)(((u64)4 * epoch + 102032) / 146097 + 15);
tmp = (u32)((u64)epoch + 2442113 + tmp - (tmp >> 2));
year = (20 * tmp - 2442) / 7305;
edays = tmp - 365 * year - (year >> 2);
month = edays * 1000 / 30601;
day = edays - month * 30 - month * 601 / 1000;
// Month/Year offset.
if(month < 14)
{
year -= 4716;
month--;
}
else
{
year -= 4715;
month -= 13;
}
// Set date.
time->year = year;
time->month = month;
time->day = day;
// Set weekday.
time->weekday = 0; //! TODO.
}
u32 max77620_rtc_date_to_epoch(const rtc_time_t *time, bool hos_encoding)
{
u32 year, month, epoch;
//Year
year = time->year;
//Month of year
month = time->month;
if (!hos_encoding)
{
// Month/Year offset.
if(month < 3)
{
month += 12;
year--;
}
}
else
{
year -= 2000;
month++;
// Month/Year offset.
if(month < 3)
{
month += 9;
year--;
}
else
month -= 3;
}
epoch = (365 * year) + (year >> 2) - (year / 100) + (year / 400); // Years to days.
if (!hos_encoding)
{
epoch += (30 * month) + (3 * (month + 1) / 5) + time->day; // Months to days.
epoch -= 719561; // Epoch time is 1/1/1970.
}
else
epoch += (30 * month) + ((3 * month + 2) / 5) + 59 + time->day; // Months to days.
epoch *= 86400; // Days to seconds.
epoch += (3600 * time->hour) + (60 * time->min) + time->sec; // Add hours, minutes and seconds.
return epoch;
}

View File

@@ -71,5 +71,7 @@ typedef struct _rtc_time_t {
void max77620_rtc_get_time(rtc_time_t *time); void max77620_rtc_get_time(rtc_time_t *time);
void max77620_rtc_stop_alarm(); void max77620_rtc_stop_alarm();
void max77620_rtc_epoch_to_date(u32 epoch, rtc_time_t *time);
u32 max77620_rtc_date_to_epoch(const rtc_time_t *time, bool hos_encoding);
#endif /* _MFD_MAX77620_RTC_H_ */ #endif /* _MFD_MAX77620_RTC_H_ */

View File

@@ -2,7 +2,7 @@
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018 CTCaer * Copyright (c) 2018 CTCaer
* Copyright (c) 2018 Atmosphère-NX * Copyright (c) 2018 Atmosphère-NX
* Copyright (c) 2019 shchmue * Copyright (c) 2019-2020 shchmue
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,

View File

@@ -70,27 +70,26 @@
#define SE_CONFIG_DEC_MODE(x) (x << SE_CONFIG_DEC_MODE_SHIFT) #define SE_CONFIG_DEC_MODE(x) (x << SE_CONFIG_DEC_MODE_SHIFT)
#define SE_RNG_CONFIG_REG_OFFSET 0x340 #define SE_RNG_CONFIG_REG_OFFSET 0x340
#define DRBG_MODE_SHIFT 0 #define RNG_MODE_SHIFT 0
#define DRBG_MODE_NORMAL 0 #define RNG_MODE_NORMAL 0
#define DRBG_MODE_FORCE_INSTANTION 1 #define RNG_MODE_FORCE_INSTANTION 1
#define DRBG_MODE_FORCE_RESEED 2 #define RNG_MODE_FORCE_RESEED 2
#define SE_RNG_CONFIG_MODE(x) (x << DRBG_MODE_SHIFT) #define SE_RNG_CONFIG_MODE(x) (x << RNG_MODE_SHIFT)
#define RNG_SRC_SHIFT 2
#define RNG_SRC_NONE 0
#define RNG_SRC_ENTROPY 1
#define RNG_SRC_LFSR 2
#define SE_RNG_CONFIG_SRC(x) (x << RNG_SRC_SHIFT)
#define SE_RNG_SRC_CONFIG_REG_OFFSET 0x344 #define SE_RNG_SRC_CONFIG_REG_OFFSET 0x344
#define DRBG_RO_ENT_SRC_SHIFT 1 #define RNG_SRC_RO_ENT_SHIFT 1
#define DRBG_RO_ENT_SRC_ENABLE 1 #define RNG_SRC_RO_ENT_ENABLE 1
#define DRBG_RO_ENT_SRC_DISABLE 0 #define RNG_SRC_RO_ENT_DISABLE 0
#define SE_RNG_SRC_CONFIG_RO_ENT_SRC(x) (x << DRBG_RO_ENT_SRC_SHIFT) #define SE_RNG_SRC_CONFIG_ENT_SRC(x) (x << RNG_SRC_RO_ENT_SHIFT)
#define DRBG_RO_ENT_SRC_LOCK_SHIFT 0 #define RNG_SRC_RO_ENT_LOCK_SHIFT 0
#define DRBG_RO_ENT_SRC_LOCK_ENABLE 1 #define RNG_SRC_RO_ENT_LOCK_ENABLE 1
#define DRBG_RO_ENT_SRC_LOCK_DISABLE 0 #define RNG_SRC_RO_ENT_LOCK_DISABLE 0
#define SE_RNG_SRC_CONFIG_RO_ENT_SRC_LOCK(x) (x << DRBG_RO_ENT_SRC_LOCK_SHIFT) #define SE_RNG_SRC_CONFIG_ENT_SRC_LOCK(x) (x << RNG_SRC_RO_ENT_LOCK_SHIFT)
#define DRBG_SRC_SHIFT 2
#define DRBG_SRC_NONE 0
#define DRBG_SRC_ENTROPY 1
#define DRBG_SRC_LFSR 2
#define SE_RNG_CONFIG_SRC(x) (x << DRBG_SRC_SHIFT)
#define SE_RNG_RESEED_INTERVAL_REG_OFFSET 0x348 #define SE_RNG_RESEED_INTERVAL_REG_OFFSET 0x348
@@ -119,6 +118,8 @@
#define OP_DONE 1 #define OP_DONE 1
#define SE_OP_DONE(x, y) ((x) && (y << SE_OP_DONE_SHIFT)) #define SE_OP_DONE(x, y) ((x) && (y << SE_OP_DONE_SHIFT))
#define SE_CRYPTO_LAST_BLOCK 0x080
#define SE_CRYPTO_REG_OFFSET 0x304 #define SE_CRYPTO_REG_OFFSET 0x304
#define SE_CRYPTO_HASH_SHIFT 0 #define SE_CRYPTO_HASH_SHIFT 0
#define HASH_DISABLE 0 #define HASH_DISABLE 0
@@ -191,6 +192,7 @@
#define SRK 6 #define SRK 6
#define RSA_KEYTABLE 1 #define RSA_KEYTABLE 1
#define AES_KEYTABLE 2
#define SE_CONTEXT_SAVE_SRC(x) (x << SE_CONTEXT_SAVE_SRC_SHIFT) #define SE_CONTEXT_SAVE_SRC(x) (x << SE_CONTEXT_SAVE_SRC_SHIFT)
#define SE_CONTEXT_SAVE_RSA_KEY_INDEX_SHIFT 16 #define SE_CONTEXT_SAVE_RSA_KEY_INDEX_SHIFT 16

View File

@@ -80,7 +80,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
kfuse_wait_ready(); kfuse_wait_ready();
//Configure Falcon. // Configure Falcon.
TSEC(TSEC_DMACTL) = 0; TSEC(TSEC_DMACTL) = 0;
TSEC(TSEC_IRQMSET) = TSEC(TSEC_IRQMSET) =
TSEC_IRQMSET_EXT(0xFF) | TSEC_IRQMSET_EXT(0xFF) |
@@ -102,7 +102,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
goto out; goto out;
} }
//Load firmware or emulate memio environment for newer TSEC fw. // Load firmware or emulate memio environment for newer TSEC fw.
if (kb == KB_FIRMWARE_VERSION_620) if (kb == KB_FIRMWARE_VERSION_620)
TSEC(TSEC_DMATRFBASE) = (u32)tsec_ctxt->fw >> 8; TSEC(TSEC_DMATRFBASE) = (u32)tsec_ctxt->fw >> 8;
else else
@@ -126,7 +126,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
{ {
// Init SMMU translation for TSEC. // Init SMMU translation for TSEC.
pdir = smmu_init_for_tsec(); pdir = smmu_init_for_tsec();
smmu_init(0x4002B000); smmu_init(tsec_ctxt->secmon_base);
// Enable SMMU // Enable SMMU
if (!smmu_is_used()) if (!smmu_is_used())
smmu_enable(); smmu_enable();
@@ -169,7 +169,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
iram = page_alloc(0x30); iram = page_alloc(0x30);
memcpy(iram, tsec_ctxt->pkg1, 0x30000); memcpy(iram, tsec_ctxt->pkg1, 0x30000);
// PKG1.1 magic offset. // PKG1.1 magic offset.
pkg11_magic_off = (u32 *)(iram + (0x7000 / 4)); pkg11_magic_off = (u32 *)(iram + ((tsec_ctxt->pkg11_off + 0x20) / 4));
smmu_map(pdir, 0x40010000, (u32)iram, 0x30, _READABLE | _WRITABLE | _NONSECURE); smmu_map(pdir, 0x40010000, (u32)iram, 0x30, _READABLE | _WRITABLE | _NONSECURE);
// Exception vectors // Exception vectors
@@ -177,7 +177,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
smmu_map(pdir, EXCP_VEC_BASE, (u32)evec, 1, _READABLE | _WRITABLE | _NONSECURE); smmu_map(pdir, EXCP_VEC_BASE, (u32)evec, 1, _READABLE | _WRITABLE | _NONSECURE);
} }
//Execute firmware. // Execute firmware.
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA; HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA;
TSEC(TSEC_STATUS) = 0; TSEC(TSEC_STATUS) = 0;
TSEC(TSEC_BOOTKEYVER) = 1; // HOS uses key version 1. TSEC(TSEC_BOOTKEYVER) = 1; // HOS uses key version 1.
@@ -254,7 +254,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
goto out_free; goto out_free;
} }
//Fetch result. // Fetch result.
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0; HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0;
u32 buf[4]; u32 buf[4];
buf[0] = SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB); buf[0] = SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB);
@@ -274,7 +274,7 @@ out_free:;
out:; out:;
//Disable clocks. // Disable clocks.
clock_disable_kfuse(); clock_disable_kfuse();
clock_disable_sor1(); clock_disable_sor1();
clock_disable_sor0(); clock_disable_sor0();

View File

@@ -27,6 +27,8 @@ typedef struct _tsec_ctxt_t
void *fw; void *fw;
u32 size; u32 size;
void *pkg1; void *pkg1;
u32 pkg11_off;
u32 secmon_base;
} tsec_ctxt_t; } tsec_ctxt_t;
typedef struct _tsec_key_data_t typedef struct _tsec_key_data_t

View File

@@ -1,7 +1,7 @@
/* /*
* BPMP-Lite Cache/MMU and Frequency driver for Tegra X1 * BPMP-Lite Cache/MMU and Frequency driver for Tegra X1
* *
* Copyright (c) 2019 CTCaer * Copyright (c) 2019-2020 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -22,56 +22,101 @@
#include "../../common/memory_map.h" #include "../../common/memory_map.h"
#include "../utils/util.h" #include "../utils/util.h"
#define BPMP_MMU_CACHE_LINE_SIZE 0x20
#define BPMP_CACHE_CONFIG 0x0 #define BPMP_CACHE_CONFIG 0x0
#define CFG_ENABLE (1 << 0) #define CFG_ENABLE_CACHE (1 << 0)
#define CFG_ENABLE_SKEW_ASSOC (1 << 1)
#define CFG_DISABLE_RANDOM_ALLOC (1 << 2)
#define CFG_FORCE_WRITE_THROUGH (1 << 3) #define CFG_FORCE_WRITE_THROUGH (1 << 3)
#define CFG_NEVER_ALLOCATE (1 << 6)
#define CFG_ENABLE_INTERRUPT (1 << 7)
#define CFG_MMU_TAG_MODE(x) (x << 8)
#define TAG_MODE_PARALLEL 0
#define TAG_MODE_TAG_FIRST 1
#define TAG_MODE_MMU_FIRST 2
#define CFG_DISABLE_WRITE_BUFFER (1 << 10) #define CFG_DISABLE_WRITE_BUFFER (1 << 10)
#define CFG_DISABLE_READ_BUFFER (1 << 11) #define CFG_DISABLE_READ_BUFFER (1 << 11)
#define CFG_ENABLE_HANG_DETECT (1 << 12)
#define CFG_FULL_LINE_DIRTY (1 << 13) #define CFG_FULL_LINE_DIRTY (1 << 13)
#define CFG_TAG_CHK_ABRT_ON_ERR (1 << 14) #define CFG_TAG_CHK_ABRT_ON_ERR (1 << 14)
#define CFG_TAG_CHK_CLR_ERR (1 << 15)
#define CFG_DISABLE_SAMELINE (1 << 16)
#define CFG_OBS_BUS_EN (1 << 31)
#define BPMP_CACHE_LOCK 0x4 #define BPMP_CACHE_LOCK 0x4
#define LOCK_LINE(x) (1 << x)
#define BPMP_CACHE_SIZE 0xC #define BPMP_CACHE_SIZE 0xC
#define BPMP_CACHE_LFSR 0x10 #define BPMP_CACHE_LFSR 0x10
#define BPMP_CACHE_TAG_STATUS 0x14 #define BPMP_CACHE_TAG_STATUS 0x14
#define TAG_STATUS_TAG_CHECK_ERROR (1 << 0)
#define TAG_STATUS_CONFLICT_ADDR_MASK 0xFFFFFFE0
#define BPMP_CACHE_CLKEN_OVERRIDE 0x18 #define BPMP_CACHE_CLKEN_OVERRIDE 0x18
#define CLKEN_OVERRIDE_WR_MCCIF_CLKEN (1 << 0)
#define CLKEN_OVERRIDE_RD_MCCIF_CLKEN (1 << 1)
#define BPMP_CACHE_MAINT_ADDR 0x20 #define BPMP_CACHE_MAINT_ADDR 0x20
#define BPMP_CACHE_MAINT_DATA 0x24 #define BPMP_CACHE_MAINT_DATA 0x24
#define BPMP_CACHE_MAINT_REQ 0x28 #define BPMP_CACHE_MAINT_REQ 0x28
#define MAINT_REQ_WAY_BITMAP(x) ((x) << 8) #define MAINT_REQ_WAY_BITMAP(x) ((x) << 8)
#define BPMP_CACHE_INT_MASK 0x40 #define BPMP_CACHE_INT_MASK 0x40
#define BPMP_CACHE_INT_CLEAR 0x44 #define BPMP_CACHE_INT_CLEAR 0x44
#define INT_CLR_MAINT_DONE (1 << 0)
#define BPMP_CACHE_INT_RAW_EVENT 0x48 #define BPMP_CACHE_INT_RAW_EVENT 0x48
#define INT_RAW_EVENT_MAINT_DONE (1 << 0)
#define BPMP_CACHE_INT_STATUS 0x4C #define BPMP_CACHE_INT_STATUS 0x4C
#define INT_MAINT_DONE (1 << 0)
#define INT_MAINT_ERROR (1 << 1)
#define BPMP_CACHE_RB_CFG 0x80 #define BPMP_CACHE_RB_CFG 0x80
#define BPMP_CACHE_WB_CFG 0x84 #define BPMP_CACHE_WB_CFG 0x84
#define BPMP_CACHE_MMU_FALLBACK_ENTRY 0xA0 #define BPMP_CACHE_MMU_FALLBACK_ENTRY 0xA0
#define BPMP_CACHE_MMU_SHADOW_COPY_MASK 0xA4 #define BPMP_CACHE_MMU_SHADOW_COPY_MASK 0xA4
#define BPMP_CACHE_MMU_CFG 0xAC #define BPMP_CACHE_MMU_CFG 0xAC
#define MMU_CFG_BLOCK_MAIN_ENTRY_WR (1 << 0)
#define MMU_CFG_SEQ_EN (1 << 1) #define MMU_CFG_SEQ_EN (1 << 1)
#define MMU_CFG_TLB_EN (1 << 2) #define MMU_CFG_TLB_EN (1 << 2)
#define MMU_CFG_SEG_CHECK_ALL_ENTRIES (1 << 3)
#define MMU_CFG_ABORT_STORE_LAST (1 << 4) #define MMU_CFG_ABORT_STORE_LAST (1 << 4)
#define MMU_CFG_CLR_ABORT (1 << 5)
#define BPMP_CACHE_MMU_CMD 0xB0 #define BPMP_CACHE_MMU_CMD 0xB0
#define MMU_CMD_NOP 0 #define MMU_CMD_NOP 0
#define MMU_CMD_INIT 1 #define MMU_CMD_INIT 1
#define MMU_CMD_COPY_SHADOW 2 #define MMU_CMD_COPY_SHADOW 2
#define BPMP_CACHE_MMU_ABORT_STAT 0xB4 #define BPMP_CACHE_MMU_ABORT_STAT 0xB4
#define ABORT_STAT_UNIT_MASK 0x7
#define ABORT_STAT_UNIT_NONE 0
#define ABORT_STAT_UNIT_CACHE 1
#define ABORT_STAT_UNIT_SEQ 2
#define ABORT_STAT_UNIT_TLB 3
#define ABORT_STAT_UNIT_SEG 4
#define ABORT_STAT_UNIT_FALLBACK 5
#define ABORT_STAT_OVERLAP (1 << 3)
#define ABORT_STAT_ENTRY (0x1F << 4)
#define ABORT_STAT_TYPE_MASK (3 << 16)
#define ABORT_STAT_TYPE_EXE (0 << 16)
#define ABORT_STAT_TYPE_RD (1 << 16)
#define ABORT_STAT_TYPE_WR (2 << 16)
#define ABORT_STAT_SIZE (3 << 18)
#define ABORT_STAT_SEQ (1 << 20)
#define ABORT_STAT_PROT (1 << 21)
#define BPMP_CACHE_MMU_ABORT_ADDR 0xB8 #define BPMP_CACHE_MMU_ABORT_ADDR 0xB8
#define BPMP_CACHE_MMU_ACTIVE_ENTRIES 0xBC #define BPMP_CACHE_MMU_ACTIVE_ENTRIES 0xBC
#define BPMP_MMU_SHADOW_ENTRY_BASE (BPMP_CACHE_BASE + 0x400) #define BPMP_MMU_SHADOW_ENTRY_BASE (BPMP_CACHE_BASE + 0x400)
#define BPMP_MMU_MAIN_ENTRY_BASE (BPMP_CACHE_BASE + 0x800) #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_CACHED (1 << 0) #define MMU_EN_READ (1 << 2)
#define MMU_EN_EXEC (1 << 1) #define MMU_EN_WRITE (1 << 3)
#define MMU_EN_READ (1 << 2)
#define MMU_EN_WRITE (1 << 3)
bpmp_mmu_entry_t mmu_entries[] = bpmp_mmu_entry_t mmu_entries[] =
{ {
@@ -81,15 +126,15 @@ bpmp_mmu_entry_t mmu_entries[] =
void bpmp_mmu_maintenance(u32 op, bool force) void bpmp_mmu_maintenance(u32 op, bool force)
{ {
if (!force && !(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE)) if (!force && !(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE))
return; return;
BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = INT_CLR_MAINT_DONE; BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = INT_MAINT_DONE;
// This is a blocking operation. // This is a blocking operation.
BPMP_CACHE_CTRL(BPMP_CACHE_MAINT_REQ) = MAINT_REQ_WAY_BITMAP(0xF) | op; 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)) while(!(BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT) & INT_MAINT_DONE))
; ;
BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT); BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT);
@@ -104,8 +149,8 @@ void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply)
if (entry->enable) if (entry->enable)
{ {
mmu_entry->min_addr = entry->min_addr & MMU_ENTRY_ADDR_MASK; mmu_entry->start_addr = ALIGN(entry->start_addr, BPMP_MMU_CACHE_LINE_SIZE);
mmu_entry->max_addr = entry->max_addr & MMU_ENTRY_ADDR_MASK; mmu_entry->end_addr = ALIGN_DOWN(entry->end_addr, BPMP_MMU_CACHE_LINE_SIZE);
mmu_entry->attr = entry->attr; mmu_entry->attr = entry->attr;
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_SHADOW_COPY_MASK) |= (1 << idx); BPMP_CACHE_CTRL(BPMP_CACHE_MMU_SHADOW_COPY_MASK) |= (1 << idx);
@@ -117,7 +162,7 @@ void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply)
void bpmp_mmu_enable() void bpmp_mmu_enable()
{ {
if (BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE) if (BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE)
return; return;
// Init BPMP MMU. // Init BPMP MMU.
@@ -136,7 +181,8 @@ void bpmp_mmu_enable()
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, true); bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, true);
// Enable cache. // Enable cache.
BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = CFG_ENABLE | CFG_FORCE_WRITE_THROUGH | CFG_TAG_CHK_ABRT_ON_ERR; BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = CFG_ENABLE_CACHE | CFG_FORCE_WRITE_THROUGH |
CFG_MMU_TAG_MODE(TAG_MODE_PARALLEL) | CFG_TAG_CHK_ABRT_ON_ERR;
// HW bug. Invalidate cache again. // HW bug. Invalidate cache again.
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false); bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false);
@@ -144,7 +190,7 @@ void bpmp_mmu_enable()
void bpmp_mmu_disable() void bpmp_mmu_disable()
{ {
if (!(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE)) if (!(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE))
return; return;
// Clean and invalidate cache. // Clean and invalidate cache.
@@ -154,7 +200,10 @@ void bpmp_mmu_disable()
BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = 0; BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = 0;
} }
const u8 pllc4_divn[] = { // APB clock affects RTC, PWM, MEMFETCH, APE, USB, SOR PWM,
// I2C host, DC/DSI/DISP. UART gives extra stress.
// 92: 100% success ratio. 93-94: 595-602MHz has 99% success ratio. 95: 608MHz less.
const u8 pll_divn[] = {
0, // BPMP_CLK_NORMAL: 408MHz 0% - 136MHz APB. 0, // BPMP_CLK_NORMAL: 408MHz 0% - 136MHz APB.
85, // BPMP_CLK_HIGH_BOOST: 544MHz 33% - 136MHz APB. 85, // BPMP_CLK_HIGH_BOOST: 544MHz 33% - 136MHz APB.
90, // BPMP_CLK_SUPER_BOOST: 576MHz 41% - 144MHz APB. 90, // BPMP_CLK_SUPER_BOOST: 576MHz 41% - 144MHz APB.
@@ -165,6 +214,28 @@ const u8 pllc4_divn[] = {
bpmp_freq_t bpmp_clock_set = BPMP_CLK_NORMAL; bpmp_freq_t bpmp_clock_set = BPMP_CLK_NORMAL;
void bpmp_clk_rate_get()
{
bool clk_src_is_pllp = ((CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) >> 4) & 7) == 3;
if (clk_src_is_pllp)
bpmp_clock_set = BPMP_CLK_NORMAL;
else
{
bpmp_clock_set = BPMP_CLK_HIGH_BOOST;
u8 pll_divn_curr = (CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) >> 10) & 0xFF;
for (u32 i = 1; i < sizeof(pll_divn); i++)
{
if (pll_divn[i] == pll_divn_curr)
{
bpmp_clock_set = i;
break;
}
}
}
}
void bpmp_clk_rate_set(bpmp_freq_t fid) void bpmp_clk_rate_set(bpmp_freq_t fid)
{ {
if (fid > (BPMP_CLK_MAX - 1)) if (fid > (BPMP_CLK_MAX - 1))
@@ -179,37 +250,26 @@ void bpmp_clk_rate_set(bpmp_freq_t fid)
{ {
// Restore to PLLP source during PLLC4 configuration. // Restore to PLLP source during PLLC4 configuration.
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // PLLP_OUT. CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // PLLP_OUT.
// Wait a bit for clock source change. msleep(1); // Wait a bit for clock source change.
msleep(10);
} }
CLOCK(CLK_RST_CONTROLLER_PLLC4_MISC) = PLLC4_MISC_EN_LCKDET; // Configure and enable PLLC.
CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) = 4 | (pllc4_divn[fid] << 8) | PLL_BASE_ENABLE; // DIVM: 4, DIVP: 1. clock_enable_pllc(pll_divn[fid]);
while (!(CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) & PLLC4_BASE_LOCK)) // Set SCLK / HCLK / PCLK.
; CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 3; // PCLK = HCLK / (3 + 1). HCLK == SCLK.
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003310; // PLLC_OUT1 for active and CLKM for idle.
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 else
{ {
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // PLLP_OUT. CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003330; // PLLP_OUT for active and CLKM for idle.
msleep(1); // Wait a bit for clock source change.
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // PCLK = HCLK / (2 + 1). HCLK == SCLK.
// Wait a bit for clock source change. // Disable PLLC to save power.
msleep(10); clock_disable_pllc();
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;
} }
bpmp_clock_set = fid;
} }
// The following functions halt BPMP to reduce power while sleeping. // The following functions halt BPMP to reduce power while sleeping.

View File

@@ -1,7 +1,7 @@
/* /*
* BPMP-Lite Cache/MMU and Frequency driver for Tegra X1 * BPMP-Lite Cache/MMU and Frequency driver for Tegra X1
* *
* Copyright (c) 2019 CTCaer * Copyright (c) 2019-2020 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -21,14 +21,24 @@
#include "../utils/types.h" #include "../utils/types.h"
#define BPMP_MMU_MAINT_CLEAN_WAY 17 typedef enum
#define BPMP_MMU_MAINT_INVALID_WAY 18 {
#define BPMP_MMU_MAINT_CLN_INV_WAY 19 BPMP_MMU_MAINT_NOP = 0,
BPMP_MMU_MAINT_CLEAN_PHY = 1,
BPMP_MMU_MAINT_INVALID_PHY = 2,
BPMP_MMU_MAINT_CLEAN_INVALID_PHY = 3,
BPMP_MMU_MAINT_CLEAN_LINE = 9,
BPMP_MMU_MAINT_INVALID_LINE = 10,
BPMP_MMU_MAINT_CLEAN_INVALID_LINE = 11,
BPMP_MMU_MAINT_CLEAN_WAY = 17,
BPMP_MMU_MAINT_INVALID_WAY = 18,
BPMP_MMU_MAINT_CLN_INV_WAY = 19
} bpmp_maintenance_t;
typedef struct _bpmp_mmu_entry_t typedef struct _bpmp_mmu_entry_t
{ {
u32 min_addr; u32 start_addr;
u32 max_addr; u32 end_addr;
u32 attr; u32 attr;
u32 enable; u32 enable;
} bpmp_mmu_entry_t; } bpmp_mmu_entry_t;
@@ -49,6 +59,7 @@ void bpmp_mmu_maintenance(u32 op, bool force);
void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply); void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply);
void bpmp_mmu_enable(); void bpmp_mmu_enable();
void bpmp_mmu_disable(); void bpmp_mmu_disable();
void bpmp_clk_rate_get();
void bpmp_clk_rate_set(bpmp_freq_t fid); void bpmp_clk_rate_set(bpmp_freq_t fid);
void bpmp_usleep(u32 us); void bpmp_usleep(u32 us);
void bpmp_msleep(u32 ms); void bpmp_msleep(u32 ms);

View File

@@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2020 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -19,6 +20,17 @@
#include "../utils/util.h" #include "../utils/util.h"
#include "../storage/sdmmc.h" #include "../storage/sdmmc.h"
/*
* CLOCK Peripherals:
* L 0 - 31
* H 32 - 63
* U 64 - 95
* V 96 - 127
* W 128 - 159
* X 160 - 191
* Y 192 - 223
*/
/* clock_t: reset, enable, source, index, clk_src, clk_div */ /* clock_t: reset, enable, source, index, clk_src, clk_div */
static const clock_t _clock_uart[] = { static const clock_t _clock_uart[] = {
@@ -29,7 +41,7 @@ static const clock_t _clock_uart[] = {
/* UART E */ { CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE, 20, 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 }
}; };
//I2C default parameters - TLOW: 4, THIGH: 2, DEBOUNCE: 0 FM_DIV: 26. //I2C default parameters - TLOW: 4, THIGH: 2, DEBOUNCE: 0, FM_DIV: 26.
static const clock_t _clock_i2c[] = { 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, 12, 0, 19 }, //20.4MHz -> 100KHz /* I2C1 */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, 12, 0, 19 }, //20.4MHz -> 100KHz
/* I2C2 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C2, 22, 0, 4 }, //81.6MHz -> 400KHz /* I2C2 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C2, 22, 0, 4 }, //81.6MHz -> 400KHz
@@ -77,6 +89,10 @@ static clock_t _clock_pwm = {
CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, 17, 6, 4 // Fref: 6.2MHz. CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, 17, 6, 4 // Fref: 6.2MHz.
}; };
static clock_t _clock_sdmmc_legacy_tm = {
CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM, 1, 4, 66
};
void clock_enable(const clock_t *clk) void clock_enable(const clock_t *clk)
{ {
// Put clock into reset. // Put clock into reset.
@@ -112,6 +128,29 @@ void clock_enable_uart(u32 idx)
clock_enable(&_clock_uart[idx]); clock_enable(&_clock_uart[idx]);
} }
void clock_disable_uart(u32 idx)
{
clock_disable(&_clock_uart[idx]);
}
#define UART_SRC_CLK_DIV_EN (1 << 24)
int clock_uart_use_src_div(u32 idx, u32 baud)
{
u32 clk_src_div = CLOCK(_clock_uart[idx].source) & 0xE0000000;
if (baud == 1000000)
CLOCK(_clock_uart[idx].source) = clk_src_div | UART_SRC_CLK_DIV_EN | 49;
else
{
CLOCK(_clock_uart[idx].source) = clk_src_div | 2;
return 1;
}
return 0;
}
void clock_enable_i2c(u32 idx) void clock_enable_i2c(u32 idx)
{ {
clock_enable(&_clock_i2c[idx]); clock_enable(&_clock_i2c[idx]);
@@ -228,6 +267,51 @@ void clock_disable_pwm()
clock_disable(&_clock_pwm); clock_disable(&_clock_pwm);
} }
void clock_enable_pllc(u32 divn)
{
u8 pll_divn_curr = (CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) >> 10) & 0xFF;
// Check if already enabled and configured.
if ((CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) & PLLCX_BASE_ENABLE) && (pll_divn_curr == divn))
return;
// Take PLLC out of reset and set basic misc parameters.
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) =
((CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) & 0xFFF0000F) & ~PLLC_MISC_RESET) | (0x80000 << 4); // PLLC_EXT_FRU.
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_2) |= 0xF0 << 8; // PLLC_FLL_LD_MEM.
// Disable PLL and IDDQ in case they are on.
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) &= ~PLLCX_BASE_ENABLE;
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_1) &= ~PLLC_MISC1_IDDQ;
usleep(10);
// Set PLLC dividers.
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) = (divn << 10) | 4; // DIVM: 4, DIVP: 1.
// Enable PLLC and wait for Phase and Frequency lock.
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) |= PLLCX_BASE_ENABLE;
while (!(CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) & PLLCX_BASE_LOCK))
;
// Disable PLLC_OUT1, enable reset and set div to 1.5.
CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) = (1 << 8);
// Enable PLLC_OUT1 and bring it out of reset.
CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) |= (PLLC_OUT1_CLKEN | PLLC_OUT1_RSTN_CLR);
msleep(1); // Wait a bit for PLL to stabilize.
}
void clock_disable_pllc()
{
// Disable PLLC and PLLC_OUT1.
CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) &= ~(PLLC_OUT1_CLKEN | PLLC_OUT1_RSTN_CLR);
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) &= ~PLLCX_BASE_ENABLE;
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) |= PLLCX_BASE_REF_DIS;
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_1) |= PLLC_MISC1_IDDQ;
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) |= PLLC_MISC_RESET;
usleep(10);
}
#define L_SWR_SDMMC1_RST (1 << 14) #define L_SWR_SDMMC1_RST (1 << 14)
#define L_SWR_SDMMC2_RST (1 << 9) #define L_SWR_SDMMC2_RST (1 << 9)
#define L_SWR_SDMMC4_RST (1 << 15) #define L_SWR_SDMMC4_RST (1 << 15)
@@ -366,56 +450,78 @@ static void _clock_sdmmc_clear_enable(u32 id)
} }
} }
static u32 _clock_sdmmc_table[8] = { 0 }; static void _clock_sdmmc_config_legacy_tm()
{
clock_t *clk = &_clock_sdmmc_legacy_tm;
if (!(CLOCK(clk->enable) & (1 << clk->index)))
clock_enable(clk);
}
#define PLLP_OUT0 0x0 typedef struct _clock_sdmmc_t
static int _clock_sdmmc_config_clock_host(u32 *pout, u32 id, u32 val) {
u32 clock;
u32 real_clock;
} clock_sdmmc_t;
static clock_sdmmc_t _clock_sdmmc_table[4] = { 0 };
#define SDMMC_CLOCK_SRC_PLLP_OUT0 0x0
#define SDMMC_CLOCK_SRC_PLLC4_OUT2 0x3
#define SDMMC4_CLOCK_SRC_PLLC4_OUT2_LJ 0x1
static int _clock_sdmmc_config_clock_host(u32 *pclock, u32 id, u32 val)
{ {
u32 divisor = 0; u32 divisor = 0;
u32 source = PLLP_OUT0; u32 source = SDMMC_CLOCK_SRC_PLLP_OUT0;
if (id > SDMMC_4)
return 0;
// Get IO clock divisor. // Get IO clock divisor.
switch (val) switch (val)
{ {
case 25000: case 25000:
*pout = 24728; *pclock = 24728;
divisor = 31; // 16.5 div. divisor = 31; // 16.5 div.
break; break;
case 26000: case 26000:
*pout = 25500; *pclock = 25500;
divisor = 30; // 16 div. divisor = 30; // 16 div.
break; break;
case 40800: case 40800:
*pout = 40800; *pclock = 40800;
divisor = 18; // 10 div. divisor = 18; // 10 div.
break; break;
case 50000: case 50000:
*pout = 48000; *pclock = 48000;
divisor = 15; // 8.5 div. divisor = 15; // 8.5 div.
break; break;
case 52000: case 52000:
*pout = 51000; *pclock = 51000;
divisor = 14; // 8 div. divisor = 14; // 8 div.
break; break;
case 100000: case 100000:
*pout = 90667; *pclock = 90667;
divisor = 7; // 4.5 div. divisor = 7; // 4.5 div.
break; break;
case 200000: case 164000:
*pout = 163200; *pclock = 163200;
divisor = 3; // 2.5 div. divisor = 3; // 2.5 div.
break; break;
case 208000: case 200000:
*pout = 204000; *pclock = 204000;
divisor = 2; // 2 div. divisor = 2; // 2 div.
break; break;
default: default:
*pout = 24728; *pclock = 24728;
divisor = 31; // 16.5 div. divisor = 31; // 16.5 div.
} }
_clock_sdmmc_table[2 * id] = val; _clock_sdmmc_table[id].clock = val;
_clock_sdmmc_table[2 * id + 1] = *pout; _clock_sdmmc_table[id].real_clock = *pclock;
// Set SDMMC legacy timeout clock.
_clock_sdmmc_config_legacy_tm();
// Set SDMMC clock. // Set SDMMC clock.
switch (id) switch (id)
@@ -437,70 +543,75 @@ static int _clock_sdmmc_config_clock_host(u32 *pout, u32 id, u32 val)
return 1; return 1;
} }
void clock_sdmmc_config_clock_source(u32 *pout, u32 id, u32 val) void clock_sdmmc_config_clock_source(u32 *pclock, u32 id, u32 val)
{ {
if (_clock_sdmmc_table[2 * id] == val) if (_clock_sdmmc_table[id].clock == val)
{ {
*pout = _clock_sdmmc_table[2 * id + 1]; *pclock = _clock_sdmmc_table[id].real_clock;
} }
else else
{ {
int is_enabled = _clock_sdmmc_is_enabled(id); int is_enabled = _clock_sdmmc_is_enabled(id);
if (is_enabled) if (is_enabled)
_clock_sdmmc_clear_enable(id); _clock_sdmmc_clear_enable(id);
_clock_sdmmc_config_clock_host(pout, id, val); _clock_sdmmc_config_clock_host(pclock, id, val);
if (is_enabled) if (is_enabled)
_clock_sdmmc_set_enable(id); _clock_sdmmc_set_enable(id);
_clock_sdmmc_is_reset(id); _clock_sdmmc_is_reset(id);
} }
} }
void clock_sdmmc_get_card_clock_div(u32 *pout, u16 *pdivisor, u32 type) void clock_sdmmc_get_card_clock_div(u32 *pclock, u16 *pdivisor, u32 type)
{ {
// Get Card clock divisor. // Get Card clock divisor.
switch (type) switch (type)
{ {
case 0: case SDHCI_TIMING_MMC_ID: // Actual IO Freq: 380.59 KHz.
*pout = 26000; *pclock = 26000;
*pdivisor = 66; *pdivisor = 66;
break; break;
case 1: case SDHCI_TIMING_MMC_LS26:
*pout = 26000; *pclock = 26000;
*pdivisor = 1; *pdivisor = 1;
break; break;
case 2: case SDHCI_TIMING_MMC_HS52:
*pout = 52000; *pclock = 52000;
*pdivisor = 1; *pdivisor = 1;
break; break;
case 3: case SDHCI_TIMING_MMC_HS200:
case 4: case SDHCI_TIMING_MMC_HS400:
case 11: case SDHCI_TIMING_UHS_SDR104:
*pout = 200000; *pclock = 200000;
*pdivisor = 1; *pdivisor = 1;
break; break;
case 5: case SDHCI_TIMING_SD_ID: // Actual IO Freq: 380.43 KHz.
*pout = 25000; *pclock = 25000;
*pdivisor = 64; *pdivisor = 64;
break; break;
case 6: case SDHCI_TIMING_SD_DS12:
case 8: case SDHCI_TIMING_UHS_SDR12:
*pout = 25000; *pclock = 25000;
*pdivisor = 1; *pdivisor = 1;
break; break;
case 7: case SDHCI_TIMING_SD_HS25:
*pout = 50000; case SDHCI_TIMING_UHS_SDR25:
*pclock = 50000;
*pdivisor = 1; *pdivisor = 1;
break; break;
case 10: case SDHCI_TIMING_UHS_SDR50:
*pout = 100000; *pclock = 100000;
*pdivisor = 1; *pdivisor = 1;
break; break;
case 13: case SDHCI_TIMING_UHS_SDR82:
*pout = 40800; *pclock = 164000;
*pdivisor = 1; *pdivisor = 1;
break; break;
case 14: case SDHCI_TIMING_UHS_DDR50:
*pout = 200000; *pclock = 40800;
*pdivisor = 1;
break;
case SDHCI_TIMING_MMC_DDR52: // Actual IO Freq: 49.92 MHz.
*pclock = 200000;
*pdivisor = 2; *pdivisor = 2;
break; break;
} }
@@ -513,15 +624,15 @@ int clock_sdmmc_is_not_reset_and_enabled(u32 id)
void clock_sdmmc_enable(u32 id, u32 val) void clock_sdmmc_enable(u32 id, u32 val)
{ {
u32 div = 0; u32 clock = 0;
if (_clock_sdmmc_is_enabled(id)) if (_clock_sdmmc_is_enabled(id))
_clock_sdmmc_clear_enable(id); _clock_sdmmc_clear_enable(id);
_clock_sdmmc_set_reset(id); _clock_sdmmc_set_reset(id);
_clock_sdmmc_config_clock_host(&div, id, val); _clock_sdmmc_config_clock_host(&clock, id, val);
_clock_sdmmc_set_enable(id); _clock_sdmmc_set_enable(id);
_clock_sdmmc_is_reset(id); _clock_sdmmc_is_reset(id);
usleep((100000 + div - 1) / div); usleep((100000 + clock - 1) / clock);
_clock_sdmmc_clear_reset(id); _clock_sdmmc_clear_reset(id);
_clock_sdmmc_is_reset(id); _clock_sdmmc_is_reset(id);
} }

View File

@@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2020 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -35,11 +36,19 @@
#define CLK_RST_CONTROLLER_MISC_CLK_ENB 0x48 #define CLK_RST_CONTROLLER_MISC_CLK_ENB 0x48
#define CLK_RST_CONTROLLER_OSC_CTRL 0x50 #define CLK_RST_CONTROLLER_OSC_CTRL 0x50
#define CLK_RST_CONTROLLER_PLLC_BASE 0x80 #define CLK_RST_CONTROLLER_PLLC_BASE 0x80
#define CLK_RST_CONTROLLER_PLLC_OUT 0x84
#define CLK_RST_CONTROLLER_PLLC_MISC 0x88 #define CLK_RST_CONTROLLER_PLLC_MISC 0x88
#define CLK_RST_CONTROLLER_PLLC_MISC_1 0x8C
#define CLK_RST_CONTROLLER_PLLM_BASE 0x90 #define CLK_RST_CONTROLLER_PLLM_BASE 0x90
#define CLK_RST_CONTROLLER_PLLM_MISC1 0x98 #define CLK_RST_CONTROLLER_PLLM_MISC1 0x98
#define CLK_RST_CONTROLLER_PLLM_MISC2 0x9C #define CLK_RST_CONTROLLER_PLLM_MISC2 0x9C
#define CLK_RST_CONTROLLER_PLLP_BASE 0xA0 #define CLK_RST_CONTROLLER_PLLP_BASE 0xA0
#define CLK_RST_CONTROLLER_PLLA_BASE 0xB0
#define CLK_RST_CONTROLLER_PLLA_OUT 0xB4
#define CLK_RST_CONTROLLER_PLLA_MISC1 0xB8
#define CLK_RST_CONTROLLER_PLLA_MISC 0xBC
#define CLK_RST_CONTROLLER_PLLU_BASE 0xC0
#define CLK_RST_CONTROLLER_PLLU_MISC 0xCC
#define CLK_RST_CONTROLLER_PLLD_BASE 0xD0 #define CLK_RST_CONTROLLER_PLLD_BASE 0xD0
#define CLK_RST_CONTROLLER_PLLD_MISC1 0xD8 #define CLK_RST_CONTROLLER_PLLD_MISC1 0xD8
#define CLK_RST_CONTROLLER_PLLD_MISC 0xDC #define CLK_RST_CONTROLLER_PLLD_MISC 0xDC
@@ -49,6 +58,7 @@
#define CLK_RST_CONTROLLER_PLLE_MISC 0xEC #define CLK_RST_CONTROLLER_PLLE_MISC 0xEC
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA 0xF8 #define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA 0xF8
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB 0xFC #define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB 0xFC
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2S2 0x100
#define CLK_RST_CONTROLLER_CLK_SOURCE_PWM 0x110 #define CLK_RST_CONTROLLER_CLK_SOURCE_PWM 0x110
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C1 0x124 #define CLK_RST_CONTROLLER_CLK_SOURCE_I2C1 0x124
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C5 0x128 #define CLK_RST_CONTROLLER_CLK_SOURCE_I2C5 0x128
@@ -67,6 +77,7 @@
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3 0x1BC #define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3 0x1BC
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTD 0x1C0 #define CLK_RST_CONTROLLER_CLK_SOURCE_UARTD 0x1C0
#define CLK_RST_CONTROLLER_CLK_SOURCE_CSITE 0x1D4 #define CLK_RST_CONTROLLER_CLK_SOURCE_CSITE 0x1D4
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2S1 0x1D8
#define CLK_RST_CONTROLLER_CLK_SOURCE_TSEC 0x1F4 #define CLK_RST_CONTROLLER_CLK_SOURCE_TSEC 0x1F4
#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X 0x280 #define CLK_RST_CONTROLLER_CLK_OUT_ENB_X 0x280
#define CLK_RST_CONTROLLER_CLK_ENB_X_SET 0x284 #define CLK_RST_CONTROLLER_CLK_ENB_X_SET 0x284
@@ -101,24 +112,32 @@
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD 0x3A4 #define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD 0x3A4
#define CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT 0x3B4 #define CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT 0x3B4
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C4 0x3C4 #define CLK_RST_CONTROLLER_CLK_SOURCE_I2C4 0x3C4
#define CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH1 0x3EC
#define CLK_RST_CONTROLLER_CLK_SOURCE_SYS 0x400 #define CLK_RST_CONTROLLER_CLK_SOURCE_SYS 0x400
#define CLK_RST_CONTROLLER_CLK_SOURCE_SOR1 0x410 #define CLK_RST_CONTROLLER_CLK_SOURCE_SOR1 0x410
#define CLK_RST_CONTROLLER_CLK_SOURCE_SE 0x42C #define CLK_RST_CONTROLLER_CLK_SOURCE_SE 0x42C
#define CLK_RST_CONTROLLER_RST_DEV_V_SET 0x430
#define CLK_RST_CONTROLLER_RST_DEV_V_CLR 0x434 #define CLK_RST_CONTROLLER_RST_DEV_V_CLR 0x434
#define CLK_RST_CONTROLLER_RST_DEV_W_SET 0x438
#define CLK_RST_CONTROLLER_RST_DEV_W_CLR 0x43C
#define CLK_RST_CONTROLLER_CLK_ENB_V_SET 0x440 #define CLK_RST_CONTROLLER_CLK_ENB_V_SET 0x440
#define CLK_RST_CONTROLLER_CLK_ENB_V_CLR 0x444 #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_SET 0x448
#define CLK_RST_CONTROLLER_CLK_ENB_W_CLR 0x44C #define CLK_RST_CONTROLLER_CLK_ENB_W_CLR 0x44C
#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET 0x450 #define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET 0x450
#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR 0x454 #define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR 0x454
#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG0 0x480
#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG1 0x484
#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG2 0x488 #define CLK_RST_CONTROLLER_UTMIP_PLL_CFG2 0x488
#define CLK_RST_CONTROLLER_PLLE_AUX 0x48C #define CLK_RST_CONTROLLER_PLLE_AUX 0x48C
#define CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S0 0x4A0 #define CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S0 0x4A0
#define CLK_RST_CONTROLLER_PLLX_MISC_3 0x518 #define CLK_RST_CONTROLLER_PLLX_MISC_3 0x518
#define CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0 0x52C
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE 0x554 #define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE 0x554
#define CLK_RST_CONTROLLER_SPARE_REG0 0x55C #define CLK_RST_CONTROLLER_SPARE_REG0 0x55C
#define CLK_RST_CONTROLLER_PLLC4_BASE 0x5A4 #define CLK_RST_CONTROLLER_PLLC4_BASE 0x5A4
#define CLK_RST_CONTROLLER_PLLC4_MISC 0x5A8 #define CLK_RST_CONTROLLER_PLLC4_MISC 0x5A8
#define CLK_RST_CONTROLLER_PLLC_MISC_2 0x5D0
#define CLK_RST_CONTROLLER_PLLC4_OUT 0x5E4 #define CLK_RST_CONTROLLER_PLLC4_OUT 0x5E4
#define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8 #define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8
#define CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP 0x620 #define CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP 0x620
@@ -127,16 +146,27 @@
#define CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_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_SDMMC_LEGACY_TM 0x694
#define CLK_RST_CONTROLLER_CLK_SOURCE_NVENC 0x6A0 #define CLK_RST_CONTROLLER_CLK_SOURCE_NVENC 0x6A0
#define CLK_RST_CONTROLLER_CLK_SOURCE_USB2_HSIC_TRK 0x6CC
#define CLK_RST_CONTROLLER_SE_SUPER_CLK_DIVIDER 0x704 #define CLK_RST_CONTROLLER_SE_SUPER_CLK_DIVIDER 0x704
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE 0x710 #define CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE 0x710
#define CLK_NO_SOURCE 0x0 #define CLK_NO_SOURCE 0x0
/*! PLL control and status bits */ /*! PLL control and status bits */
#define PLL_BASE_ENABLE (1 << 30) #define PLLCX_BASE_ENABLE (1 << 30)
#define PLLCX_BASE_REF_DIS (1 << 29)
#define PLLCX_BASE_LOCK (1 << 27)
#define PLLA_BASE_IDDQ (1 << 25)
#define PLLA_OUT0_CLKEN (1 << 1)
#define PLLA_OUT0_RSTN_CLR (1 << 0)
#define PLLC_MISC_RESET (1 << 30)
#define PLLC_MISC1_IDDQ (1 << 27)
#define PLLC_OUT1_CLKEN (1 << 1)
#define PLLC_OUT1_RSTN_CLR (1 << 0)
#define PLLC4_MISC_EN_LCKDET (1 << 30) #define PLLC4_MISC_EN_LCKDET (1 << 30)
#define PLLC4_BASE_LOCK (1 << 27)
#define PLLC4_BASE_IDDQ (1 << 18) #define PLLC4_BASE_IDDQ (1 << 18)
#define PLLC4_OUT3_CLKEN (1 << 1) #define PLLC4_OUT3_CLKEN (1 << 1)
#define PLLC4_OUT3_RSTN_CLR (1 << 0) #define PLLC4_OUT3_RSTN_CLR (1 << 0)
@@ -159,6 +189,8 @@ void clock_disable(const clock_t *clk);
/*! Clock control for specific hardware portions. */ /*! Clock control for specific hardware portions. */
void clock_enable_fuse(bool enable); void clock_enable_fuse(bool enable);
void clock_enable_uart(u32 idx); void clock_enable_uart(u32 idx);
void clock_disable_uart(u32 idx);
int clock_uart_use_src_div(u32 idx, u32 baud);
void clock_enable_i2c(u32 idx); void clock_enable_i2c(u32 idx);
void clock_disable_i2c(u32 idx); void clock_disable_i2c(u32 idx);
void clock_enable_se(); void clock_enable_se();
@@ -181,9 +213,11 @@ void clock_enable_coresight();
void clock_disable_coresight(); void clock_disable_coresight();
void clock_enable_pwm(); void clock_enable_pwm();
void clock_disable_pwm(); void clock_disable_pwm();
void clock_sdmmc_config_clock_source(u32 *pout, u32 id, u32 val); void clock_enable_pllc(u32 divn);
void clock_sdmmc_get_card_clock_div(u32 *pout, u16 *pdivisor, u32 type); void clock_disable_pllc();
int clock_sdmmc_is_not_reset_and_enabled(u32 id); void clock_sdmmc_config_clock_source(u32 *pclock, u32 id, u32 val);
void clock_sdmmc_get_card_clock_div(u32 *pclock, u16 *pdivisor, u32 type);
int clock_sdmmc_is_not_reset_and_enabled(u32 id);
void clock_sdmmc_enable(u32 id, u32 val); void clock_sdmmc_enable(u32 id, u32 val);
void clock_sdmmc_disable(u32 id); void clock_sdmmc_disable(u32 id);

View File

@@ -54,6 +54,7 @@
#define FUSE_PRIVATE_KEY3 0x1B0 #define FUSE_PRIVATE_KEY3 0x1B0
#define FUSE_PRIVATE_KEY4 0x1B4 #define FUSE_PRIVATE_KEY4 0x1B4
#define FUSE_RESERVED_SW 0x1C0 #define FUSE_RESERVED_SW 0x1C0
#define FUSE_USB_CALIB 0x1F0
#define FUSE_SKU_DIRECT_CONFIG 0x1F4 #define FUSE_SKU_DIRECT_CONFIG 0x1F4
#define FUSE_OPT_VENDOR_CODE 0x200 #define FUSE_OPT_VENDOR_CODE 0x200
#define FUSE_OPT_FAB_CODE 0x204 #define FUSE_OPT_FAB_CODE 0x204
@@ -63,6 +64,7 @@
#define FUSE_OPT_X_COORDINATE 0x214 #define FUSE_OPT_X_COORDINATE 0x214
#define FUSE_OPT_Y_COORDINATE 0x218 #define FUSE_OPT_Y_COORDINATE 0x218
#define FUSE_GPU_IDDQ_CALIB 0x228 #define FUSE_GPU_IDDQ_CALIB 0x228
#define FUSE_USB_CALIB_EXT 0x350
/*! Fuse commands. */ /*! Fuse commands. */
#define FUSE_READ 0x1 #define FUSE_READ 0x1

View File

@@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2019 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -14,81 +15,146 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "../soc/gpio.h" #include "gpio.h"
#include "../soc/t210.h" #include "irq.h"
#include "t210.h"
static const u16 _gpio_cnf[31] = { #define GPIO_BANK_IDX(port) (port >> 2)
0x000, 0x004, 0x008, 0x00C,
0x100, 0x104, 0x108, 0x10C,
0x200, 0x204, 0x208, 0x20C,
0x300, 0x304, 0x308, 0x30C,
0x400, 0x404, 0x408, 0x40C,
0x500, 0x504, 0x508, 0x50C,
0x600, 0x604, 0x608, 0x60C,
0x700, 0x704, 0x708
};
static const u16 _gpio_oe[31] = { #define GPIO_CNF_OFFSET(port) (0x00 + ((port >> 2) << 8) + ((port % 4) << 2))
0x010, 0x014, 0x018, 0x01C, #define GPIO_OE_OFFSET(port) (0x10 + ((port >> 2) << 8) + ((port % 4) << 2))
0x110, 0x114, 0x118, 0x11C, #define GPIO_OUT_OFFSET(port) (0x20 + ((port >> 2) << 8) + ((port % 4) << 2))
0x210, 0x214, 0x218, 0x21C, #define GPIO_IN_OFFSET(port) (0x30 + ((port >> 2) << 8) + ((port % 4) << 2))
0x310, 0x314, 0x318, 0x31C, #define GPIO_INT_STA_OFFSET(port) (0x40 + ((port >> 2) << 8) + ((port % 4) << 2))
0x410, 0x414, 0x418, 0x41C, #define GPIO_INT_ENB_OFFSET(port) (0x50 + ((port >> 2) << 8) + ((port % 4) << 2))
0x510, 0x514, 0x518, 0x51C, #define GPIO_INT_LVL_OFFSET(port) (0x60 + ((port >> 2) << 8) + ((port % 4) << 2))
0x610, 0x614, 0x618, 0x61C, #define GPIO_INT_CLR_OFFSET(port) (0x70 + ((port >> 2) << 8) + ((port % 4) << 2))
0x710, 0x714, 0x718
};
static const u16 _gpio_out[31] = { #define GPIO_CNF_MASKED_OFFSET(port) (0x80 + ((port >> 2) << 8) + ((port % 4) << 2))
0x020, 0x024, 0x028, 0x02C, #define GPIO_OE_MASKED_OFFSET(port) (0x90 + ((port >> 2) << 8) + ((port % 4) << 2))
0x120, 0x124, 0x128, 0x12C, #define GPIO_OUT_MASKED_OFFSET(port) (0xA0 + ((port >> 2) << 8) + ((port % 4) << 2))
0x220, 0x224, 0x228, 0x22C, #define GPIO_INT_STA_MASKED_OFFSET(port) (0xC0 + ((port >> 2) << 8) + ((port % 4) << 2))
0x320, 0x324, 0x328, 0x32C, #define GPIO_INT_ENB_MASKED_OFFSET(port) (0xD0 + ((port >> 2) << 8) + ((port % 4) << 2))
0x420, 0x424, 0x428, 0x42C, #define GPIO_INT_LVL_MASKED_OFFSET(port) (0xE0 + ((port >> 2) << 8) + ((port % 4) << 2))
0x520, 0x524, 0x528, 0x52C,
0x620, 0x624, 0x628, 0x62C,
0x720, 0x724, 0x728
};
static const u16 _gpio_in[31] = { static u8 gpio_bank_irq_ids[8] = {
0x030, 0x034, 0x038, 0x03C, IRQ_GPIO1, IRQ_GPIO2, IRQ_GPIO3, IRQ_GPIO4,
0x130, 0x134, 0x138, 0x13C, IRQ_GPIO5, IRQ_GPIO6, IRQ_GPIO7, IRQ_GPIO8
0x230, 0x234, 0x238, 0x23C,
0x330, 0x334, 0x338, 0x33C,
0x430, 0x434, 0x438, 0x43C,
0x530, 0x534, 0x538, 0x53C,
0x630, 0x634, 0x638, 0x63C,
0x730, 0x734, 0x738
}; };
void gpio_config(u32 port, u32 pins, int mode) void gpio_config(u32 port, u32 pins, int mode)
{ {
u32 offset = GPIO_CNF_OFFSET(port);
if (mode) if (mode)
GPIO(_gpio_cnf[port]) |= pins; GPIO(offset) |= pins;
else else
GPIO(_gpio_cnf[port]) &= ~pins; GPIO(offset) &= ~pins;
(void)GPIO(_gpio_cnf[port]);
(void)GPIO(offset); // Commit the write.
} }
void gpio_output_enable(u32 port, u32 pins, int enable) void gpio_output_enable(u32 port, u32 pins, int enable)
{ {
u32 port_offset = GPIO_OE_OFFSET(port);
if (enable) if (enable)
GPIO(_gpio_oe[port]) |= pins; GPIO(port_offset) |= pins;
else else
GPIO(_gpio_oe[port]) &= ~pins; GPIO(port_offset) &= ~pins;
(void)GPIO(_gpio_oe[port]);
(void)GPIO(port_offset); // Commit the write.
} }
void gpio_write(u32 port, u32 pins, int high) void gpio_write(u32 port, u32 pins, int high)
{ {
u32 port_offset = GPIO_OUT_OFFSET(port);
if (high) if (high)
GPIO(_gpio_out[port]) |= pins; GPIO(port_offset) |= pins;
else else
GPIO(_gpio_out[port]) &= ~pins; GPIO(port_offset) &= ~pins;
(void)GPIO(_gpio_out[port]);
(void)GPIO(port_offset); // Commit the write.
} }
int gpio_read(u32 port, u32 pins) int gpio_read(u32 port, u32 pins)
{ {
return (GPIO(_gpio_in[port]) & pins) ? 1 : 0; u32 port_offset = GPIO_IN_OFFSET(port);
return (GPIO(port_offset) & pins) ? 1 : 0;
}
static void _gpio_interrupt_clear(u32 port, u32 pins)
{
u32 port_offset = GPIO_INT_CLR_OFFSET(port);
GPIO(port_offset) |= pins;
(void)GPIO(port_offset); // Commit the write.
}
int gpio_interrupt_status(u32 port, u32 pins)
{
u32 port_offset = GPIO_INT_STA_OFFSET(port);
u32 enabled = GPIO(GPIO_INT_ENB_OFFSET(port)) & pins;
int status = ((GPIO(port_offset) & pins) && enabled) ? 1 : 0;
// Clear the interrupt status.
if (status)
_gpio_interrupt_clear(port, pins);
return status;
}
void gpio_interrupt_enable(u32 port, u32 pins, int enable)
{
u32 port_offset = GPIO_INT_ENB_OFFSET(port);
// Clear any possible stray interrupt.
_gpio_interrupt_clear(port, pins);
if (enable)
GPIO(port_offset) |= pins;
else
GPIO(port_offset) &= ~pins;
(void)GPIO(port_offset); // Commit the write.
}
void gpio_interrupt_level(u32 port, u32 pins, int high, int edge, int delta)
{
u32 port_offset = GPIO_INT_LVL_OFFSET(port);
u32 val = GPIO(port_offset);
if (high)
val |= pins;
else
val &= ~pins;
if (edge)
val |= pins << 8;
else
val &= ~(pins << 8);
if (delta)
val |= pins << 16;
else
val &= ~(pins << 16);
GPIO(port_offset) = val;
(void)GPIO(port_offset); // Commit the write.
// Clear any possible stray interrupt.
_gpio_interrupt_clear(port, pins);
}
u32 gpio_get_bank_irq_id(u32 port)
{
u32 bank_idx = GPIO_BANK_IDX(port);
return gpio_bank_irq_ids[bank_idx];
} }

View File

@@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2019 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -21,10 +22,23 @@
#define GPIO_MODE_SPIO 0 #define GPIO_MODE_SPIO 0
#define GPIO_MODE_GPIO 1 #define GPIO_MODE_GPIO 1
#define GPIO_OUTPUT_DISABLE 0 #define GPIO_OUTPUT_DISABLE 0
#define GPIO_OUTPUT_ENABLE 1 #define GPIO_OUTPUT_ENABLE 1
#define GPIO_IRQ_DISABLE 0
#define GPIO_IRQ_ENABLE 1
#define GPIO_LOW 0 #define GPIO_LOW 0
#define GPIO_HIGH 1 #define GPIO_HIGH 1
#define GPIO_FALLING 0
#define GPIO_RISING 1
#define GPIO_LEVEL 0
#define GPIO_EDGE 1
#define GPIO_CONFIGURED_EDGE 0
#define GPIO_ANY_EDGE_CHANGE 1
/*! GPIO pins (0-7 for each port). */ /*! GPIO pins (0-7 for each port). */
#define GPIO_PIN_0 (1 << 0) #define GPIO_PIN_0 (1 << 0)
@@ -72,6 +86,10 @@
void gpio_config(u32 port, u32 pins, int mode); void gpio_config(u32 port, u32 pins, int mode);
void gpio_output_enable(u32 port, u32 pins, int enable); void gpio_output_enable(u32 port, u32 pins, int enable);
void gpio_write(u32 port, u32 pins, int high); void gpio_write(u32 port, u32 pins, int high);
int gpio_read(u32 port, u32 pins); int gpio_read(u32 port, u32 pins);
int gpio_interrupt_status(u32 port, u32 pins);
void gpio_interrupt_enable(u32 port, u32 pins, int enable);
void gpio_interrupt_level(u32 port, u32 pins, int high, int edge, int delta);
u32 gpio_get_bank_irq_id(u32 port);
#endif #endif

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2019 CTCaer * Copyright (c) 2018-2020 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -26,6 +26,7 @@
#include "pinmux.h" #include "pinmux.h"
#include "pmc.h" #include "pmc.h"
#include "t210.h" #include "t210.h"
#include "uart.h"
#include "../gfx/di.h" #include "../gfx/di.h"
#include "../mem/mc.h" #include "../mem/mc.h"
#include "../mem/minerva.h" #include "../mem/minerva.h"
@@ -34,11 +35,12 @@
#include "../power/max7762x.h" #include "../power/max7762x.h"
#include "../sec/se.h" #include "../sec/se.h"
#include "../sec/se_t210.h" #include "../sec/se_t210.h"
#include "../storage/nx_sd.h"
#include "../storage/sdmmc.h" #include "../storage/sdmmc.h"
#include "../utils/util.h" #include "../utils/util.h"
extern sdmmc_t sd_sdmmc;
extern boot_cfg_t b_cfg; extern boot_cfg_t b_cfg;
extern volatile nyx_storage_t *nyx_str;
/* /*
* CLK_OSC - 38.4 MHz crystal. * CLK_OSC - 38.4 MHz crystal.
@@ -78,8 +80,8 @@ void _config_gpios()
PINMUX_AUX(PINMUX_AUX_UART3_TX) = 0; PINMUX_AUX(PINMUX_AUX_UART3_TX) = 0;
// Set Joy-Con IsAttached direction. // Set Joy-Con IsAttached direction.
PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE; PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;
PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE; PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;
// Set pin mode for Joy-Con IsAttached and UARTB/C TX pins. // Set pin mode for Joy-Con IsAttached and UARTB/C TX pins.
#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_B #if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_B
@@ -100,7 +102,7 @@ void _config_gpios()
pinmux_config_i2c(I2C_1); pinmux_config_i2c(I2C_1);
pinmux_config_i2c(I2C_5); pinmux_config_i2c(I2C_5);
pinmux_config_uart(0); pinmux_config_uart(UART_A);
// Configure volume up/down as inputs. // Configure volume up/down as inputs.
gpio_config(GPIO_PORT_X, GPIO_PIN_6, GPIO_MODE_GPIO); gpio_config(GPIO_PORT_X, GPIO_PIN_6, GPIO_MODE_GPIO);
@@ -109,7 +111,7 @@ void _config_gpios()
gpio_output_enable(GPIO_PORT_X, GPIO_PIN_7, GPIO_OUTPUT_DISABLE); gpio_output_enable(GPIO_PORT_X, GPIO_PIN_7, GPIO_OUTPUT_DISABLE);
// Configure HOME as inputs. // Configure HOME as inputs.
// PINMUX_AUX(PINMUX_AUX_BUTTON_HOME) = PINMUX_PULL_UP | PINMUX_INPUT_ENABLE; // PINMUX_AUX(PINMUX_AUX_BUTTON_HOME) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;
// gpio_config(GPIO_PORT_Y, GPIO_PIN_1, GPIO_MODE_GPIO); // gpio_config(GPIO_PORT_Y, GPIO_PIN_1, GPIO_MODE_GPIO);
} }
@@ -160,7 +162,7 @@ void _mbist_workaround()
// Enable specific clocks and disable all others. // 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_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) = 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_L) = 0x80400130; // Keep USBD 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_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_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_W) = 0x402000FC; // Enable clock PCIERX0, PCIERX1, PCIERX2, PCIERX3, PCIERX4, PCIERX5, ENTROPY, MC1.
@@ -184,6 +186,9 @@ void _mbist_workaround()
void _config_se_brom() void _config_se_brom()
{ {
// Enable fuse clock.
clock_enable_fuse(true);
// Skip SBK/SSK if sept was run. // Skip SBK/SSK if sept was run.
if (!(b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN)) if (!(b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN))
{ {
@@ -217,10 +222,19 @@ void _config_se_brom()
void _config_regulators() void _config_regulators()
{ {
// Disable low battery shutdown monitor.
max77620_low_battery_monitor_config(false);
// Disable SDMMC1 IO power.
gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_DISABLE);
max77620_regulator_enable(REGULATOR_LDO2, 0);
sd_power_cycle_time_start = get_tmr_ms();
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_CNFGBBC, MAX77620_CNFGBBC_RESISTOR_1K);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1,
(1 << 6) | (3 << MAX77620_ONOFFCNFG1_MRT_SHIFT)); // PWR delay for forced shutdown off. (1 << 6) | (3 << MAX77620_ONOFFCNFG1_MRT_SHIFT)); // PWR delay for forced shutdown off.
// Configure all Flexible Power Sequencers.
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG0, i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG0,
(7 << MAX77620_FPS_TIME_PERIOD_SHIFT)); (7 << MAX77620_FPS_TIME_PERIOD_SHIFT));
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG1, i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG1,
@@ -236,10 +250,10 @@ void _config_regulators()
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_GPIO3, 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+ (4 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (2 << MAX77620_FPS_PD_PERIOD_SHIFT)); // 3.x+
// Set vdd_core voltage to 1.125V // Set vdd_core voltage to 1.125V.
max77620_regulator_set_voltage(REGULATOR_SD0, 1125000); max77620_regulator_set_voltage(REGULATOR_SD0, 1125000);
// Fix CPU/GPU after a Linux warmboot. // Fix CPU/GPU after a L4T warmboot.
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, 2); 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, MAX77620_I2C_ADDR, MAX77620_REG_GPIO6, 2);
@@ -256,9 +270,6 @@ void _config_regulators()
i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL2_REG, 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_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS |
MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL); MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL);
// Enable low battery shutdown monitor for < 2800mV.
max77620_low_battery_monitor_config();
} }
void config_hw() void config_hw()
@@ -284,6 +295,11 @@ void config_hw()
APB_MISC(APB_MISC_PP_PINMUX_GLOBAL) = 0; APB_MISC(APB_MISC_PP_PINMUX_GLOBAL) = 0;
_config_gpios(); _config_gpios();
#ifdef DEBUG_UART_PORT
clock_enable_uart(DEBUG_UART_PORT);
uart_init(DEBUG_UART_PORT, 115200);
#endif
clock_enable_cl_dvfs(); clock_enable_cl_dvfs();
clock_enable_i2c(I2C_1); clock_enable_i2c(I2C_1);
@@ -303,7 +319,9 @@ void config_hw()
sdram_init(); sdram_init();
bpmp_mmu_enable(); bpmp_mmu_enable();
mc_enable_ahb_redirect();
// Clear flags from PMC_SCRATCH0
PMC(APBDEV_PMC_SCRATCH0) &= ~PMC_SCRATCH0_MODE_PAYLOAD;
} }
void reconfig_hw_workaround(bool extra_reconfig, u32 magic) void reconfig_hw_workaround(bool extra_reconfig, u32 magic)
@@ -312,10 +330,11 @@ void reconfig_hw_workaround(bool extra_reconfig, u32 magic)
bpmp_mmu_disable(); bpmp_mmu_disable();
bpmp_clk_rate_set(BPMP_CLK_NORMAL); bpmp_clk_rate_set(BPMP_CLK_NORMAL);
minerva_change_freq(FREQ_204); minerva_change_freq(FREQ_204);
nyx_str->mtc_cfg.init_done = 0;
// Re-enable clocks to Audio Processing Engine as a workaround to hanging. // 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_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.
if (extra_reconfig) if (extra_reconfig)
{ {
@@ -338,7 +357,7 @@ void reconfig_hw_workaround(bool extra_reconfig, u32 magic)
if (magic == 0xBAADF00D) if (magic == 0xBAADF00D)
{ {
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) |= (1 << 22); CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) |= (1 << 22);
sdmmc_init(&sd_sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, 5, 0); sdmmc_init(&sd_sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_SD_ID, 0);
clock_disable_cl_dvfs(); clock_disable_cl_dvfs();
msleep(200); msleep(200);

View File

@@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2020 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -19,7 +20,7 @@
#include "i2c.h" #include "i2c.h"
#include "../utils/util.h" #include "../utils/util.h"
static u32 i2c_addrs[] = { static const u32 i2c_addrs[] = {
0x7000C000, 0x7000C400, 0x7000C500, 0x7000C000, 0x7000C400, 0x7000C500,
0x7000C700, 0x7000D000, 0x7000D100 0x7000C700, 0x7000D000, 0x7000D100
}; };
@@ -37,21 +38,39 @@ static void _i2c_wait(vu32 *base)
static int _i2c_send_pkt(u32 idx, u32 x, u8 *buf, u32 size) static int _i2c_send_pkt(u32 idx, u32 x, u8 *buf, u32 size)
{ {
if (size > 4) if (size > 8)
return 0; return 0;
u32 tmp = 0; u32 tmp = 0;
memcpy(&tmp, buf, size);
vu32 *base = (vu32 *)i2c_addrs[idx]; vu32 *base = (vu32 *)i2c_addrs[idx];
base[I2C_CMD_ADDR0] = x << 1; //Set x (send mode). base[I2C_CMD_ADDR0] = x << 1; //Set x (send mode).
base[I2C_CMD_DATA1] = tmp; //Set value.
if (size > 4)
{
memcpy(&tmp, buf, 4);
base[I2C_CMD_DATA1] = tmp; //Set value.
tmp = 0;
memcpy(&tmp, buf + 4, size - 4);
base[I2C_CMD_DATA2] = tmp;
}
else
{
memcpy(&tmp, buf, size);
base[I2C_CMD_DATA1] = tmp; //Set value.
}
base[I2C_CNFG] = ((size - 1) << 1) | 0x2800; //Set size and send mode. base[I2C_CNFG] = ((size - 1) << 1) | 0x2800; //Set size and send mode.
_i2c_wait(base); //Kick transaction. _i2c_wait(base); //Kick transaction.
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200; base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200;
u32 timeout = get_tmr_ms() + 1500;
while (base[I2C_STATUS] & 0x100) while (base[I2C_STATUS] & 0x100)
; {
if (get_tmr_ms() > timeout)
return 0;
}
if (base[I2C_STATUS] << 28) if (base[I2C_STATUS] << 28)
return 0; return 0;
@@ -70,8 +89,13 @@ static int _i2c_recv_pkt(u32 idx, u8 *buf, u32 size, u32 x)
_i2c_wait(base); // Kick transaction. _i2c_wait(base); // Kick transaction.
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200; base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200;
u32 timeout = get_tmr_ms() + 1500;
while (base[I2C_STATUS] & 0x100) while (base[I2C_STATUS] & 0x100)
; {
if (get_tmr_ms() > timeout)
return 0;
}
if (base[I2C_STATUS] << 28) if (base[I2C_STATUS] << 28)
return 0; return 0;
@@ -112,7 +136,7 @@ int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size)
{ {
u8 tmp[4]; u8 tmp[4];
if (size > 3) if (size > 7)
return 0; return 0;
tmp[0] = y; tmp[0] = y;
@@ -121,6 +145,11 @@ int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size)
return _i2c_send_pkt(idx, x, tmp, size + 1); return _i2c_send_pkt(idx, x, tmp, size + 1);
} }
int i2c_recv_buf(u8 *buf, u32 size, u32 idx, u32 x)
{
return _i2c_recv_pkt(idx, buf, size, x);
}
int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y) int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y)
{ {
int res = _i2c_send_pkt(idx, x, (u8 *)&y, 1); int res = _i2c_send_pkt(idx, x, (u8 *)&y, 1);

View File

@@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2020 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -39,6 +40,7 @@
void i2c_init(u32 idx); void i2c_init(u32 idx);
int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size); int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size);
int i2c_recv_buf(u8 *buf, u32 size, u32 idx, u32 x);
int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y); int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y);
int i2c_send_byte(u32 idx, u32 x, u32 y, u8 b); int i2c_send_byte(u32 idx, u32 x, u32 y, u8 b);
u8 i2c_recv_byte(u32 idx, u32 x, u32 y); u8 i2c_recv_byte(u32 idx, u32 x, u32 y);

263
source/soc/irq.c Normal file
View File

@@ -0,0 +1,263 @@
/*
* BPMP-Lite IRQ 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 <string.h>
#include "irq.h"
#include "t210.h"
#include "../gfx/gfx.h"
#include "../mem/heap.h"
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
#define DPRINTF(...)
extern void irq_disable();
extern void irq_enable_cpu_irq_exceptions();
extern void irq_disable_cpu_irq_exceptions();
typedef struct _irq_ctxt_t
{
u32 irq;
int (*handler)(u32 irq, void *data);
void *data;
u32 flags;
} irq_ctxt_t;
bool irq_init_done = false;
irq_ctxt_t irqs[IRQ_MAX_HANDLERS];
static void _irq_enable_source(u32 irq)
{
u32 ctrl_idx = irq >> 5;
u32 bit = irq % 32;
// Set as normal IRQ.
ICTLR(ctrl_idx, PRI_ICTLR_COP_IEP_CLASS) &= ~(1 << bit);
// Enable IRQ source.
ICTLR(ctrl_idx, PRI_ICTLR_COP_IER_SET) = 1 << bit;
}
static void _irq_disable_source(u32 irq)
{
u32 ctrl_idx = irq >> 5;
u32 bit = irq % 32;
// Disable IRQ source.
ICTLR(ctrl_idx, PRI_ICTLR_COP_IER_CLR) = 1 << bit;
}
static void _irq_disable_and_ack_all()
{
// Disable and ack all IRQ sources.
for (u32 ctrl_idx = 0; ctrl_idx < 6; ctrl_idx++)
{
u32 enabled_irqs = ICTLR(ctrl_idx, PRI_ICTLR_COP_IER);
ICTLR(ctrl_idx, PRI_ICTLR_COP_IER_CLR) = enabled_irqs;
ICTLR(ctrl_idx, PRI_ICTLR_FIR_CLR) = enabled_irqs;
}
}
static void _irq_ack_source(u32 irq)
{
u32 ctrl_idx = irq >> 5;
u32 bit = irq % 32;
// Force stop the interrupt as it's serviced here.
ICTLR(ctrl_idx, PRI_ICTLR_FIR_CLR) = 1 << bit;
}
void irq_free(u32 irq)
{
for (u32 idx = 0; idx < IRQ_MAX_HANDLERS; idx++)
{
if (irqs[idx].irq == irq && irqs[idx].handler)
{
irqs[idx].irq = 0;
irqs[idx].handler = NULL;
irqs[idx].data = NULL;
irqs[idx].flags = 0;
_irq_disable_source(irq);
}
}
}
static void _irq_free_all()
{
for (u32 idx = 0; idx < IRQ_MAX_HANDLERS; idx++)
{
if (irqs[idx].handler)
{
_irq_disable_source(irqs[idx].irq);
irqs[idx].irq = 0;
irqs[idx].handler = NULL;
irqs[idx].data = NULL;
irqs[idx].flags = 0;
}
}
}
static irq_status_t _irq_handle_source(u32 irq)
{
int status = IRQ_NONE;
_irq_disable_source(irq);
_irq_ack_source(irq);
u32 idx;
for (idx = 0; idx < IRQ_MAX_HANDLERS; idx++)
{
if (irqs[idx].irq == irq)
{
status = irqs[idx].handler(irqs[idx].irq, irqs[idx].data);
if (status == IRQ_HANDLED)
break;
}
}
if (irqs[idx].flags & IRQ_FLAG_ONE_OFF)
irq_free(irq);
else
_irq_enable_source(irq);
return status;
}
void irq_handler()
{
// Get IRQ source.
u32 irq = EXCP_VEC(EVP_COP_IRQ_STS) & 0xFF;
if (!irq_init_done)
{
_irq_ack_source(irq);
return;
}
DPRINTF("IRQ: %d\n", irq);
int err = _irq_handle_source(irq);
//TODO: disable if unhandhled.
if (err == IRQ_NONE)
gfx_printf("Unhandled IRQ: %d\n", irq);
}
static void _irq_init()
{
_irq_disable_and_ack_all();
memset(irqs, 0, sizeof(irq_ctxt_t) * IRQ_MAX_HANDLERS);
irq_init_done = true;
}
void irq_end()
{
_irq_free_all();
irq_disable_cpu_irq_exceptions();
irq_init_done = false;
}
void irq_wait_event(u32 irq)
{
irq_disable_cpu_irq_exceptions();
_irq_enable_source(irq);
// Halt BPMP and wait for the IRQ. No need to use WAIT_EVENT + LIC_IRQ when BPMP serves the IRQ.
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_STOP_UNTIL_IRQ;
_irq_disable_source(irq);
_irq_ack_source(irq);
irq_enable_cpu_irq_exceptions();
}
void irq_disable_wait_event()
{
irq_enable_cpu_irq_exceptions();
}
irq_status_t irq_request(u32 irq, irq_handler_t handler, void *data, irq_flags_t flags)
{
if (!irq_init_done)
_irq_init();
for (u32 idx = 0; idx < IRQ_MAX_HANDLERS; idx++)
{
if (irqs[idx].handler == NULL ||
(irqs[idx].irq == irq && irqs[idx].flags & IRQ_FLAG_REPLACEABLE))
{
DPRINTF("Registered handler, IRQ: %d, Slot: %d\n", irq, idx);
DPRINTF("Handler: %08p, Flags: %x\n", (u32)handler, flags);
irqs[idx].irq = irq;
irqs[idx].handler = handler;
irqs[idx].data = data;
irqs[idx].flags = flags;
_irq_enable_source(irq);
return IRQ_ENABLED;
}
else if (irqs[idx].irq == irq)
return IRQ_ALREADY_REGISTERED;
}
return IRQ_NO_SLOTS_AVAILABLE;
}
void __attribute__ ((target("arm"))) fiq_setup()
{
/*
asm volatile("mrs r12, cpsr\n\t"
"bic r12, r12, #0x1F\n\t"
"orr r12, r12, #0x11\n\t"
"msr cpsr_c, r12\n\t");
register volatile char *text asm ("r8");
register volatile char *uart_tx asm ("r9");
register int len asm ("r10");
len = 5;
uart_tx = (char *)0x70006040;
memcpy((char *)text, "FIQ\r\n", len);
*uart_tx = 0;
asm volatile("mrs r12, cpsr\n"
"orr r12, r12, #0x1F\n"
"msr cpsr_c, r12");
*/
}
void __attribute__ ((target("arm"), interrupt ("FIQ"))) fiq_handler()
{
/*
register volatile char *text asm ("r8");
register volatile char *uart_tx asm ("r9");
register int len asm ("r10");
while (len)
{
*uart_tx = *text++;
len--;
}
*/
}

222
source/soc/irq.h Normal file
View File

@@ -0,0 +1,222 @@
/*
* BPMP-Lite IRQ 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 IRQ_H
#define IRQ_H
#include "../utils/types.h"
#define IRQ_MAX_HANDLERS 16
/* Primary interrupt controller ids */
#define IRQ_TMR1 0
#define IRQ_TMR2 1
#define IRQ_RTC 2
#define IRQ_CEC 3
#define IRQ_SHR_SEM_INBOX_FULL 4
#define IRQ_SHR_SEM_INBOX_EMPTY 5
#define IRQ_SHR_SEM_OUTBOX_FULL 6
#define IRQ_SHR_SEM_OUTBOX_EMPTY 7
#define IRQ_NVJPEG 8
#define IRQ_NVDEC 9
#define IRQ_QUAD_SPI 10
#define IRQ_DPAUX_INT1 11
#define IRQ_SATA_RX_STAT 13
#define IRQ_SDMMC1 14
#define IRQ_SDMMC2 15
#define IRQ_VGPIO_INT 16
#define IRQ_VII2C_INT 17
#define IRQ_SDMMC3 19
#define IRQ_USB 20
#define IRQ_USB2 21
#define IRQ_SATA_CTL 23
#define IRQ_PMC_INT 24
#define IRQ_FC_INT 25
#define IRQ_APB_DMA_CPU 26
#define IRQ_ARB_SEM_GNT_COP 28
#define IRQ_ARB_SEM_GNT_CPU 29
#define IRQ_SDMMC4 31
/* Secondary interrupt controller ids */
#define IRQ_GPIO1 32
#define IRQ_GPIO2 33
#define IRQ_GPIO3 34
#define IRQ_GPIO4 35
#define IRQ_UARTA 36
#define IRQ_UARTB 37
#define IRQ_I2C 38
#define IRQ_USB3_HOST_INT 39
#define IRQ_USB3_HOST_SMI 40
#define IRQ_TMR3 41
#define IRQ_TMR4 42
#define IRQ_USB3_HOST_PME 43
#define IRQ_USB3_DEV_HOST 44
#define IRQ_ACTMON 45
#define IRQ_UARTC 46
#define IRQ_THERMAL 48
#define IRQ_XUSB_PADCTL 49
#define IRQ_TSEC 50
#define IRQ_EDP 51
#define IRQ_I2C5 53
#define IRQ_GPIO5 55
#define IRQ_USB3_DEV_SMI 56
#define IRQ_USB3_DEV_PME 57
#define IRQ_SE 58
#define IRQ_SPI1 59
#define IRQ_APB_DMA_COP 60
#define IRQ_CLDVFS 62
#define IRQ_I2C6 63
/* Tertiary interrupt controller ids */
#define IRQ_HOST1X_SYNCPT_COP 64
#define IRQ_HOST1X_SYNCPT_CPU 65
#define IRQ_HOST1X_GEN_COP 66
#define IRQ_HOST1X_GEN_CPU 67
#define IRQ_NVENC 68
#define IRQ_VI 69
#define IRQ_ISPB 70
#define IRQ_ISP 71
#define IRQ_VIC 72
#define IRQ_DISPLAY 73
#define IRQ_DISPLAYB 74
#define IRQ_SOR1 75
#define IRQ_SOR 76
#define IRQ_MC 77
#define IRQ_EMC 78
#define IRQ_TSECB 80
#define IRQ_HDA 81
#define IRQ_SPI2 82
#define IRQ_SPI3 83
#define IRQ_I2C2 84
#define IRQ_PMU_EXT 86
#define IRQ_GPIO6 87
#define IRQ_GPIO7 89
#define IRQ_UARTD 90
#define IRQ_I2C3 92
#define IRQ_SPI4 93
/* Quaternary interrupt controller ids */
#define IRQ_DTV 96
#define IRQ_PCIE_INT 98
#define IRQ_PCIE_MSI 99
#define IRQ_AVP_CACHE 101
#define IRQ_APE_INT1 102
#define IRQ_APE_INT0 103
#define IRQ_APB_DMA_CH0 104
#define IRQ_APB_DMA_CH1 105
#define IRQ_APB_DMA_CH2 106
#define IRQ_APB_DMA_CH3 107
#define IRQ_APB_DMA_CH4 108
#define IRQ_APB_DMA_CH5 109
#define IRQ_APB_DMA_CH6 110
#define IRQ_APB_DMA_CH7 111
#define IRQ_APB_DMA_CH8 112
#define IRQ_APB_DMA_CH9 113
#define IRQ_APB_DMA_CH10 114
#define IRQ_APB_DMA_CH11 115
#define IRQ_APB_DMA_CH12 116
#define IRQ_APB_DMA_CH13 117
#define IRQ_APB_DMA_CH14 118
#define IRQ_APB_DMA_CH15 119
#define IRQ_I2C4 120
#define IRQ_TMR5 121
#define IRQ_WDT_CPU 123
#define IRQ_WDT_AVP 124
#define IRQ_GPIO8 125
#define IRQ_CAR 126
/* Quinary interrupt controller ids */
#define IRQ_APB_DMA_CH16 128
#define IRQ_APB_DMA_CH17 129
#define IRQ_APB_DMA_CH18 130
#define IRQ_APB_DMA_CH19 131
#define IRQ_APB_DMA_CH20 132
#define IRQ_APB_DMA_CH21 133
#define IRQ_APB_DMA_CH22 134
#define IRQ_APB_DMA_CH23 135
#define IRQ_APB_DMA_CH24 136
#define IRQ_APB_DMA_CH25 137
#define IRQ_APB_DMA_CH26 138
#define IRQ_APB_DMA_CH27 139
#define IRQ_APB_DMA_CH28 140
#define IRQ_APB_DMA_CH29 141
#define IRQ_APB_DMA_CH30 142
#define IRQ_APB_DMA_CH31 143
#define IRQ_CPU0_PMU_INTR 144
#define IRQ_CPU1_PMU_INTR 145
#define IRQ_CPU2_PMU_INTR 146
#define IRQ_CPU3_PMU_INTR 147
#define IRQ_SDMMC1_SYS 148
#define IRQ_SDMMC2_SYS 149
#define IRQ_SDMMC3_SYS 150
#define IRQ_SDMMC4_SYS 151
#define IRQ_TMR6 152
#define IRQ_TMR7 153
#define IRQ_TMR8 154
#define IRQ_TMR9 155
#define IRQ_TMR0 156
#define IRQ_GPU_STALL 157
#define IRQ_GPU_NONSTALL 158
#define IRQ_DPAUX 159
/* Senary interrupt controller ids */
#define IRQ_MPCORE_AXIERRIRQ 160
#define IRQ_MPCORE_INTERRIRQ 161
#define IRQ_EVENT_GPIO_A 162
#define IRQ_EVENT_GPIO_B 163
#define IRQ_EVENT_GPIO_C 164
#define IRQ_FLOW_RSM_CPU 168
#define IRQ_FLOW_RSM_COP 169
#define IRQ_TMR_SHARED 170
#define IRQ_MPCORE_CTIIRQ0 171
#define IRQ_MPCORE_CTIIRQ1 172
#define IRQ_MPCORE_CTIIRQ2 173
#define IRQ_MPCORE_CTIIRQ3 174
#define IRQ_MSELECT_ERROR 175
#define IRQ_TMR10 176
#define IRQ_TMR11 177
#define IRQ_TMR12 178
#define IRQ_TMR13 179
typedef int (*irq_handler_t)(u32 irq, void *data);
typedef enum _irq_status_t
{
IRQ_NONE = 0,
IRQ_HANDLED = 1,
IRQ_ERROR = 2,
IRQ_ENABLED = 0,
IRQ_NO_SLOTS_AVAILABLE = 1,
IRQ_ALREADY_REGISTERED = 2
} irq_status_t;
typedef enum _irq_flags_t
{
IRQ_FLAG_NONE = 0,
IRQ_FLAG_ONE_OFF = (1 << 0),
IRQ_FLAG_REPLACEABLE = (1 << 1)
} irq_flags_t;
void irq_end();
void irq_free(u32 irq);
void irq_wait_event();
void irq_disable_wait_event();
irq_status_t irq_request(u32 irq, irq_handler_t handler, void *data, irq_flags_t flags);
#endif

View File

@@ -62,6 +62,7 @@
#define PINMUX_AUX_LCD_BL_PWM 0x1FC #define PINMUX_AUX_LCD_BL_PWM 0x1FC
#define PINMUX_AUX_LCD_BL_EN 0x200 #define PINMUX_AUX_LCD_BL_EN 0x200
#define PINMUX_AUX_LCD_RST 0x204 #define PINMUX_AUX_LCD_RST 0x204
#define PINMUX_AUX_LCD_GPIO1 0x208
#define PINMUX_AUX_LCD_GPIO2 0x20C #define PINMUX_AUX_LCD_GPIO2 0x20C
#define PINMUX_AUX_TOUCH_INT 0x220 #define PINMUX_AUX_TOUCH_INT 0x220
#define PINMUX_AUX_MOTION_INT 0x224 #define PINMUX_AUX_MOTION_INT 0x224

View File

@@ -25,13 +25,23 @@
#define APBDEV_PMC_PWRGATE_TOGGLE 0x30 #define APBDEV_PMC_PWRGATE_TOGGLE 0x30
#define APBDEV_PMC_PWRGATE_STATUS 0x38 #define APBDEV_PMC_PWRGATE_STATUS 0x38
#define APBDEV_PMC_NO_IOPOWER 0x44 #define APBDEV_PMC_NO_IOPOWER 0x44
#define PMC_NO_IOPOWER_GPIO_IO_EN (1 << 21)
#define PMC_NO_IOPOWER_AUDIO_HV (1 << 18)
#define PMC_NO_IOPOWER_SDMMC1_IO_EN (1 << 12) #define PMC_NO_IOPOWER_SDMMC1_IO_EN (1 << 12)
#define APBDEV_PMC_SCRATCH0 0x50 #define APBDEV_PMC_SCRATCH0 0x50
#define PMC_SCRATCH0_MODE_RECOVERY (1 << 31)
#define PMC_SCRATCH0_MODE_FASTBOOT (1 << 30)
#define PMC_SCRATCH0_MODE_PAYLOAD (1 << 29)
#define PMC_SCRATCH0_MODE_RCM (1 << 1)
#define PMC_SCRATCH0_MODE_WARMBOOT (1 << 0)
#define APBDEV_PMC_SCRATCH1 0x54 #define APBDEV_PMC_SCRATCH1 0x54
#define APBDEV_PMC_SCRATCH20 0xA0 #define APBDEV_PMC_SCRATCH20 0xA0
#define APBDEV_PMC_PWR_DET_VAL 0xE4 #define APBDEV_PMC_PWR_DET_VAL 0xE4
#define PMC_PWR_DET_GPIO_IO_EN (1 << 21)
#define PMC_PWR_DET_AUDIO_HV (1 << 18)
#define PMC_PWR_DET_SDMMC1_IO_EN (1 << 12) #define PMC_PWR_DET_SDMMC1_IO_EN (1 << 12)
#define APBDEV_PMC_DDR_PWR 0xE8 #define APBDEV_PMC_DDR_PWR 0xE8
#define APBDEV_PMC_USB_AO 0xF0
#define APBDEV_PMC_CRYPTO_OP 0xF4 #define APBDEV_PMC_CRYPTO_OP 0xF4
#define PMC_CRYPTO_OP_SE_ENABLE 0 #define PMC_CRYPTO_OP_SE_ENABLE 0
#define PMC_CRYPTO_OP_SE_DISABLE 1 #define PMC_CRYPTO_OP_SE_DISABLE 1
@@ -39,6 +49,8 @@
#define APBDEV_PMC_SCRATCH40 0x13C #define APBDEV_PMC_SCRATCH40 0x13C
#define APBDEV_PMC_OSC_EDPD_OVER 0x1A4 #define APBDEV_PMC_OSC_EDPD_OVER 0x1A4
#define PMC_OSC_EDPD_OVER_OSC_CTRL_OVER 0x400000 #define PMC_OSC_EDPD_OVER_OSC_CTRL_OVER 0x400000
#define APBDEV_PMC_CLK_OUT_CNTRL 0x1A8
#define PMC_CLK_OUT_CNTRL_CLK1_FORCE_EN (1 << 2)
#define APBDEV_PMC_RST_STATUS 0x1B4 #define APBDEV_PMC_RST_STATUS 0x1B4
#define APBDEV_PMC_IO_DPD_REQ 0x1B8 #define APBDEV_PMC_IO_DPD_REQ 0x1B8
#define APBDEV_PMC_IO_DPD2_REQ 0x1C0 #define APBDEV_PMC_IO_DPD2_REQ 0x1C0

View File

@@ -28,9 +28,11 @@
#define VIC_BASE 0x54340000 #define VIC_BASE 0x54340000
#define TSEC_BASE 0x54500000 #define TSEC_BASE 0x54500000
#define SOR1_BASE 0x54580000 #define SOR1_BASE 0x54580000
#define ICTLR_BASE 0x60004000
#define TMR_BASE 0x60005000 #define TMR_BASE 0x60005000
#define CLOCK_BASE 0x60006000 #define CLOCK_BASE 0x60006000
#define FLOW_CTLR_BASE 0x60007000 #define FLOW_CTLR_BASE 0x60007000
#define AHBDMA_BASE 0x60008000
#define SYSREG_BASE 0x6000C000 #define SYSREG_BASE 0x6000C000
#define SB_BASE (SYSREG_BASE + 0x200) #define SB_BASE (SYSREG_BASE + 0x200)
#define GPIO_BASE 0x6000D000 #define GPIO_BASE 0x6000D000
@@ -44,6 +46,7 @@
#define GPIO_8_BASE (GPIO_BASE + 0x700) #define GPIO_8_BASE (GPIO_BASE + 0x700)
#define EXCP_VEC_BASE 0x6000F000 #define EXCP_VEC_BASE 0x6000F000
#define IPATCH_BASE 0x6001DC00 #define IPATCH_BASE 0x6001DC00
#define APBDMA_BASE 0x60020000
#define APB_MISC_BASE 0x70000000 #define APB_MISC_BASE 0x70000000
#define PINMUX_AUX_BASE 0x70003000 #define PINMUX_AUX_BASE 0x70003000
#define UART_BASE 0x70006000 #define UART_BASE 0x70006000
@@ -56,10 +59,16 @@
#define SE_BASE 0x70012000 #define SE_BASE 0x70012000
#define MC_BASE 0x70019000 #define MC_BASE 0x70019000
#define EMC_BASE 0x7001B000 #define EMC_BASE 0x7001B000
#define EMC0_BASE 0x7001E000
#define EMC1_BASE 0x7001F000
#define MIPI_CAL_BASE 0x700E3000 #define MIPI_CAL_BASE 0x700E3000
#define CL_DVFS_BASE 0x70110000 #define CL_DVFS_BASE 0x70110000
#define I2S_BASE 0x702D1000 #define I2S_BASE 0x702D1000
#define ADMA_BASE 0x702E2000
#define TZRAM_BASE 0x7C010000 #define TZRAM_BASE 0x7C010000
#define USB_BASE 0x7D000000
#define USB_OTG_BASE USB_BASE
#define USB1_BASE 0x7D004000
#define _REG(base, off) *(vu32 *)((base) + (off)) #define _REG(base, off) *(vu32 *)((base) + (off))
@@ -70,10 +79,12 @@
#define VIC(off) _REG(VIC_BASE, off) #define VIC(off) _REG(VIC_BASE, off)
#define TSEC(off) _REG(TSEC_BASE, off) #define TSEC(off) _REG(TSEC_BASE, off)
#define SOR1(off) _REG(SOR1_BASE, off) #define SOR1(off) _REG(SOR1_BASE, off)
#define ICTLR(cidx, off) _REG(ICTLR_BASE + (0x100 * cidx), off)
#define TMR(off) _REG(TMR_BASE, off) #define TMR(off) _REG(TMR_BASE, off)
#define CLOCK(off) _REG(CLOCK_BASE, off) #define CLOCK(off) _REG(CLOCK_BASE, off)
#define FLOW_CTLR(off) _REG(FLOW_CTLR_BASE, off) #define FLOW_CTLR(off) _REG(FLOW_CTLR_BASE, off)
#define SYSREG(off) _REG(SYSREG_BASE, off) #define SYSREG(off) _REG(SYSREG_BASE, off)
#define AHB_GIZMO(off) _REG(SYSREG_BASE, off)
#define SB(off) _REG(SB_BASE, off) #define SB(off) _REG(SB_BASE, off)
#define GPIO(off) _REG(GPIO_BASE, off) #define GPIO(off) _REG(GPIO_BASE, off)
#define GPIO_1(off) _REG(GPIO_1_BASE, off) #define GPIO_1(off) _REG(GPIO_1_BASE, off)
@@ -96,9 +107,14 @@
#define SE(off) _REG(SE_BASE, off) #define SE(off) _REG(SE_BASE, off)
#define MC(off) _REG(MC_BASE, off) #define MC(off) _REG(MC_BASE, off)
#define EMC(off) _REG(EMC_BASE, off) #define EMC(off) _REG(EMC_BASE, off)
#define EMC_CH0(off) _REG(EMC0_BASE, off)
#define EMC_CH1(off) _REG(EMC1_BASE, off)
#define MIPI_CAL(off) _REG(MIPI_CAL_BASE, off) #define MIPI_CAL(off) _REG(MIPI_CAL_BASE, off)
#define I2S(off) _REG(I2S_BASE, off)
#define CL_DVFS(off) _REG(CL_DVFS_BASE, off) #define CL_DVFS(off) _REG(CL_DVFS_BASE, off)
#define I2S(off) _REG(I2S_BASE, off)
#define ADMA(off) _REG(ADMA_BASE, off)
#define USB(off) _REG(USB_BASE, off)
#define USB1(off) _REG(USB1_BASE, off)
#define TEST_REG(off) _REG(0x0, off) #define TEST_REG(off) _REG(0x0, off)
/* HOST1X registers. */ /* HOST1X registers. */
@@ -116,13 +132,40 @@
#define EVP_COP_RSVD_VECTOR 0x214 #define EVP_COP_RSVD_VECTOR 0x214
#define EVP_COP_IRQ_VECTOR 0x218 #define EVP_COP_IRQ_VECTOR 0x218
#define EVP_COP_FIQ_VECTOR 0x21C #define EVP_COP_FIQ_VECTOR 0x21C
#define EVP_COP_IRQ_STS 0x220
/*! Primary Interrupt Controller registers. */
#define PRI_ICTLR_FIR 0x14
#define PRI_ICTLR_FIR_SET 0x18
#define PRI_ICTLR_FIR_CLR 0x1C
#define PRI_ICTLR_CPU_IER 0x20
#define PRI_ICTLR_CPU_IER_SET 0x24
#define PRI_ICTLR_CPU_IER_CLR 0x28
#define PRI_ICTLR_CPU_IEP_CLASS 0x2C
#define PRI_ICTLR_COP_IER 0x30
#define PRI_ICTLR_COP_IER_SET 0x34
#define PRI_ICTLR_COP_IER_CLR 0x38
#define PRI_ICTLR_COP_IEP_CLASS 0x3C
/*! AHB Gizmo registers. */
#define AHB_ARBITRATION_PRIORITY_CTRL 0x8
#define ARBITRATION_PRIORITY_CTRL_ENB_FAST_REARBITRATE (1 << 6)
#define AHB_GIZMO_AHB_MEM 0x10
#define AHB_MEM_ENB_FAST_REARBITRATE (1 << 2)
#define AHB_GIZMO_USB 0x20
#define AHB_GIZMO_USB_IMMEDIATE (1 << 18)
#define AHB_AHB_MEM_PREFETCH_CFG1 0xF0
#define MEM_PREFETCH_ENABLE (1 << 31)
#define MEM_PREFETCH_AHB_MST_USB 6
/*! Misc registers. */ /*! Misc registers. */
#define APB_MISC_PP_STRAPPING_OPT_A 0x08 #define APB_MISC_PP_STRAPPING_OPT_A 0x08
#define APB_MISC_PP_PINMUX_GLOBAL 0x40 #define APB_MISC_PP_PINMUX_GLOBAL 0x40
#define APB_MISC_GP_HIDREV 0x804 #define APB_MISC_GP_HIDREV 0x804
#define APB_MISC_GP_AUD_MCLK_CFGPADCTRL 0x8F4
#define APB_MISC_GP_LCD_BL_PWM_CFGPADCTRL 0xA34 #define APB_MISC_GP_LCD_BL_PWM_CFGPADCTRL 0xA34
#define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL 0xA98 #define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL 0xA98
#define APB_MISC_GP_EMMC2_PAD_CFGPADCTRL 0xA9C
#define APB_MISC_GP_EMMC4_PAD_CFGPADCTRL 0xAB4 #define APB_MISC_GP_EMMC4_PAD_CFGPADCTRL 0xAB4
#define APB_MISC_GP_EMMC4_PAD_PUPD_CFGPADCTRL 0xABC #define APB_MISC_GP_EMMC4_PAD_PUPD_CFGPADCTRL 0xABC
#define APB_MISC_GP_WIFI_EN_CFGPADCTRL 0xB64 #define APB_MISC_GP_WIFI_EN_CFGPADCTRL 0xB64
@@ -170,9 +213,14 @@
/*! TMR registers. */ /*! TMR registers. */
#define TIMERUS_CNTR_1US (0x10 + 0x0) #define TIMERUS_CNTR_1US (0x10 + 0x0)
#define TIMERUS_USEC_CFG (0x10 + 0x4) #define TIMERUS_USEC_CFG (0x10 + 0x4)
#define TIMER_TMR8_TMR_PTV 0x78
#define TIMER_TMR9_TMR_PTV 0x80 #define TIMER_TMR9_TMR_PTV 0x80
#define TIMER_EN (1 << 31) #define TIMER_EN (1 << 31)
#define TIMER_PER_EN (1 << 30) #define TIMER_PER_EN (1 << 30)
#define TIMER_TMR8_TMR_PCR 0x7C
#define TIMER_TMR9_TMR_PCR 0x8C
#define TIMER_INTR_CLR (1 << 30)
#define TIMER_WDT4_CONFIG (0x100 + 0x80) #define TIMER_WDT4_CONFIG (0x100 + 0x80)
#define TIMER_SRC(TMR) (TMR & 0xF) #define TIMER_SRC(TMR) (TMR & 0xF)
#define TIMER_PER(PER) ((PER & 0xFF) << 4) #define TIMER_PER(PER) ((PER & 0xFF) << 4)
@@ -210,13 +258,15 @@
/*! Flow controller registers. */ /*! Flow controller registers. */
#define FLOW_CTLR_HALT_COP_EVENTS 0x4 #define FLOW_CTLR_HALT_COP_EVENTS 0x4
#define HALT_COP_SEC (1 << 23) #define HALT_COP_GIC_IRQ (1 << 9)
#define HALT_COP_MSEC (1 << 24) #define HALT_COP_LIC_IRQ (1 << 11)
#define HALT_COP_USEC (1 << 25) #define HALT_COP_SEC (1 << 23)
#define HALT_COP_JTAG (1 << 28) #define HALT_COP_MSEC (1 << 24)
#define HALT_COP_WAIT_EVENT (1 << 30) #define HALT_COP_USEC (1 << 25)
#define HALT_COP_WAIT_IRQ (1 << 31) #define HALT_COP_JTAG (1 << 28)
#define HALT_COP_MAX_CNT 0xFF #define HALT_COP_WAIT_EVENT (1 << 30)
#define HALT_COP_STOP_UNTIL_IRQ (1 << 31)
#define HALT_COP_MAX_CNT 0xFF
#define FLOW_CTLR_HALT_CPU0_EVENTS 0x0 #define FLOW_CTLR_HALT_CPU0_EVENTS 0x0
#define FLOW_CTLR_HALT_CPU1_EVENTS 0x14 #define FLOW_CTLR_HALT_CPU1_EVENTS 0x14
#define FLOW_CTLR_HALT_CPU2_EVENTS 0x1C #define FLOW_CTLR_HALT_CPU2_EVENTS 0x1C
@@ -228,4 +278,9 @@
#define FLOW_CTLR_RAM_REPAIR 0x40 #define FLOW_CTLR_RAM_REPAIR 0x40
#define FLOW_CTLR_BPMP_CLUSTER_CONTROL 0x98 #define FLOW_CTLR_BPMP_CLUSTER_CONTROL 0x98
/*! USB controller registers. */
#define USB1_UTMIP_BAT_CHRG_CFG0 0x830
#define BAT_CHRG_CFG0_OP_SRC_EN (1 << 3)
#define BAT_CHRG_CFG0_PWRDOWN_CHRG (1 << 0)
#endif #endif

172
source/soc/uart.c Normal file
View File

@@ -0,0 +1,172 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2019-2020 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 "../soc/uart.h"
#include "../soc/clock.h"
#include "../soc/t210.h"
#include "../utils/util.h"
/* UART A, B, C, D and E. */
static const u32 uart_baseoff[5] = { 0, 0x40, 0x200, 0x300, 0x400 };
void uart_init(u32 idx, u32 baud)
{
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
// Make sure no data is being sent.
uart_wait_idle(idx, UART_TX_IDLE);
// Set clock.
bool clk_type = clock_uart_use_src_div(idx, baud);
// Misc settings.
u32 div = clk_type ? ((8 * baud + 408000000) / (16 * baud)) : 1; // DIV_ROUND_CLOSEST.
uart->UART_IER_DLAB = 0; // Disable interrupts.
uart->UART_LCR = UART_LCR_DLAB | UART_LCR_WORD_LENGTH_8; // Enable DLAB & set 8n1 mode.
uart->UART_THR_DLAB = (u8)div; // Divisor latch LSB.
uart->UART_IER_DLAB = (u8)(div >> 8); // Divisor latch MSB.
uart->UART_LCR = UART_LCR_WORD_LENGTH_8; // Disable DLAB.
(void)uart->UART_SPR;
// Setup and flush fifo.
uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO;
(void)uart->UART_SPR;
usleep(20);
uart->UART_MCR = 0; // Disable hardware flow control.
usleep(96);
uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO | UART_IIR_FCR_TX_CLR | UART_IIR_FCR_RX_CLR;
// Wait 3 symbols for baudrate change.
usleep(3 * ((baud + 999999) / baud));
uart_wait_idle(idx, UART_TX_IDLE | UART_RX_IDLE);
}
void uart_wait_idle(u32 idx, u32 which)
{
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
if (UART_TX_IDLE & which)
{
while (!(uart->UART_LSR & UART_LSR_TMTY))
;
}
if (UART_RX_IDLE & which)
{
while (uart->UART_LSR & UART_LSR_RDR)
;
}
}
void uart_send(u32 idx, const u8 *buf, u32 len)
{
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
for (u32 i = 0; i != len; i++)
{
while (!(uart->UART_LSR & UART_LSR_THRE))
;
uart->UART_THR_DLAB = buf[i];
};
}
u32 uart_recv(u32 idx, u8 *buf, u32 len)
{
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
u32 timeout = get_tmr_us() + 1000;
u32 i;
for (i = 0; ; i++)
{
while (!(uart->UART_LSR & UART_LSR_RDR))
{
if (!len)
{
if (timeout < get_tmr_us())
break;
}
else if (len < i)
break;
}
if (timeout < get_tmr_us())
break;
buf[i] = uart->UART_THR_DLAB;
timeout = get_tmr_us() + 1000;
};
return i ? (len ? (i - 1) : i) : 0;
}
void uart_invert(u32 idx, bool enable, u32 invert_mask)
{
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
if (enable)
uart->UART_IRDA_CSR |= invert_mask;
else
uart->UART_IRDA_CSR &= ~invert_mask;
(void)uart->UART_SPR;
}
u32 uart_get_IIR(u32 idx)
{
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
return uart->UART_IIR_FCR;
}
void uart_set_IIR(u32 idx)
{
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
uart->UART_IER_DLAB &= ~UART_IER_DLAB_IE_EORD;
(void)uart->UART_SPR;
uart->UART_IER_DLAB |= UART_IER_DLAB_IE_EORD;
(void)uart->UART_SPR;
}
void uart_empty_fifo(u32 idx, u32 which)
{
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
uart->UART_MCR = 0;
(void)uart->UART_SPR;
usleep(96);
uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO | UART_IIR_FCR_TX_CLR | UART_IIR_FCR_RX_CLR;
(void)uart->UART_SPR;
usleep(18);
u32 tries = 0;
if (UART_IIR_FCR_TX_CLR & which)
{
while (tries < 10 && uart->UART_LSR & UART_LSR_TMTY)
{
tries++;
usleep(100);
}
tries = 0;
}
if (UART_IIR_FCR_RX_CLR & which)
{
while (tries < 10 && !uart->UART_LSR & UART_LSR_RDR)
{
tries++;
usleep(100);
}
}
}

87
source/soc/uart.h Normal file
View File

@@ -0,0 +1,87 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2019-2020 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 _UART_H_
#define _UART_H_
#include "../utils/types.h"
#define UART_A 0
#define UART_B 1
#define UART_C 2
#define UART_D 3
#define UART_E 4
#define BAUD_115200 115200
#define UART_TX_IDLE 0x1
#define UART_RX_IDLE 0x2
#define UART_TX_FIFO_FULL 0x100
#define UART_RX_FIFO_EMPTY 0x200
#define UART_INVERT_RXD 0x01
#define UART_INVERT_TXD 0x02
#define UART_INVERT_CTS 0x04
#define UART_INVERT_RTS 0x08
#define UART_IER_DLAB_IE_EORD 0x20
#define UART_LCR_DLAB 0x80
#define UART_LCR_STOP 0x4
#define UART_LCR_WORD_LENGTH_8 0x3
#define UART_LSR_RDR 0x1
#define UART_LSR_THRE 0x20
#define UART_LSR_TMTY 0x40
#define UART_LSR_FIFOE 0x80
#define UART_IIR_FCR_TX_CLR 0x4
#define UART_IIR_FCR_RX_CLR 0x2
#define UART_IIR_FCR_EN_FIFO 0x1
#define UART_MCR_RTS 0x2
#define UART_MCR_DTR 0x1
typedef struct _uart_t
{
/* 0x00 */ vu32 UART_THR_DLAB;
/* 0x04 */ vu32 UART_IER_DLAB;
/* 0x08 */ vu32 UART_IIR_FCR;
/* 0x0C */ vu32 UART_LCR;
/* 0x10 */ vu32 UART_MCR;
/* 0x14 */ vu32 UART_LSR;
/* 0x18 */ vu32 UART_MSR;
/* 0x1C */ vu32 UART_SPR;
/* 0x20 */ vu32 UART_IRDA_CSR;
/* 0x24 */ vu32 UART_RX_FIFO_CFG;
/* 0x28 */ vu32 UART_MIE;
/* 0x2C */ vu32 UART_VENDOR_STATUS;
/* 0x30 */ u8 _pad_30[0xC];
/* 0x3C */ vu32 UART_ASR;
} uart_t;
void uart_init(u32 idx, u32 baud);
void uart_wait_idle(u32 idx, u32 which);
void uart_send(u32 idx, const u8 *buf, u32 len);
u32 uart_recv(u32 idx, u8 *buf, u32 len);
void uart_invert(u32 idx, bool enable, u32 invert_mask);
u32 uart_get_IIR(u32 idx);
void uart_set_IIR(u32 idx);
void uart_empty_fifo(u32 idx, u32 which);
#endif

View File

@@ -23,8 +23,8 @@
.extern memset .extern memset
.type memset, %function .type memset, %function
.extern ipl_main .extern _irq_setup
.type ipl_main, %function .type _irq_setup, %function
.globl _start .globl _start
.type _start, %function .type _start, %function
@@ -67,7 +67,7 @@ _real_start:
LDR R2, =__bss_end LDR R2, =__bss_end
SUB R2, R2, R0 SUB R2, R2, R0
BL memset BL memset
BL ipl_main BL _irq_setup
B . B .
.globl pivot_stack .globl pivot_stack

View File

@@ -47,7 +47,8 @@ bool emummc_load_cfg()
emu_cfg.file_based_part_size = 0; emu_cfg.file_based_part_size = 0;
emu_cfg.active_part = 0; emu_cfg.active_part = 0;
emu_cfg.fs_ver = 0; emu_cfg.fs_ver = 0;
emu_cfg.emummc_file_based_path = (char *)malloc(0x80); if (!emu_cfg.emummc_file_based_path)
emu_cfg.emummc_file_based_path = (char *)malloc(0x80);
LIST_INIT(ini_sections); LIST_INIT(ini_sections);
if (ini_parse(&ini_sections, "emuMMC/emummc.ini", false)) if (ini_parse(&ini_sections, "emuMMC/emummc.ini", false))
@@ -98,7 +99,7 @@ static int emummc_raw_get_part_off(int part_idx)
int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc) int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc)
{ {
FILINFO fno; FILINFO fno;
if (!sdmmc_storage_init_mmc(storage, sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4)) if (!sdmmc_storage_init_mmc(storage, sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
{ {
EPRINTF("Failed to init eMMC."); EPRINTF("Failed to init eMMC.");

84
source/storage/mbr_gpt.h Normal file
View File

@@ -0,0 +1,84 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* 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 MBR_GPT_H
#define MBR_GPT_H
#include "../utils/types.h"
typedef struct _mbr_chs_t
{
u8 head;
u8 sector;
u8 cylinder;
} __attribute__((packed)) mbr_chs_t;
typedef struct _mbr_part_t
{
u8 status;
mbr_chs_t start_sct_chs;
u8 type;
mbr_chs_t end_sct_chs;
u32 start_sct;
u32 size_sct;
} __attribute__((packed)) mbr_part_t;
typedef struct _mbr_t
{
u8 bootstrap[0x1B8];
u32 signature;
u16 copy_protected;
mbr_part_t partitions[4];
u16 boot_signature;
} __attribute__((packed)) mbr_t;
typedef struct _gpt_entry_t
{
u8 type_guid[0x10];
u8 part_guid[0x10];
u64 lba_start;
u64 lba_end;
u64 attrs;
u16 name[36];
} gpt_entry_t;
typedef struct _gpt_header_t
{
u64 signature; // "EFI PART"
u32 revision;
u32 size;
u32 crc32;
u32 res1;
u64 my_lba;
u64 alt_lba;
u64 first_use_lba;
u64 last_use_lba;
u8 disk_guid[0x10];
u64 part_ent_lba;
u32 num_part_ents;
u32 part_ent_size;
u32 part_ents_crc32;
u8 res2[420]; // Used as first 3 partition entries backup for HOS.
} gpt_header_t;
typedef struct _gpt_t
{
gpt_header_t header;
gpt_entry_t entries[128];
} gpt_t;
#endif

View File

@@ -31,7 +31,7 @@
#define MMC_ALL_SEND_CID 2 /* bcr R2 */ #define MMC_ALL_SEND_CID 2 /* bcr R2 */
#define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */ #define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */
#define MMC_SET_DSR 4 /* bc [31:16] RCA */ #define MMC_SET_DSR 4 /* bc [31:16] RCA */
#define MMC_SLEEP_AWAKE 5 /* ac [31:16] RCA 15:flg R1b */ #define MMC_SLEEP_AWAKE 5 /* ac [31:16] RCA 15:flg R1b */
#define MMC_SWITCH 6 /* ac [31:0] See below R1b */ #define MMC_SWITCH 6 /* ac [31:0] See below R1b */
#define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */ #define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */
#define MMC_SEND_EXT_CSD 8 /* adtc R1 */ #define MMC_SEND_EXT_CSD 8 /* adtc R1 */
@@ -51,7 +51,7 @@
#define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */ #define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */
#define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */ #define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */
#define MMC_SEND_TUNING_BLOCK 19 /* adtc R1 */ #define MMC_SEND_TUNING_BLOCK 19 /* adtc R1 */
#define MMC_SEND_TUNING_BLOCK_HS200 21 /* adtc R1 */ #define MMC_SEND_TUNING_BLOCK_HS200 21 /* adtc R1 */
/* class 3 */ /* class 3 */
#define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */ #define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */

View File

@@ -16,6 +16,7 @@
#include <string.h> #include <string.h>
#include "mbr_gpt.h"
#include "nx_emmc.h" #include "nx_emmc.h"
#include "emummc.h" #include "emummc.h"
#include "../mem/heap.h" #include "../mem/heap.h"
@@ -23,28 +24,31 @@
void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage) void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage)
{ {
u8 *buf = (u8 *)malloc(NX_GPT_NUM_BLOCKS * NX_EMMC_BLOCKSIZE); gpt_t *gpt_buf = (gpt_t *)calloc(NX_GPT_NUM_BLOCKS, NX_EMMC_BLOCKSIZE);
emummc_storage_read(storage, NX_GPT_FIRST_LBA, NX_GPT_NUM_BLOCKS, buf); emummc_storage_read(storage, NX_GPT_FIRST_LBA, NX_GPT_NUM_BLOCKS, gpt_buf);
gpt_header_t *hdr = (gpt_header_t *)buf; for (u32 i = 0; i < gpt_buf->header.num_part_ents; i++)
for (u32 i = 0; i < hdr->num_part_ents; i++)
{ {
gpt_entry_t *ent = (gpt_entry_t *)(buf + (hdr->part_ent_lba - 1) * NX_EMMC_BLOCKSIZE + i * sizeof(gpt_entry_t)); emmc_part_t *part = (emmc_part_t *)calloc(sizeof(emmc_part_t), 1);
emmc_part_t *part = (emmc_part_t *)malloc(sizeof(emmc_part_t));
part->lba_start = ent->lba_start; if (gpt_buf->entries[i].lba_start < gpt_buf->header.first_use_lba)
part->lba_end = ent->lba_end; continue;
part->attrs = ent->attrs;
part->index = i;
part->lba_start = gpt_buf->entries[i].lba_start;
part->lba_end = gpt_buf->entries[i].lba_end;
part->attrs = gpt_buf->entries[i].attrs;
// ASCII conversion. Copy only the LSByte of the UTF-16LE name. // ASCII conversion. Copy only the LSByte of the UTF-16LE name.
for (u32 i = 0; i < 36; i++) for (u32 j = 0; j < 36; j++)
part->name[i] = ent->name[i]; part->name[j] = gpt_buf->entries[i].name[j];
part->name[36] = 0; part->name[35] = 0;
list_append(gpt, &part->link); list_append(gpt, &part->link);
} }
free(buf); free(gpt_buf);
} }
void nx_emmc_gpt_free(link_t *gpt) void nx_emmc_gpt_free(link_t *gpt)

View File

@@ -17,38 +17,9 @@
#ifndef _NX_EMMC_H_ #ifndef _NX_EMMC_H_
#define _NX_EMMC_H_ #define _NX_EMMC_H_
#include "sdmmc.h"
#include "../utils/types.h" #include "../utils/types.h"
#include "../utils/list.h" #include "../utils/list.h"
#include "sdmmc.h"
typedef struct _gpt_entry_t
{
u8 type_guid[0x10];
u8 part_guid[0x10];
u64 lba_start;
u64 lba_end;
u64 attrs;
u16 name[36];
} gpt_entry_t;
typedef struct _gpt_header_t
{
u64 signature;
u32 revision;
u32 size;
u32 crc32;
u32 res1;
u64 my_lba;
u64 alt_lba;
u64 first_use_lba;
u64 last_use_lba;
u8 disk_guid[0x10];
u64 part_ent_lba;
u32 num_part_ents;
u32 part_ent_size;
u32 part_ents_crc32;
u8 res2[420];
} gpt_header_t;
#define NX_GPT_FIRST_LBA 1 #define NX_GPT_FIRST_LBA 1
#define NX_GPT_NUM_BLOCKS 33 #define NX_GPT_NUM_BLOCKS 33
@@ -56,6 +27,7 @@ typedef struct _gpt_header_t
typedef struct _emmc_part_t typedef struct _emmc_part_t
{ {
u32 index;
u32 lba_start; u32 lba_start;
u32 lba_end; u32 lba_end;
u64 attrs; u64 attrs;

181
source/storage/nx_sd.c Normal file
View File

@@ -0,0 +1,181 @@
/*
* 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 "nx_sd.h"
#include "sdmmc.h"
#include "sdmmc_driver.h"
#include "../gfx/gfx.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
bool sd_mounted = false, sd_inited = false;
static u32 sd_mode = SD_UHS_SDR82;
u32 sd_get_mode()
{
return sd_mode;
}
int sd_init_retry(bool power_cycle)
{
u32 bus_width = SDMMC_BUS_WIDTH_4;
u32 type = SDHCI_TIMING_UHS_SDR82;
// Power cycle SD card.
if (power_cycle)
{
sd_mode--;
sdmmc_storage_end(&sd_storage);
}
// Get init parameters.
switch (sd_mode)
{
case SD_INIT_FAIL: // Reset to max.
return 0;
case SD_1BIT_HS25:
bus_width = SDMMC_BUS_WIDTH_1;
type = SDHCI_TIMING_SD_HS25;
break;
case SD_4BIT_HS25:
type = SDHCI_TIMING_SD_HS25;
break;
case SD_UHS_SDR82:
type = SDHCI_TIMING_UHS_SDR82;
break;
default:
sd_mode = SD_UHS_SDR82;
}
return sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, bus_width, type);
}
bool sd_initialize(bool power_cycle)
{
if (power_cycle)
sdmmc_storage_end(&sd_storage);
int res = !sd_init_retry(false);
while (true)
{
if (!res)
return true;
else if (!sdmmc_get_sd_inserted()) // SD Card is not inserted.
{
sd_mode = SD_UHS_SDR82;
break;
}
else if (sd_mode == SD_INIT_FAIL)
break;
else
res = !sd_init_retry(true);
}
sdmmc_storage_end(&sd_storage);
return false;
}
bool sd_mount()
{
if (sd_mounted)
return true;
sd_inited = sd_initialize(false);
int res = !sd_inited;
if (res)
{
gfx_con.mute = false;
EPRINTF("Failed to init SD card.");
if (!sdmmc_get_sd_inserted())
EPRINTF("Make sure that it is inserted.");
else
EPRINTF("SD Card Reader is not properly seated!");
}
else
{
res = f_mount(&sd_fs, "", 1);
if (res == FR_OK)
{
sd_mounted = true;
return true;
}
else
{
gfx_con.mute = false;
EPRINTFARGS("Failed to mount SD card (FatFS Error %d).\nMake sure that a FAT partition exists..", res);
}
}
return false;
}
void sd_unmount()
{
sd_mode = SD_UHS_SDR82;
if (sd_mounted)
{
f_mount(NULL, "", 1);
sdmmc_storage_end(&sd_storage);
sd_mounted = false;
sd_inited = false;
}
}
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);
if (f_read(&fp, buf, size, NULL) != FR_OK)
{
free(buf);
f_close(&fp);
return NULL;
}
f_close(&fp);
return buf;
}
int sd_save_to_file(void *buf, u32 size, const char *filename)
{
FIL fp;
u32 res = 0;
res = f_open(&fp, filename, FA_CREATE_ALWAYS | FA_WRITE);
if (res)
{
EPRINTFARGS("Error (%d) creating file\n%s.\n", res, filename);
return res;
}
f_write(&fp, buf, size, NULL);
f_close(&fp);
return 0;
}

45
source/storage/nx_sd.h Normal file
View File

@@ -0,0 +1,45 @@
/*
* 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/>.
*/
#ifndef NX_SD_H
#define NX_SD_H
#include "sdmmc.h"
#include "sdmmc_driver.h"
#include "../libs/fatfs/ff.h"
enum
{
SD_INIT_FAIL = 0,
SD_1BIT_HS25 = 1,
SD_4BIT_HS25 = 2,
SD_UHS_SDR82 = 3,
};
sdmmc_t sd_sdmmc;
sdmmc_storage_t sd_storage;
FATFS sd_fs;
u32 sd_get_mode();
int sd_init_retry(bool power_cycle);
bool sd_initialize(bool power_cycle);
bool sd_mount();
void sd_unmount();
void *sd_file_read(const char *path, u32 *fsize);
int sd_save_to_file(void *buf, u32 size, const char *filename);
#endif

View File

@@ -106,6 +106,11 @@
#define SD_SET_CURRENT_LIMIT_600 2 #define SD_SET_CURRENT_LIMIT_600 2
#define SD_SET_CURRENT_LIMIT_800 3 #define SD_SET_CURRENT_LIMIT_800 3
#define SD_MAX_CURRENT_200 (1 << SD_SET_CURRENT_LIMIT_200)
#define SD_MAX_CURRENT_400 (1 << SD_SET_CURRENT_LIMIT_400)
#define SD_MAX_CURRENT_600 (1 << SD_SET_CURRENT_LIMIT_600)
#define SD_MAX_CURRENT_800 (1 << SD_SET_CURRENT_LIMIT_800)
/* /*
* SD_SWITCH mode * SD_SWITCH mode
*/ */

View File

@@ -18,6 +18,7 @@
#include <string.h> #include <string.h>
#include "sdmmc.h" #include "sdmmc.h"
#include "mmc.h" #include "mmc.h"
#include "nx_sd.h"
#include "sd.h" #include "sd.h"
#include "../../common/memory_map.h" #include "../../common/memory_map.h"
#include "../gfx/gfx.h" #include "../gfx/gfx.h"
@@ -135,10 +136,12 @@ static int _sdmmc_storage_check_status(sdmmc_storage_t *storage)
static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out, u32 sector, u32 num_sectors, void *buf, u32 is_write) static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out, u32 sector, u32 num_sectors, void *buf, u32 is_write)
{ {
u32 tmp = 0;
sdmmc_cmd_t cmdbuf; sdmmc_cmd_t cmdbuf;
sdmmc_req_t reqbuf;
sdmmc_init_cmd(&cmdbuf, is_write ? MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK, sector, SDMMC_RSP_TYPE_1, 0); sdmmc_init_cmd(&cmdbuf, is_write ? MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK, sector, SDMMC_RSP_TYPE_1, 0);
sdmmc_req_t reqbuf;
reqbuf.buf = buf; reqbuf.buf = buf;
reqbuf.num_sectors = num_sectors; reqbuf.num_sectors = num_sectors;
reqbuf.blksize = 512; reqbuf.blksize = 512;
@@ -148,7 +151,6 @@ static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out
if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, blkcnt_out)) if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, blkcnt_out))
{ {
u32 tmp = 0;
sdmmc_stop_transmission(storage->sdmmc, &tmp); sdmmc_stop_transmission(storage->sdmmc, &tmp);
_sdmmc_storage_get_status(storage, &tmp, 0); _sdmmc_storage_get_status(storage, &tmp, 0);
@@ -171,25 +173,42 @@ int sdmmc_storage_end(sdmmc_storage_t *storage)
static int _sdmmc_storage_readwrite(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf, u32 is_write) static int _sdmmc_storage_readwrite(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf, u32 is_write)
{ {
u8 *bbuf = (u8 *)buf; u8 *bbuf = (u8 *)buf;
bool first_reinit = false;
while (num_sectors) while (num_sectors)
{ {
u32 blkcnt = 0; u32 blkcnt = 0;
//Retry 9 times on error. // Retry 5 times if failed.
u32 retries = 10; u32 retries = 5;
do do
{ {
reinit_try:
if (_sdmmc_storage_readwrite_ex(storage, &blkcnt, sector, MIN(num_sectors, 0xFFFF), bbuf, is_write)) if (_sdmmc_storage_readwrite_ex(storage, &blkcnt, sector, MIN(num_sectors, 0xFFFF), bbuf, is_write))
goto out; goto out;
else else
retries--; retries--;
msleep(100); msleep(50);
} while (retries); } while (retries);
// Disk IO failure! Reinit SD Card to a lower speed.
if (storage->sdmmc->id == SDMMC_1)
{
int res;
if (!first_reinit)
res = sd_initialize(true);
else
res = sd_init_retry(true);
retries = 3;
first_reinit = true;
if (res)
goto reinit_try;
}
return 0; return 0;
out:; out:
DPRINTF("readwrite: %08X\n", blkcnt); DPRINTF("readwrite: %08X\n", blkcnt);
sector += blkcnt; sector += blkcnt;
num_sectors -= blkcnt; num_sectors -= blkcnt;
@@ -201,12 +220,34 @@ DPRINTF("readwrite: %08X\n", blkcnt);
int sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf) int sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf)
{ {
return _sdmmc_storage_readwrite(storage, sector, num_sectors, buf, 0); // Ensure that buffer resides in DRAM and it's DMA aligned.
if (((u32)buf >= DRAM_START) && !((u32)buf % 8))
return _sdmmc_storage_readwrite(storage, sector, num_sectors, buf, 0);
if (num_sectors > (SDMMC_UP_BUF_SZ / 512))
return 0;
u8 *tmp_buf = (u8 *)SDMMC_UPPER_BUFFER;
if (_sdmmc_storage_readwrite(storage, sector, num_sectors, tmp_buf, 0))
{
memcpy(buf, tmp_buf, 512 * num_sectors);
return 1;
}
return 0;
} }
int sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf) int sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf)
{ {
return _sdmmc_storage_readwrite(storage, sector, num_sectors, buf, 1); // Ensure that buffer resides in DRAM and it's DMA aligned.
if (((u32)buf >= DRAM_START) && !((u32)buf % 8))
return _sdmmc_storage_readwrite(storage, sector, num_sectors, buf, 1);
if (num_sectors > (SDMMC_UP_BUF_SZ / 512))
return 0;
u8 *tmp_buf = (u8 *)SDMMC_UPPER_BUFFER;
memcpy(tmp_buf, buf, 512 * num_sectors);
return _sdmmc_storage_readwrite(storage, sector, num_sectors, tmp_buf, 1);
} }
/* /*
@@ -401,7 +442,7 @@ static int _mmc_storage_enable_HS(sdmmc_storage_t *storage, int check)
if (check && !_sdmmc_storage_check_status(storage)) if (check && !_sdmmc_storage_check_status(storage))
return 0; return 0;
if (!sdmmc_setup_clock(storage->sdmmc, 2)) if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS52))
return 0; return 0;
DPRINTF("[MMC] switched to HS\n"); DPRINTF("[MMC] switched to HS\n");
@@ -418,10 +459,10 @@ 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))) if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200)))
return 0; return 0;
if (!sdmmc_setup_clock(storage->sdmmc, 3)) if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS200))
return 0; return 0;
if (!sdmmc_config_tuning(storage->sdmmc, 3, MMC_SEND_TUNING_BLOCK_HS200)) if (!sdmmc_tuning_execute(storage->sdmmc, SDHCI_TIMING_MMC_HS200, MMC_SEND_TUNING_BLOCK_HS200))
return 0; return 0;
DPRINTF("[MMC] switched to HS200\n"); DPRINTF("[MMC] switched to HS200\n");
@@ -435,7 +476,7 @@ static int _mmc_storage_enable_HS400(sdmmc_storage_t *storage)
if (!_mmc_storage_enable_HS200(storage)) if (!_mmc_storage_enable_HS200(storage))
return 0; return 0;
sdmmc_get_venclkctl(storage->sdmmc); sdmmc_set_tap_value(storage->sdmmc);
if (!_mmc_storage_enable_HS(storage, 0)) if (!_mmc_storage_enable_HS(storage, 0))
return 0; return 0;
@@ -446,7 +487,7 @@ static int _mmc_storage_enable_HS400(sdmmc_storage_t *storage)
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400))) if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400)))
return 0; return 0;
if (!sdmmc_setup_clock(storage->sdmmc, 4)) if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS400))
return 0; return 0;
DPRINTF("[MMC] switched to HS400\n"); DPRINTF("[MMC] switched to HS400\n");
@@ -457,22 +498,20 @@ DPRINTF("[MMC] switched to HS400\n");
static int _mmc_storage_enable_highspeed(sdmmc_storage_t *storage, u32 card_type, u32 type) static int _mmc_storage_enable_highspeed(sdmmc_storage_t *storage, u32 card_type, u32 type)
{ {
//TODO: this should be a config item. if (sdmmc_get_io_power(storage->sdmmc) != SDMMC_POWER_1_8)
// --v
if (!1 || sdmmc_get_voltage(storage->sdmmc) != SDMMC_POWER_1_8)
goto out; goto out;
if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 && 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 == SDHCI_TIMING_MMC_HS400)
return _mmc_storage_enable_HS400(storage); return _mmc_storage_enable_HS400(storage);
if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 || if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 ||
(sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_4 (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_4
&& card_type & EXT_CSD_CARD_TYPE_HS200_1_8V && card_type & EXT_CSD_CARD_TYPE_HS200_1_8V
&& (type == 4 || type == 3))) && (type == SDHCI_TIMING_MMC_HS400 || type == SDHCI_TIMING_MMC_HS200)))
return _mmc_storage_enable_HS200(storage); return _mmc_storage_enable_HS200(storage);
out:; out:
if (card_type & EXT_CSD_CARD_TYPE_HS_52) if (card_type & EXT_CSD_CARD_TYPE_HS_52)
return _mmc_storage_enable_HS(storage, 1); return _mmc_storage_enable_HS(storage, 1);
@@ -487,13 +526,13 @@ static int _mmc_storage_enable_bkops(sdmmc_storage_t *storage)
return _sdmmc_storage_check_status(storage); return _sdmmc_storage_check_status(storage);
} }
int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type) int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type)
{ {
memset(storage, 0, sizeof(sdmmc_storage_t)); memset(storage, 0, sizeof(sdmmc_storage_t));
storage->sdmmc = sdmmc; storage->sdmmc = sdmmc;
storage->rca = 2; //TODO: this could be a config item. storage->rca = 2; //TODO: this could be a config item.
if (!sdmmc_init(sdmmc, id, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_1, 0, 0)) if (!sdmmc_init(sdmmc, SDMMC_4, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_MMC_ID, SDMMC_AUTO_CAL_DISABLE))
return 0; return 0;
DPRINTF("[MMC] after init\n"); DPRINTF("[MMC] after init\n");
@@ -520,7 +559,7 @@ DPRINTF("[MMC] set relative addr\n");
DPRINTF("[MMC] got csd\n"); DPRINTF("[MMC] got csd\n");
_mmc_storage_parse_csd(storage); _mmc_storage_parse_csd(storage);
if (!sdmmc_setup_clock(storage->sdmmc, 1)) if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_LS26))
return 0; return 0;
DPRINTF("[MMC] after setup clock\n"); DPRINTF("[MMC] after setup clock\n");
@@ -544,35 +583,27 @@ DPRINTF("[MMC] set blocklen to 512\n");
return 0; 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, (u8 *)SDMMC_UPPER_BUFFER))
if (!_mmc_storage_get_ext_csd(storage, ext_csd))
{
free(ext_csd);
return 0; 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 _mmc_storage_parse_cid(storage); //This needs to be after csd and ext_csd
//gfx_hexdump(0, ext_csd, 512); //gfx_hexdump(0, ext_csd, 512);
/* When auto BKOPS is enabled the mmc device should be powered all the time until we disable this and check status. /* When auto BKOPS is enabled the mmc device should be powered all the time until we disable this and check status.
Disable it for now until BKOPS disable added to power down sequence at sdmmc_storage_end(). Disable it for now until BKOPS disable added to power down sequence at sdmmc_storage_end().
Additionally this works only when we put the device in idle mode which we don't after enabling it. */ Additionally this works only when we put the device in idle mode which we don't after enabling it. */
if (storage->ext_csd.bkops & 0x1 && !(storage->ext_csd.bkops_en & EXT_CSD_BKOPS_LEVEL_2) && 0) if (0 && storage->ext_csd.bkops & 0x1 && !(storage->ext_csd.bkops_en & EXT_CSD_BKOPS_LEVEL_2))
{ {
_mmc_storage_enable_bkops(storage); _mmc_storage_enable_bkops(storage);
DPRINTF("[MMC] BKOPS enabled\n"); DPRINTF("[MMC] BKOPS enabled\n");
} }
else
{
DPRINTF("[MMC] BKOPS disabled\n");
}
if (!_mmc_storage_enable_highspeed(storage, storage->ext_csd.card_type, type)) if (!_mmc_storage_enable_highspeed(storage, storage->ext_csd.card_type, type))
return 0; return 0;
DPRINTF("[MMC] succesfully switched to HS mode\n"); DPRINTF("[MMC] succesfully switched to HS mode\n");
sdmmc_sd_clock_ctrl(storage->sdmmc, 1); sdmmc_card_clock_ctrl(storage->sdmmc, SDMMC_AUTO_CAL_ENABLE);
return 1; return 1;
} }
@@ -656,6 +687,7 @@ static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, i
if (cond & SD_OCR_CCS) if (cond & SD_OCR_CCS)
storage->has_sector_access = 1; storage->has_sector_access = 1;
// Check if card supports 1.8V signaling.
if (cond & SD_ROCR_S18A && supports_low_voltage) if (cond & SD_ROCR_S18A && supports_low_voltage)
{ {
//The low voltage regulator configuration is valid for SDMMC1 only. //The low voltage regulator configuration is valid for SDMMC1 only.
@@ -804,34 +836,37 @@ int _sd_storage_switch(sdmmc_storage_t *storage, void *buf, int mode, int group,
return _sdmmc_storage_check_result(tmp); return _sdmmc_storage_check_result(tmp);
} }
void _sd_storage_set_current_limit(sdmmc_storage_t *storage, u8 *buf) void _sd_storage_set_current_limit(sdmmc_storage_t *storage, u16 current_limit, u8 *buf)
{ {
u32 pwr = SD_SET_CURRENT_LIMIT_800; u32 pwr = SD_SET_CURRENT_LIMIT_200;
if (current_limit & SD_MAX_CURRENT_800)
pwr = SD_SET_CURRENT_LIMIT_800;
else if (current_limit & SD_MAX_CURRENT_600)
pwr = SD_SET_CURRENT_LIMIT_600;
else if (current_limit & SD_MAX_CURRENT_400)
pwr = SD_SET_CURRENT_LIMIT_400;
_sd_storage_switch(storage, buf, SD_SWITCH_SET, 3, pwr); _sd_storage_switch(storage, buf, SD_SWITCH_SET, 3, pwr);
while (pwr > 0) if (((buf[15] >> 4) & 0x0F) == pwr)
{ {
pwr--; switch (pwr)
_sd_storage_switch(storage, buf, SD_SWITCH_SET, 3, pwr); {
if (((buf[15] >> 4) & 0x0F) == pwr) case SD_SET_CURRENT_LIMIT_800:
DPRINTF("[SD] power limit raised to 800mA\n");
break; break;
} case SD_SET_CURRENT_LIMIT_600:
switch (pwr)
{
case SD_SET_CURRENT_LIMIT_800:
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; break;
case SD_SET_CURRENT_LIMIT_400: case SD_SET_CURRENT_LIMIT_400:
DPRINTF("[SD] power limit raised to 800mA\n"); DPRINTF("[SD] power limit raised to 400mA\n");
break; break;
default: default:
case SD_SET_CURRENT_LIMIT_200: case SD_SET_CURRENT_LIMIT_200:
DPRINTF("[SD] power limit defaulted to 200mA\n"); DPRINTF("[SD] power limit defaulted to 200mA\n");
break; break;
}
} }
} }
@@ -839,30 +874,33 @@ 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)) if (!_sd_storage_switch(storage, buf, SD_SWITCH_CHECK, 0, hs_type))
return 0; return 0;
DPRINTF("[SD] SD supports switch to (U)HS check\n"); DPRINTF("[SD] supports switch to (U)HS mode\n");
u32 type_out = buf[16] & 0xF; u32 type_out = buf[16] & 0xF;
if (type_out != hs_type) if (type_out != hs_type)
return 0; return 0;
DPRINTF("[SD] SD supports selected (U)HS mode\n"); DPRINTF("[SD] supports selected (U)HS mode\n");
if ((((u16)buf[0] << 8) | buf[1]) < 0x320) u16 total_pwr_consumption = ((u16)buf[0] << 8) | buf[1];
DPRINTF("[SD] total max current: %d\n", total_pwr_consumption);
if (total_pwr_consumption <= 800)
{ {
if (!_sd_storage_switch(storage, buf, SD_SWITCH_SET, 0, hs_type)) if (!_sd_storage_switch(storage, buf, SD_SWITCH_SET, 0, hs_type))
return 0; return 0;
if (type_out != (buf[16] & 0xF)) if (type_out != (buf[16] & 0xF))
return 0; return 0;
}
return 1; return 1;
}
DPRINTF("[SD] card max current over limit\n");
return 0;
} }
int _sd_storage_enable_uhs_low_volt(sdmmc_storage_t *storage, u32 type, u8 *buf) int _sd_storage_enable_uhs_low_volt(sdmmc_storage_t *storage, u32 type, u8 *buf)
{ {
// Try to raise the current limit to let the card perform better.
_sd_storage_set_current_limit(storage, buf);
if (sdmmc_get_bus_width(storage->sdmmc) != SDMMC_BUS_WIDTH_4) if (sdmmc_get_bus_width(storage->sdmmc) != SDMMC_BUS_WIDTH_4)
return 0; return 0;
@@ -870,32 +908,55 @@ int _sd_storage_enable_uhs_low_volt(sdmmc_storage_t *storage, u32 type, u8 *buf)
return 0; return 0;
//gfx_hexdump(0, (u8 *)buf, 64); //gfx_hexdump(0, (u8 *)buf, 64);
u8 access_mode = buf[13];
u16 current_limit = buf[7] | buf[6] << 8;
// Try to raise the current limit to let the card perform better.
_sd_storage_set_current_limit(storage, current_limit, buf);
u32 hs_type = 0; u32 hs_type = 0;
switch (type) switch (type)
{ {
case 11: // SDR104. case SDHCI_TIMING_UHS_SDR104:
case SDHCI_TIMING_UHS_SDR82:
// Fall through if not supported. // Fall through if not supported.
if (buf[13] & SD_MODE_UHS_SDR104) if (access_mode & SD_MODE_UHS_SDR104)
{ {
type = 11;
hs_type = UHS_SDR104_BUS_SPEED; 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; switch (type)
{
case SDHCI_TIMING_UHS_SDR104:
storage->csd.busspeed = 104;
break;
case SDHCI_TIMING_UHS_SDR82:
storage->csd.busspeed = 82;
break;
}
break; break;
} }
case 10: // SDR50. case SDHCI_TIMING_UHS_SDR50:
if (buf[13] & SD_MODE_UHS_SDR50) if (access_mode & SD_MODE_UHS_SDR50)
{ {
type = 10; type = SDHCI_TIMING_UHS_SDR50;
hs_type = UHS_SDR50_BUS_SPEED; 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; storage->csd.busspeed = 50;
break; break;
} }
case 8: // SDR12. case SDHCI_TIMING_UHS_SDR25:
if (!(buf[13] & SD_MODE_UHS_SDR12)) if (access_mode & SD_MODE_UHS_SDR25)
{
type = SDHCI_TIMING_UHS_SDR25;
hs_type = UHS_SDR50_BUS_SPEED;
DPRINTF("[SD] bus speed set to SDR25\n");
storage->csd.busspeed = 25;
break;
}
case SDHCI_TIMING_UHS_SDR12:
if (!(access_mode & SD_MODE_UHS_SDR12))
return 0; return 0;
type = 8; type = SDHCI_TIMING_UHS_SDR12;
hs_type = UHS_SDR12_BUS_SPEED; 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; storage->csd.busspeed = 12;
@@ -907,11 +968,11 @@ DPRINTF("[SD] bus speed set to SDR12\n");
if (!_sd_storage_enable_highspeed(storage, hs_type, buf)) if (!_sd_storage_enable_highspeed(storage, hs_type, buf))
return 0; return 0;
DPRINTF("[SD] SD card accepted UHS\n"); DPRINTF("[SD] card accepted UHS\n");
if (!sdmmc_setup_clock(storage->sdmmc, type)) if (!sdmmc_setup_clock(storage->sdmmc, type))
return 0; return 0;
DPRINTF("[SD] setup clock\n"); DPRINTF("[SD] setup clock\n");
if (!sdmmc_config_tuning(storage->sdmmc, type, MMC_SEND_TUNING_BLOCK)) if (!sdmmc_tuning_execute(storage->sdmmc, type, MMC_SEND_TUNING_BLOCK))
return 0; return 0;
DPRINTF("[SD] config tuning\n"); DPRINTF("[SD] config tuning\n");
return _sdmmc_storage_check_status(storage); return _sdmmc_storage_check_status(storage);
@@ -922,16 +983,23 @@ int _sd_storage_enable_hs_high_volt(sdmmc_storage_t *storage, u8 *buf)
if (!_sd_storage_switch_get(storage, buf)) if (!_sd_storage_switch_get(storage, buf))
return 0; return 0;
//gfx_hexdump(0, (u8 *)buf, 64); //gfx_hexdump(0, (u8 *)buf, 64);
if (!(buf[13] & SD_MODE_HIGH_SPEED))
u8 access_mode = buf[13];
u16 current_limit = buf[7] | buf[6] << 8;
// Try to raise the current limit to let the card perform better.
_sd_storage_set_current_limit(storage, current_limit, buf);
if (!(access_mode & SD_MODE_HIGH_SPEED))
return 1; return 1;
if (!_sd_storage_enable_highspeed(storage, 1, buf)) if (!_sd_storage_enable_highspeed(storage, HIGH_SPEED_BUS_SPEED, buf))
return 0; return 0;
if (!_sdmmc_storage_check_status(storage)) if (!_sdmmc_storage_check_status(storage))
return 0; return 0;
return sdmmc_setup_clock(storage->sdmmc, 7); return sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_SD_HS25);
} }
static void _sd_storage_parse_ssr(sdmmc_storage_t *storage) static void _sd_storage_parse_ssr(sdmmc_storage_t *storage)
@@ -1055,6 +1123,23 @@ static void _sd_storage_parse_csd(sdmmc_storage_t *storage)
} }
} }
static bool _sdmmc_storage_supports_low_voltage(u32 bus_width, u32 type)
{
switch (type)
{
case SDHCI_TIMING_UHS_SDR12:
case SDHCI_TIMING_UHS_SDR25:
case SDHCI_TIMING_UHS_SDR50:
case SDHCI_TIMING_UHS_SDR104:
case SDHCI_TIMING_UHS_SDR82:
case SDHCI_TIMING_UHS_DDR50:
if (bus_width == SDMMC_BUS_WIDTH_4)
return true;
default:
return false;
}
}
void sdmmc_storage_init_wait_sd() void sdmmc_storage_init_wait_sd()
{ {
u32 sd_poweroff_time = (u32)get_tmr_ms() - sd_power_cycle_time_start; u32 sd_poweroff_time = (u32)get_tmr_ms() - sd_power_cycle_time_start;
@@ -1062,7 +1147,7 @@ void sdmmc_storage_init_wait_sd()
msleep(100 - sd_poweroff_time); 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 sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type)
{ {
int is_version_1 = 0; int is_version_1 = 0;
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; u8 *buf = (u8 *)SDMMC_UPPER_BUFFER;
@@ -1073,7 +1158,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
memset(storage, 0, sizeof(sdmmc_storage_t)); memset(storage, 0, sizeof(sdmmc_storage_t));
storage->sdmmc = sdmmc; storage->sdmmc = sdmmc;
if (!sdmmc_init(sdmmc, id, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, 5, 0)) if (!sdmmc_init(sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_SD_ID, SDMMC_AUTO_CAL_DISABLE))
return 0; return 0;
DPRINTF("[SD] after init\n"); DPRINTF("[SD] after init\n");
@@ -1088,7 +1173,9 @@ DPRINTF("[SD] went to idle state\n");
return 0; 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)) bool supports_low_voltage = _sdmmc_storage_supports_low_voltage(bus_width, type);
if (!_sd_storage_get_op_cond(storage, is_version_1, supports_low_voltage))
return 0; return 0;
DPRINTF("[SD] got op cond\n"); DPRINTF("[SD] got op cond\n");
@@ -1122,7 +1209,7 @@ DPRINTF("[SD] unknown CSD structure %d\n", storage->csd.structure);
if (!storage->is_low_voltage) if (!storage->is_low_voltage)
{ {
if (!sdmmc_setup_clock(storage->sdmmc, 6)) if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_SD_DS12))
return 0; return 0;
DPRINTF("[SD] after setup clock\n"); DPRINTF("[SD] after setup clock\n");
} }
@@ -1165,18 +1252,26 @@ DPRINTF("[SD] SD does not support wide bus width\n");
if (!_sd_storage_enable_uhs_low_volt(storage, type, buf)) if (!_sd_storage_enable_uhs_low_volt(storage, type, buf))
return 0; return 0;
DPRINTF("[SD] enabled UHS\n"); DPRINTF("[SD] enabled UHS\n");
sdmmc_card_clock_ctrl(sdmmc, SDMMC_AUTO_CAL_ENABLE);
} }
else if (type != 6 && (storage->scr.sda_vsn & 0xF) != 0) else if (type != SDHCI_TIMING_SD_DS12 && (storage->scr.sda_vsn & 0xF) != 0)
{ {
if (!_sd_storage_enable_hs_high_volt(storage, buf)) if (!_sd_storage_enable_hs_high_volt(storage, buf))
return 0; return 0;
DPRINTF("[SD] enabled HS\n"); DPRINTF("[SD] enabled HS\n");
storage->csd.busspeed = 25; switch (bus_width)
{
case SDMMC_BUS_WIDTH_4:
storage->csd.busspeed = 25;
break;
case SDMMC_BUS_WIDTH_1:
storage->csd.busspeed = 6;
break;
}
} }
sdmmc_sd_clock_ctrl(sdmmc, 1);
// Parse additional card info from sd status. // Parse additional card info from sd status.
if (_sd_storage_get_ssr(storage, buf)) if (_sd_storage_get_ssr(storage, buf))
{ {
@@ -1222,17 +1317,17 @@ int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc)
memset(storage, 0, sizeof(sdmmc_storage_t)); memset(storage, 0, sizeof(sdmmc_storage_t));
storage->sdmmc = sdmmc; storage->sdmmc = sdmmc;
if (!sdmmc_init(sdmmc, SDMMC_2, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_8, 14, 0)) if (!sdmmc_init(sdmmc, SDMMC_2, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_DDR52, SDMMC_AUTO_CAL_DISABLE))
return 0; return 0;
DPRINTF("[gc] after init\n"); DPRINTF("[gc] after init\n");
usleep(1000 + (10000 + sdmmc->divisor - 1) / sdmmc->divisor); usleep(1000 + (10000 + sdmmc->divisor - 1) / sdmmc->divisor);
if (!sdmmc_config_tuning(storage->sdmmc, 14, MMC_SEND_TUNING_BLOCK_HS200)) if (!sdmmc_tuning_execute(storage->sdmmc, SDHCI_TIMING_MMC_DDR52, MMC_SEND_TUNING_BLOCK_HS200))
return 0; return 0;
DPRINTF("[gc] after tuning\n"); DPRINTF("[gc] after tuning\n");
sdmmc_sd_clock_ctrl(sdmmc, 1); sdmmc_card_clock_ctrl(sdmmc, SDMMC_AUTO_CAL_ENABLE);
return 1; return 1;
} }

View File

@@ -23,6 +23,16 @@
u32 sd_power_cycle_time_start; u32 sd_power_cycle_time_start;
typedef enum _sdmmc_type
{
MMC_SD = 0,
MMC_EMMC = 1,
EMMC_GPP = 0,
EMMC_BOOT0 = 1,
EMMC_BOOT1 = 2
} sdmmc_type;
typedef struct _mmc_cid typedef struct _mmc_cid
{ {
u32 manfid; u32 manfid;
@@ -107,10 +117,10 @@ typedef struct _sdmmc_storage_t
int sdmmc_storage_end(sdmmc_storage_t *storage); int sdmmc_storage_end(sdmmc_storage_t *storage);
int sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf); int sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf);
int sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf); 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_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type);
int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition); int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition);
void sdmmc_storage_init_wait_sd(); 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_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type);
int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc); int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc);
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2019 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -49,24 +50,158 @@
#define SDMMC_MASKINT_NOERROR -1 #define SDMMC_MASKINT_NOERROR -1
#define SDMMC_MASKINT_ERROR -2 #define SDMMC_MASKINT_ERROR -2
/*! SDMMC host control 2 */ /*! SDMMC present state. */
#define SDHCI_CTRL_UHS_MASK 0xFFF8 #define SDHCI_CMD_INHIBIT 0x1
#define SDHCI_CTRL_VDD_330 0xFFF7 #define SDHCI_DATA_INHIBIT 0x2
#define SDHCI_CTRL_VDD_180 8 #define SDHCI_DOING_WRITE 0x100
#define SDHCI_CTRL_EXEC_TUNING 0x40 #define SDHCI_DOING_READ 0x200
#define SDHCI_CTRL_TUNED_CLK 0x80 #define SDHCI_SPACE_AVAILABLE 0x400
#define SDHCI_HOST_VERSION_4_EN 0x1000 #define SDHCI_DATA_AVAILABLE 0x800
#define SDHCI_ADDRESSING_64BIT_EN 0x2000 #define SDHCI_CARD_PRESENT 0x10000
#define SDHCI_CTRL_PRESET_VAL_EN 0x8000 #define SDHCI_CD_STABLE 0x20000
#define SDHCI_CD_LVL 0x40000
#define SDHCI_WRITE_PROTECT 0x80000
#define SDHCI_DATA_LVL_MASK 0xF00000
#define SDHCI_DATA_0_LVL_MASK 0x100000
#define SDHCI_CMD_LVL 0x1000000
/*! SDMMC transfer mode. */
#define SDHCI_TRNS_DMA 0x01
#define SDHCI_TRNS_BLK_CNT_EN 0x02
#define SDHCI_TRNS_AUTO_CMD12 0x04
#define SDHCI_TRNS_AUTO_CMD23 0x08
#define SDHCI_TRNS_AUTO_SEL 0x0C
#define SDHCI_TRNS_WRITE 0x00
#define SDHCI_TRNS_READ 0x10
#define SDHCI_TRNS_MULTI 0x20
/*! SDMMC command. */
#define SDHCI_CMD_RESP_MASK 0x3
#define SDHCI_CMD_RESP_NO_RESP 0x0
#define SDHCI_CMD_RESP_LEN136 0x1
#define SDHCI_CMD_RESP_LEN48 0x2
#define SDHCI_CMD_RESP_LEN48_BUSY 0x3
#define SDHCI_CMD_CRC 0x08
#define SDHCI_CMD_INDEX 0x10
#define SDHCI_CMD_DATA 0x20
#define SDHCI_CMD_ABORTCMD 0xC0
/*! SDMMC host control. */
#define SDHCI_CTRL_LED 0x01
#define SDHCI_CTRL_4BITBUS 0x02
#define SDHCI_CTRL_HISPD 0x04
#define SDHCI_CTRL_DMA_MASK 0x18
#define SDHCI_CTRL_SDMA 0x00
#define SDHCI_CTRL_ADMA1 0x08
#define SDHCI_CTRL_ADMA32 0x10
#define SDHCI_CTRL_ADMA64 0x18
#define SDHCI_CTRL_8BITBUS 0x20
#define SDHCI_CTRL_CDTEST_INS 0x40
#define SDHCI_CTRL_CDTEST_EN 0x80
/*! SDMMC host control 2. */
#define SDHCI_CTRL_UHS_MASK 0xFFF8
#define SDHCI_CTRL_VDD_180 8
#define SDHCI_CTRL_DRV_TYPE_B 0x00
#define SDHCI_CTRL_DRV_TYPE_A 0x10
#define SDHCI_CTRL_DRV_TYPE_C 0x20
#define SDHCI_CTRL_DRV_TYPE_D 0x30
#define SDHCI_CTRL_EXEC_TUNING 0x40
#define SDHCI_CTRL_TUNED_CLK 0x80
#define SDHCI_HOST_VERSION_4_EN 0x1000
#define SDHCI_ADDRESSING_64BIT_EN 0x2000
#define SDHCI_CTRL_PRESET_VAL_EN 0x8000
/*! SDMMC power control. */
#define SDHCI_POWER_ON 0x01
#define SDHCI_POWER_180 0x0A
#define SDHCI_POWER_300 0x0C
#define SDHCI_POWER_330 0x0E
#define SDHCI_POWER_MASK 0xF1
// /*! SDMMC max current. */
// #define SDHCI_MAX_CURRENT_330_MASK 0xFF
// #define SDHCI_MAX_CURRENT_180_MASK 0xFF0000
// #define SDHCI_MAX_CURRENT_MULTIPLIER 4
/*! SDMMC clock control. */
#define SDHCI_DIVIDER_SHIFT 8
#define SDHCI_DIVIDER_HI_SHIFT 6
#define SDHCI_DIV_MASK 0xFF00
#define SDHCI_DIV_HI_MASK 0xC0
#define SDHCI_PROG_CLOCK_MODE 0x20
#define SDHCI_CLOCK_CARD_EN 0x4
#define SDHCI_CLOCK_INT_STABLE 0x2
#define SDHCI_CLOCK_INT_EN 0x1
/*! SDMMC software reset. */
#define SDHCI_RESET_ALL 0x01
#define SDHCI_RESET_CMD 0x02
#define SDHCI_RESET_DATA 0x04
/*! SDMMC interrupt status and control. */
#define SDHCI_INT_RESPONSE 0x1
#define SDHCI_INT_DATA_END 0x2
#define SDHCI_INT_BLK_GAP 0x4
#define SDHCI_INT_DMA_END 0x8
#define SDHCI_INT_SPACE_AVAIL 0x10
#define SDHCI_INT_DATA_AVAIL 0x20
#define SDHCI_INT_CARD_INSERT 0x40
#define SDHCI_INT_CARD_REMOVE 0x80
#define SDHCI_INT_CARD_INT 0x100
#define SDHCI_INT_RETUNE 0x1000
#define SDHCI_INT_CQE 0x4000
#define SDHCI_INT_ERROR 0x8000
/*! SDMMC error interrupt status and control. */
#define SDHCI_ERR_INT_TIMEOUT 0x1
#define SDHCI_ERR_INT_CRC 0x2
#define SDHCI_ERR_INT_END_BIT 0x4
#define SDHCI_ERR_INT_INDEX 0x8
#define SDHCI_ERR_INT_DATA_TIMEOUT 0x10
#define SDHCI_ERR_INT_DATA_CRC 0x20
#define SDHCI_ERR_INT_DATA_END_BIT 0x40
#define SDHCI_ERR_INT_BUS_POWER 0x80
#define SDHCI_ERR_INT_AUTO_CMD_ERR 0x100
#define SDHCI_ERR_INT_ADMA_ERROR 0x200
#define SDHCI_ERR_INT_ALL_EXCEPT_ADMA_BUSPWR \
(SDHCI_ERR_INT_AUTO_CMD_ERR | SDHCI_ERR_INT_DATA_END_BIT | \
SDHCI_ERR_INT_DATA_CRC | SDHCI_ERR_INT_DATA_TIMEOUT | \
SDHCI_ERR_INT_INDEX | SDHCI_ERR_INT_END_BIT | \
SDHCI_ERR_INT_CRC | SDHCI_ERR_INT_TIMEOUT)
/*! SD bus speeds. */ /*! SD bus speeds. */
#define UHS_SDR12_BUS_SPEED 0 #define UHS_SDR12_BUS_SPEED 0
#define HIGH_SPEED_BUS_SPEED 1 #define HIGH_SPEED_BUS_SPEED 1
#define UHS_SDR25_BUS_SPEED 1 #define UHS_SDR25_BUS_SPEED 1
#define UHS_SDR50_BUS_SPEED 2 #define UHS_SDR50_BUS_SPEED 2
#define UHS_SDR104_BUS_SPEED 3 #define UHS_SDR104_BUS_SPEED 3
#define UHS_DDR50_BUS_SPEED 4 #define UHS_DDR50_BUS_SPEED 4
#define HS400_BUS_SPEED 5 #define HS400_BUS_SPEED 5
/*! SDMMC timmings. */
#define SDHCI_TIMING_MMC_ID 0
#define SDHCI_TIMING_MMC_LS26 1
#define SDHCI_TIMING_MMC_HS52 2
#define SDHCI_TIMING_MMC_HS200 3
#define SDHCI_TIMING_MMC_HS400 4
#define SDHCI_TIMING_SD_ID 5
#define SDHCI_TIMING_SD_DS12 6
#define SDHCI_TIMING_SD_HS25 7
#define SDHCI_TIMING_UHS_SDR12 8
#define SDHCI_TIMING_UHS_SDR25 9
#define SDHCI_TIMING_UHS_SDR50 10
#define SDHCI_TIMING_UHS_SDR104 11
#define SDHCI_TIMING_UHS_SDR82 12 // SDR104 with a 163.2MHz -> 81.6MHz clock.
#define SDHCI_TIMING_UHS_DDR50 13
#define SDHCI_TIMING_MMC_DDR52 14
#define SDHCI_CAN_64BIT 0x10000000
/*! SDMMC Low power features. */
#define SDMMC_AUTO_CAL_DISABLE 0
#define SDMMC_AUTO_CAL_ENABLE 1
/*! Helper for SWITCH command argument. */ /*! Helper for SWITCH command argument. */
#define SDMMC_SWITCH(mode, index, value) (((mode) << 24) | ((index) << 16) | ((value) << 8)) #define SDMMC_SWITCH(mode, index, value) (((mode) << 24) | ((index) << 16) | ((value) << 8))
@@ -78,8 +213,8 @@ typedef struct _sdmmc_t
u32 id; u32 id;
u32 divisor; u32 divisor;
u32 clock_stopped; u32 clock_stopped;
int no_sd; int auto_cal_enabled;
int sd_clock_enabled; int card_clock_enabled;
int venclkctl_set; int venclkctl_set;
u32 venclkctl_tap; u32 venclkctl_tap;
u32 expected_rsp_type; u32 expected_rsp_type;
@@ -108,19 +243,20 @@ typedef struct _sdmmc_req_t
int is_auto_cmd12; int is_auto_cmd12;
} sdmmc_req_t; } sdmmc_req_t;
int sdmmc_get_voltage(sdmmc_t *sdmmc); int sdmmc_get_io_power(sdmmc_t *sdmmc);
u32 sdmmc_get_bus_width(sdmmc_t *sdmmc); u32 sdmmc_get_bus_width(sdmmc_t *sdmmc);
void sdmmc_set_bus_width(sdmmc_t *sdmmc, u32 bus_width); void sdmmc_set_bus_width(sdmmc_t *sdmmc, u32 bus_width);
void sdmmc_get_venclkctl(sdmmc_t *sdmmc); void sdmmc_set_tap_value(sdmmc_t *sdmmc);
int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type); int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type);
void sdmmc_sd_clock_ctrl(sdmmc_t *sdmmc, int no_sd); void sdmmc_card_clock_ctrl(sdmmc_t *sdmmc, int auto_cal_enable);
int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type); int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type);
int sdmmc_config_tuning(sdmmc_t *sdmmc, u32 type, u32 cmd); int sdmmc_tuning_execute(sdmmc_t *sdmmc, u32 type, u32 cmd);
int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp); int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp);
int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int no_sd); bool sdmmc_get_sd_inserted();
int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int auto_cal_enable);
void sdmmc_end(sdmmc_t *sdmmc); void sdmmc_end(sdmmc_t *sdmmc);
void sdmmc_init_cmd(sdmmc_cmd_t *cmdbuf, u16 cmd, u32 arg, u32 rsp_type, u32 check_busy); void sdmmc_init_cmd(sdmmc_cmd_t *cmdbuf, u16 cmd, u32 arg, u32 rsp_type, u32 check_busy);
int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *blkcnt_out); int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *blkcnt_out);
int sdmmc_enable_low_voltage(sdmmc_t *sdmmc); int sdmmc_enable_low_voltage(sdmmc_t *sdmmc);
#endif #endif

View File

@@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2019 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -19,49 +20,14 @@
#include "../utils/types.h" #include "../utils/types.h"
#define TEGRA_MMC_PWRCTL_SD_BUS_POWER 0x1 #define TEGRA_MMC_VNDR_TUN_CTRL0_TAP_VAL_UPDATED_BY_HW 0x20000
#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8 0xA #define TEGRA_MMC_DLLCAL_CFG_EN_CALIBRATE 0x80000000
#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_0 0xC #define TEGRA_MMC_DLLCAL_CFG_STATUS_DLL_ACTIVE 0x80000000
#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3 0xE #define TEGRA_MMC_SDMEMCOMPPADCTRL_PAD_E_INPUT_PWRD 0x80000000
#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_MASK 0xF1 #define TEGRA_MMC_SDMEMCOMPPADCTRL_COMP_VREF_SEL_MASK 0xFFFFFFF0
#define TEGRA_MMC_AUTOCALCFG_AUTO_CAL_ENABLE 0x20000000
#define TEGRA_MMC_HOSTCTL_1BIT 0x00 #define TEGRA_MMC_AUTOCALCFG_AUTO_CAL_START 0x80000000
#define TEGRA_MMC_HOSTCTL_4BIT 0x02 #define TEGRA_MMC_AUTOCALSTS_AUTO_CAL_ACTIVE 0x80000000
#define TEGRA_MMC_HOSTCTL_8BIT 0x20
#define TEGRA_MMC_CLKCON_INTERNAL_CLOCK_ENABLE 0x1
#define TEGRA_MMC_CLKCON_INTERNAL_CLOCK_STABLE 0x2
#define TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE 0x4
#define TEGRA_MMC_CLKCON_CLKGEN_SELECT 0x20
#define TEGRA_MMC_SWRST_SW_RESET_FOR_ALL 0x1
#define TEGRA_MMC_SWRST_SW_RESET_FOR_CMD_LINE 0x2
#define TEGRA_MMC_SWRST_SW_RESET_FOR_DAT_LINE 0x4
#define TEGRA_MMC_TRNMOD_DMA_ENABLE 0x1
#define TEGRA_MMC_TRNMOD_BLOCK_COUNT_ENABLE 0x2
#define TEGRA_MMC_TRNMOD_AUTO_CMD12 0x4
#define TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_WRITE 0x0
#define TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ 0x10
#define TEGRA_MMC_TRNMOD_MULTI_BLOCK_SELECT 0x20
#define TEGRA_MMC_TRNMOD_CMD_CRC_CHECK 0x8
#define TEGRA_MMC_TRNMOD_CMD_INDEX_CHECK 0x10
#define TEGRA_MMC_TRNMOD_DATA_PRESENT_SELECT_DATA_TRANSFER 0x20
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_MASK 0x3
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_NO_RESPONSE 0x0
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_136 0x1
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48 0x2
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48_BUSY 0x3
#define TEGRA_MMC_NORINTSTS_CMD_COMPLETE 0x1
#define TEGRA_MMC_NORINTSTS_XFER_COMPLETE 0x2
#define TEGRA_MMC_NORINTSTS_DMA_INTERRUPT 0x8
#define TEGRA_MMC_NORINTSTS_ERR_INTERRUPT 0x8000
#define TEGRA_MMC_NORINTSTS_CMD_TIMEOUT 0x10000
#define TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY 0x20
typedef struct _t210_sdmmc_t typedef struct _t210_sdmmc_t
{ {
@@ -77,56 +43,66 @@ typedef struct _t210_sdmmc_t
vu32 rspreg3; vu32 rspreg3;
vu32 bdata; vu32 bdata;
vu32 prnsts; vu32 prnsts;
vu8 hostctl; vu8 hostctl;
vu8 pwrcon; vu8 pwrcon;
vu8 blkgap; vu8 blkgap;
vu8 wakcon; vu8 wakcon;
vu16 clkcon; vu16 clkcon;
vu8 timeoutcon; vu8 timeoutcon;
vu8 swrst; vu8 swrst;
vu16 norintsts; vu16 norintsts;
vu16 errintsts; vu16 errintsts;
vu16 norintstsen; vu16 norintstsen; // Enable irq status.
vu16 errintstsen; vu16 errintstsen; // Enable irq status.
vu16 norintsigen; vu16 norintsigen; // Enable irq signal to LIC/GIC.
vu16 errintsigen; vu16 errintsigen; // Enable irq signal to LIC/GIC.
vu16 acmd12errsts; vu16 acmd12errsts;
vu16 hostctl2; vu16 hostctl2;
vu32 capareg; vu32 capareg;
vu32 capareg_1; vu32 capareg_1;
vu32 maxcurr; vu32 maxcurr;
vu8 res3[4]; vu8 rsvd0[4]; // 4C-4F reserved for more max current.
vu16 setacmd12err; vu16 setacmd12err;
vu16 setinterr; vu16 setinterr;
vu8 admaerr; vu8 admaerr;
vu8 res4[3]; vu8 rsvd1[3]; // 55-57 reserved.
vu32 admaaddr; vu32 admaaddr;
vu32 admaaddr_hi; vu32 admaaddr_hi;
vu8 res5[156]; vu8 rsvd2[156]; // 60-FB reserved.
vu16 slotintstatus; vu16 slotintsts;
vu16 hcver; vu16 hcver;
vu32 venclkctl; vu32 venclkctl;
vu32 venspictl; vu32 vensysswctl;
vu32 venspiintsts; vu32 venerrintsts;
vu32 venceatactl; vu32 vencapover;
vu32 venbootctl; vu32 venbootctl;
vu32 venbootacktout; vu32 venbootacktout;
vu32 venbootdattout; vu32 venbootdattout;
vu32 vendebouncecnt; vu32 vendebouncecnt;
vu32 venmiscctl; vu32 venmiscctl;
vu32 res6[34]; vu32 maxcurrover;
vu32 maxcurrover_hi;
vu32 unk0[32]; // 0x12C
vu32 veniotrimctl; vu32 veniotrimctl;
vu32 vendllcal; vu32 vendllcalcfg;
vu8 res7[8]; vu32 vendllctl0;
vu32 dllcfgstatus; vu32 vendllctl1;
vu32 vendllcalcfgsts;
vu32 ventunctl0; vu32 ventunctl0;
vu32 field_1C4; vu32 ventunctl1;
vu8 field_1C8[24]; vu32 ventunsts0;
vu32 ventunsts1;
vu32 venclkgatehystcnt;
vu32 venpresetval0;
vu32 venpresetval1;
vu32 venpresetval2;
vu32 sdmemcmppadctl; vu32 sdmemcmppadctl;
vu32 autocalcfg; vu32 autocalcfg;
vu32 autocalintval; vu32 autocalintval;
vu32 autocalsts; vu32 autocalsts;
vu32 iospare; vu32 iospare;
vu32 mcciffifoctl;
vu32 timeoutwcoal;
} t210_sdmmc_t; } t210_sdmmc_t;
#endif #endif

View File

@@ -5,7 +5,7 @@ extern const char *gfx_file_size_names[];
extern const char *menu_sd_states[]; extern const char *menu_sd_states[];
extern const char *emmc_fs_entries[]; extern const char *emmc_fs_entries[];
extern const char *utils_err_codes[]; extern const char *utils_err_codes[];
extern const char *pkg2names[]; //extern const char *pkg2names[];
extern const char *mainmenu_credits; extern const char *mainmenu_credits;
enum utils_err_codes_te_call { enum utils_err_codes_te_call {
@@ -23,7 +23,7 @@ enum utils_err_codes_te_call {
ERR_SD_EJECTED, ERR_SD_EJECTED,
ERR_PARSE_FAIL, ERR_PARSE_FAIL,
ERR_CANNOT_COPY_FILE_TO_FS_PART, ERR_CANNOT_COPY_FILE_TO_FS_PART,
ERR_NO_DESTENATION ERR_NO_DESTINATION
}; };
extern const char *utils_err_codes_te[]; extern const char *utils_err_codes_te[];
@@ -81,6 +81,7 @@ extern menu_entry utils_mmcChoice[];
enum fs_menu_file_return { enum fs_menu_file_return {
FILE_COPY = 4, FILE_COPY = 4,
FILE_MOVE, FILE_MOVE,
FILE_RENAME,
FILE_DELETE, FILE_DELETE,
FILE_PAYLOAD, FILE_PAYLOAD,
FILE_SCRIPT, FILE_SCRIPT,
@@ -93,7 +94,9 @@ extern menu_entry fs_menu_file[];
enum fs_menu_folder_return { enum fs_menu_folder_return {
DIR_EXITFOLDER = 2, DIR_EXITFOLDER = 2,
DIR_COPYFOLDER, DIR_COPYFOLDER,
DIR_DELETEFOLDER DIR_DELETEFOLDER,
DIR_RENAME,
DIR_CREATE
}; };
extern menu_entry fs_menu_folder[]; extern menu_entry fs_menu_folder[];

View File

@@ -52,9 +52,9 @@ const char *utils_err_codes_te[] = { // these start at 50
"SD EJECTED", "SD EJECTED",
"PARSING FAILED", "PARSING FAILED",
"CANNOT COPY FILE TO FS PART", "CANNOT COPY FILE TO FS PART",
"NO DESTENATION" "NO DESTINATION"
}; };
/*
const char *pkg2names[] = { const char *pkg2names[] = {
"BCPKG2-1-Normal-Main", "BCPKG2-1-Normal-Main",
"BCPKG2-2-Normal-Sub", "BCPKG2-2-Normal-Sub",
@@ -63,5 +63,5 @@ const char *pkg2names[] = {
"BCPKG2-5-Repair-Main", "BCPKG2-5-Repair-Main",
"BCPKG2-6-Repair-Sub" "BCPKG2-6-Repair-Sub"
}; };
*/
const char *mainmenu_credits = "\nTegraexplorer, made by:\nSuch Meme, Many Skill\n\nProject based on:\nLockpick_RCM\nHekate\n\nCool people:\nshchmue\ndennthecafebabe\nDax"; const char *mainmenu_credits = "\nTegraexplorer, made by:\nSuch Meme, Many Skill\n\nProject based on:\nLockpick_RCM\nHekate\n\nCool people:\nshchmue\ndennthecafebabe\nDax";

View File

@@ -2,71 +2,74 @@
#include "types.h" #include "types.h"
menu_entry mainmenu_main[] = { menu_entry mainmenu_main[] = {
{"[SD:/] SD CARD", COLOR_GREEN, ISMENU}, {"[SD:/] SD CARD", COLOR_GREEN, {ISMENU}},
{"[EMMC:/] EMMC", COLOR_ORANGE, ISMENU}, {"[EMMC:/] EMMC", COLOR_ORANGE, {ISMENU}},
{"[EMMC:/] EMUMMC", COLOR_BLUE, ISMENU}, {"[EMMC:/] EMUMMC", COLOR_BLUE, {ISMENU}},
{"\nMount/Unmount SD", COLOR_WHITE, ISMENU}, {"\nMount/Unmount SD", COLOR_WHITE, {ISMENU}},
{"Tools", COLOR_VIOLET, ISMENU}, {"Tools", COLOR_VIOLET, {ISMENU}},
{"SD format", COLOR_VIOLET, ISMENU}, {"SD format", COLOR_VIOLET, {ISMENU}},
{"\nCredits", COLOR_WHITE, ISMENU}, {"\nCredits", COLOR_WHITE, {ISMENU}},
{"Exit", COLOR_WHITE, ISMENU} {"Exit", COLOR_WHITE, {ISMENU}}
}; };
menu_entry mainmenu_shutdown[] = { menu_entry mainmenu_shutdown[] = {
{"Back", COLOR_WHITE, ISMENU}, {"Back", COLOR_WHITE, {ISMENU}},
{"\nReboot to RCM", COLOR_VIOLET, ISMENU}, {"\nReboot to RCM", COLOR_VIOLET, {ISMENU}},
{"Reboot normally", COLOR_ORANGE, ISMENU}, {"Reboot normally", COLOR_ORANGE, {ISMENU}},
{"Power off\n", COLOR_BLUE, ISMENU}, {"Power off\n", COLOR_BLUE, {ISMENU}},
{"Reboot to Hekate", COLOR_GREEN, ISMENU}, {"Reboot to Hekate", COLOR_GREEN, {ISMENU}},
{"Reboot to Atmosphere", COLOR_GREEN, ISMENU} {"Reboot to Atmosphere", COLOR_GREEN, {ISMENU}}
}; };
menu_entry mainmenu_tools[] = { menu_entry mainmenu_tools[] = {
{"Back", COLOR_WHITE, ISMENU}, {"Back", COLOR_WHITE, {ISMENU}},
{"\nDisplay Console Info", COLOR_GREEN, ISMENU}, {"\nDisplay Console Info", COLOR_GREEN, {ISMENU}},
{"Display GPIO pins", COLOR_VIOLET, ISMENU}, {"Display GPIO pins", COLOR_VIOLET, {ISMENU}},
{"Dump Firmware", COLOR_BLUE, ISMENU}, {"Dump Firmware", COLOR_BLUE, {ISMENU}},
{"Dump User Saves", COLOR_YELLOW, ISMENU} {"Dump User Saves", COLOR_YELLOW, {ISMENU}}
}; };
menu_entry mainmenu_format[] = { menu_entry mainmenu_format[] = {
{"Back\n", COLOR_WHITE, ISMENU}, {"Back\n", COLOR_WHITE, {ISMENU}},
{"Format entire SD to FAT32", COLOR_RED, ISMENU}, {"Format entire SD to FAT32", COLOR_RED, {ISMENU}},
{"Format for EmuMMC setup (FAT32/RAW)", COLOR_RED, ISMENU} {"Format for EmuMMC setup (FAT32/RAW)", COLOR_RED, {ISMENU}}
}; };
menu_entry utils_mmcChoice[] = { menu_entry utils_mmcChoice[] = {
{"Back\n", COLOR_WHITE, ISMENU}, {"Back\n", COLOR_WHITE, {ISMENU}},
{"SysMMC", COLOR_ORANGE, ISMENU}, {"SysMMC", COLOR_ORANGE, {ISMENU}},
{"EmuMMC", COLOR_BLUE, ISMENU} {"EmuMMC", COLOR_BLUE, {ISMENU}}
}; };
menu_entry fs_menu_file[] = { menu_entry fs_menu_file[] = {
{NULL, COLOR_GREEN, ISMENU | ISSKIP}, {NULL, COLOR_GREEN, {ISMENU | ISSKIP}},
{NULL, COLOR_VIOLET, ISMENU | ISSKIP}, {NULL, COLOR_VIOLET, {ISMENU | ISSKIP}},
{NULL, COLOR_VIOLET, ISMENU | ISSKIP}, {NULL, COLOR_VIOLET, {ISMENU | ISSKIP}},
{"\n\n\nBack", COLOR_WHITE, ISMENU}, {"\n\n\nBack", COLOR_WHITE, {ISMENU}},
{"\nCopy to clipboard", COLOR_BLUE, ISMENU}, {"\nCopy to clipboard", COLOR_BLUE, {ISMENU}},
{"Move to clipboard", COLOR_BLUE, ISMENU}, {"Move to clipboard", COLOR_BLUE, {ISMENU}},
{"\nDelete file\n", COLOR_RED, ISMENU}, {"Rename file", COLOR_BLUE, {ISMENU}},
{"Launch Payload", COLOR_ORANGE, ISMENU}, {"\nDelete file\n", COLOR_RED, {ISMENU}},
{"Launch Script", COLOR_YELLOW, ISMENU}, {"Launch Payload", COLOR_ORANGE, {ISMENU}},
{"View Hex", COLOR_GREEN, ISMENU}, {"Launch Script", COLOR_YELLOW, {ISMENU}},
{"\nExtract BIS", COLOR_YELLOW, ISMENU} {"View Hex", COLOR_GREEN, {ISMENU}},
{"\nExtract BIS", COLOR_YELLOW, {ISMENU}}
}; };
menu_entry fs_menu_folder[] = { menu_entry fs_menu_folder[] = {
{NULL, COLOR_VIOLET, ISMENU | ISSKIP}, {NULL, COLOR_VIOLET, {ISMENU | ISSKIP}},
{"\nBack", COLOR_WHITE, ISMENU}, {"\nBack", COLOR_WHITE, {ISMENU}},
{"Return to main menu\n", COLOR_BLUE, ISMENU}, {"Return to main menu\n", COLOR_BLUE, {ISMENU}},
{"Copy to clipboard", COLOR_VIOLET, ISMENU}, {"Copy to clipboard", COLOR_VIOLET, {ISMENU}},
{"Delete folder", COLOR_RED, ISMENU} {"Delete folder\n", COLOR_RED, {ISMENU}},
{"Rename folder", COLOR_BLUE, {ISMENU}},
{"Create folder", COLOR_BLUE, {ISMENU}}
}; };
menu_entry fs_menu_startdir[] = { menu_entry fs_menu_startdir[] = {
{"Folder -> previous folder ", COLOR_ORANGE, ISMENU}, {"Folder -> previous folder ", COLOR_ORANGE, {ISMENU}},
{"Clipboard -> Current folder ", COLOR_ORANGE, ISMENU}, {"Clipboard -> Current folder", COLOR_ORANGE, {ISMENU}},
{"Current folder menu ", COLOR_ORANGE, ISMENU} {"Current folder menu ", COLOR_ORANGE, {ISMENU}}
}; };
gpt_entry_rule gpt_fs_rules[] = { gpt_entry_rule gpt_fs_rules[] = {
@@ -78,15 +81,15 @@ gpt_entry_rule gpt_fs_rules[] = {
}; };
menu_entry mmcmenu_start[] = { menu_entry mmcmenu_start[] = {
{"Back", COLOR_ORANGE, ISMENU}, {"Back", COLOR_ORANGE, {ISMENU}},
{"Dump File Partitions", COLOR_ORANGE, ISMENU}, {"Dump File Partitions", COLOR_ORANGE, {ISMENU}},
{"Clipboard -> Partition\n", COLOR_ORANGE, ISMENU}, {"Clipboard -> Partition\n", COLOR_ORANGE, {ISMENU}},
{"BOOT0/1", COLOR_BLUE, isBOOT | ISMENU} {"BOOT0/1", COLOR_BLUE, {ISNULL | ISMENU}}
}; };
menu_entry mmcmenu_filemenu[] = { menu_entry mmcmenu_filemenu[] = {
{"Part:", COLOR_ORANGE, ISSKIP | ISMENU}, {"Part:", COLOR_ORANGE, {ISSKIP | ISMENU}},
{NULL, COLOR_VIOLET, ISSKIP | ISMENU}, {NULL, COLOR_VIOLET, {ISSKIP | ISMENU}},
{"\nBack", COLOR_WHITE, ISMENU}, {"\nBack", COLOR_WHITE, {ISMENU}},
{"Dump to SD", COLOR_YELLOW, ISMENU} {"Dump to SD", COLOR_YELLOW, {ISMENU}}
}; };

View File

@@ -1,17 +1,14 @@
#pragma once #pragma once
#include "../../utils/types.h" #include "../../utils/types.h"
#define ISDIR (1 << 0) #define BIT(n) (1U << n)
#define ISARC (1 << 1)
#define ISHIDE (1 << 8) #define ISDIR BIT(0)
#define ISMENU (1 << 9) #define ISMENU BIT(1)
#define ISSKIP (1 << 10) #define SETSIZE(x) (x << 2)
#define ISNULL BIT(4)
#define ISGB (1 << 7) #define ISHIDE BIT(5)
#define ISMB (1 << 6) #define ISSKIP BIT(6)
#define ISKB (1 << 5)
#define ISB (1 << 4)
#define SETBIT(object, shift, value) ((value) ? (object |= shift) : (object &= ~shift)) #define SETBIT(object, shift, value) ((value) ? (object |= shift) : (object &= ~shift))
@@ -26,7 +23,7 @@
#define COPY_MODE_PRINT 0x1 #define COPY_MODE_PRINT 0x1
#define COPY_MODE_CANCEL 0x2 #define COPY_MODE_CANCEL 0x2
#define BUFSIZE 32768 #define BUFSIZE 65536 //32768
#define OPERATIONCOPY 0x2 #define OPERATIONCOPY 0x2
#define OPERATIONMOVE 0x4 #define OPERATIONMOVE 0x4
@@ -42,7 +39,17 @@
typedef struct { typedef struct {
char *name; char *name;
u32 storage; u32 storage;
u16 property; union {
u8 property;
struct {
u8 isDir:1;
u8 isMenu:1;
u8 size:2;
u8 isNull:1;
u8 isHide:1;
u8 isSkip:1;
};
};
} menu_entry; } menu_entry;
typedef struct { typedef struct {

View File

@@ -4,7 +4,6 @@
#include "../../utils/types.h" #include "../../utils/types.h"
#include "../../libs/fatfs/ff.h" #include "../../libs/fatfs/ff.h"
#include "../../utils/sprintf.h" #include "../../utils/sprintf.h"
#include "../../utils/btn.h"
#include "../../gfx/gfx.h" #include "../../gfx/gfx.h"
#include "../../utils/util.h" #include "../../utils/util.h"
#include "../../hos/pkg1.h" #include "../../hos/pkg1.h"
@@ -100,7 +99,7 @@ void connect_mmc(short mmctype){
h_cfg.emummc_force_disable = 0; h_cfg.emummc_force_disable = 0;
switch (mmctype){ switch (mmctype){
case SYSMMC: case SYSMMC:
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4); sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400);
h_cfg.emummc_force_disable = 1; h_cfg.emummc_force_disable = 1;
currentlyMounted = SYSMMC; currentlyMounted = SYSMMC;
break; break;
@@ -139,6 +138,7 @@ int dump_biskeys(){
u8 *pkg1 = (u8 *)malloc(0x40000); u8 *pkg1 = (u8 *)malloc(0x40000);
sdmmc_storage_set_mmc_partition(&storage, 1); sdmmc_storage_set_mmc_partition(&storage, 1);
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1); sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
strncpy(pkg1inf.id, pkg1 + 0x10, 14);
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1); const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
if (!pkg1_id) { if (!pkg1_id) {
EPRINTF("Unknown pkg1 version."); EPRINTF("Unknown pkg1 version.");
@@ -215,8 +215,9 @@ int dump_biskeys(){
memcpy(bis_key[3], bis_key[2], 0x20); memcpy(bis_key[3], bis_key[2], 0x20);
} }
sdmmc_storage_set_mmc_partition(&storage, 0); //sdmmc_storage_set_mmc_partition(&storage, 0);
nx_emmc_gpt_parse(&sys_gpt, &storage); //nx_emmc_gpt_parse(&sys_gpt, &storage);
se_aes_key_set(8, bis_key[2] + 0x00, 0x10); se_aes_key_set(8, bis_key[2] + 0x00, 0x10);
se_aes_key_set(9, bis_key[2] + 0x10, 0x10); se_aes_key_set(9, bis_key[2] + 0x10, 0x10);
@@ -226,10 +227,16 @@ int dump_biskeys(){
return 0; return 0;
} }
void dumpEmuGpt(){ void dumpGpt(){
connect_mmc(EMUMMC); connect_mmc(SYSMMC);
emummc_storage_set_mmc_partition(&storage, 0); sdmmc_storage_set_mmc_partition(&storage, 0);
nx_emmc_gpt_parse(&emu_gpt, &storage); nx_emmc_gpt_parse(&sys_gpt, &storage);
if (emu_cfg.enabled){
connect_mmc(EMUMMC);
emummc_storage_set_mmc_partition(&storage, 0);
nx_emmc_gpt_parse(&emu_gpt, &storage);
}
} }
link_t *selectGpt(short mmcType){ link_t *selectGpt(short mmcType){

View File

@@ -16,7 +16,7 @@ int mount_mmc(const char *partition, const int biskeynumb);
void connect_mmc(short mmctype); void connect_mmc(short mmctype);
void disconnect_mmc(); void disconnect_mmc();
int connect_part(const char *partition); int connect_part(const char *partition);
void dumpEmuGpt(); void dumpGpt();
link_t *selectGpt(short mmcType); link_t *selectGpt(short mmcType);
int checkGptRules(char *in); int checkGptRules(char *in);

View File

@@ -8,7 +8,6 @@
#include "../common/common.h" #include "../common/common.h"
#include "../../libs/fatfs/ff.h" #include "../../libs/fatfs/ff.h"
#include "../../utils/sprintf.h" #include "../../utils/sprintf.h"
#include "../../utils/btn.h"
#include "../../mem/heap.h" #include "../../mem/heap.h"
#include "../../storage/nx_emmc.h" #include "../../storage/nx_emmc.h"
#include "../common/types.h" #include "../common/types.h"
@@ -46,7 +45,7 @@ int emmcDumpPart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part){
f_lseek(&fp, 0); f_lseek(&fp, 0);
while (totalSectors > 0){ while (totalSectors > 0){
num = MIN(totalSectors, 64); num = MIN(totalSectors, 128);
if (!emummc_storage_read(mmcstorage, lba_curr, num, buf)){ if (!emummc_storage_read(mmcstorage, lba_curr, num, buf)){
gfx_errDisplay("dump_emmc_part", ERR_EMMC_READ_FAILED, 3); gfx_errDisplay("dump_emmc_part", ERR_EMMC_READ_FAILED, 3);
return -1; return -1;
@@ -72,8 +71,8 @@ int existsCheck(char *path){
int res = 0; int res = 0;
if (fsutil_checkfile(path)){ if (fsutil_checkfile(path)){
gfx_printf("File already exists! Overwrite?\nVol +/- to cancel\n"); gfx_printf("File already exists! Overwrite?\nBto cancel\n");
res = gfx_makewaitmenu("Power to continue", 3); res = gfx_makewaitmenu("A to continue", 3);
gfx_printf("\r \r"); gfx_printf("\r \r");
return res; return res;
} }

View File

@@ -3,7 +3,7 @@
#include "../../mem/heap.h" #include "../../mem/heap.h"
#include "../../utils/types.h" #include "../../utils/types.h"
#include "../../libs/fatfs/ff.h" #include "../../libs/fatfs/ff.h"
#include "../../utils/btn.h" #include "../../hid/hid.h"
#include "../../gfx/gfx.h" #include "../../gfx/gfx.h"
#include "../../utils/util.h" #include "../../utils/util.h"
#include "../../storage/nx_emmc.h" #include "../../storage/nx_emmc.h"
@@ -16,12 +16,12 @@
#include "../../utils/list.h" #include "../../utils/list.h"
#include "../../mem/heap.h" #include "../../mem/heap.h"
#include "emmcmenu.h" #include "emmcmenu.h"
#include "../fs/fsreader.h"
#include "../utils/utils.h" #include "../utils/utils.h"
#include "../gfx/menu.h" #include "../gfx/menu.h"
#include "../fs/fsmenu.h" #include "../fs/fsmenu.h"
#include "emmcoperations.h" #include "emmcoperations.h"
#include "../fs/fsutils.h" #include "../fs/fsutils.h"
#include "../utils/menuUtils.h"
menu_entry *mmcMenuEntries = NULL; menu_entry *mmcMenuEntries = NULL;
extern sdmmc_storage_t storage; extern sdmmc_storage_t storage;
@@ -30,22 +30,20 @@ extern char *clipboard;
extern u8 clipboardhelper; extern u8 clipboardhelper;
void addEntry(emmc_part_t *part, u8 property, int spot){ void addEntry(emmc_part_t *part, u8 property_GPT, int spot){
if (mmcMenuEntries[spot].name != NULL){ u32 storage = 0;
free(mmcMenuEntries[spot].name); u8 property = 0;
}
utils_copystring(part->name, &mmcMenuEntries[spot].name); if (property_GPT & isFS){
storage = (u32)(property_GPT & 0x7F);
if (property & isFS){ property = ISDIR;
mmcMenuEntries[spot].storage = (u32)(property & 0x7F);
mmcMenuEntries[spot].property = ISDIR;
} }
else { else {
u64 size = 0; u64 size = 0;
int sizes = 0; u32 sizes = 0;
mmcMenuEntries[spot].property = 0;
size = (part->lba_end + 1 - part->lba_start) * NX_EMMC_BLOCKSIZE; size = (u64)(part->lba_end + 1 - part->lba_start);
size *= (u64)NX_EMMC_BLOCKSIZE;
while (size > 1024){ while (size > 1024){
size /= 1024; size /= 1024;
@@ -53,31 +51,30 @@ void addEntry(emmc_part_t *part, u8 property, int spot){
} }
if (sizes > 3) if (sizes > 3)
sizes = 0; sizes = 3;
mmcMenuEntries[spot].property |= (1 << (4 + sizes)); property |= SETSIZE(sizes);
mmcMenuEntries[spot].storage = (u32)size; storage = (u32)size;
} }
mu_copySingle(part->name, storage, property, &mmcMenuEntries[spot]);
} }
int fillMmcMenu(short mmcType){ int fillMmcMenu(short mmcType){
int count = 4, i; int count = 4, i;
if (mmcMenuEntries != NULL) if (mmcMenuEntries != NULL)
clearfileobjects(&mmcMenuEntries); mu_clearObjects(&mmcMenuEntries);
link_t *gpt = selectGpt(mmcType); link_t *gpt = selectGpt(mmcType);
LIST_FOREACH_ENTRY(emmc_part_t, part, gpt, link) LIST_FOREACH_ENTRY(emmc_part_t, part, gpt, link)
count++; count++;
createfileobjects(count, &mmcMenuEntries); mu_createObjects(count, &mmcMenuEntries);
for (i = 0; i < 4; i++){ for (i = 0; i < 4; i++)
utils_copystring(mmcmenu_start[i].name, &mmcMenuEntries[i].name); mu_copySingle(mmcmenu_start[i].name, mmcmenu_start[i].storage, mmcmenu_start[i].property, &mmcMenuEntries[i]);
mmcMenuEntries[i].property = mmcmenu_start[i].property;
mmcMenuEntries[i].storage = mmcmenu_start[i].storage;
}
LIST_FOREACH_ENTRY(emmc_part_t, part, gpt, link){ LIST_FOREACH_ENTRY(emmc_part_t, part, gpt, link){
addEntry(part, checkGptRules(part->name), i++); addEntry(part, checkGptRules(part->name), i++);
@@ -90,14 +87,22 @@ int handleEntries(short mmcType, menu_entry part){
int res = 0; int res = 0;
if (part.property & ISDIR){ if (part.property & ISDIR){
if (returnpkg1info().ver < 0){
gfx_errDisplay("emmcMakeMenu", ERR_BISKEY_DUMP_FAILED, 0);
return -1;
}
if (!mount_mmc(part.name, part.storage)) if (!mount_mmc(part.name, part.storage))
fileexplorer("emmc:/", 1); fileexplorer("emmc:/", 1);
} }
else { else {
/*
if (mmcmenu_filemenu[1].name != NULL) if (mmcmenu_filemenu[1].name != NULL)
free(mmcmenu_filemenu[1].name); free(mmcmenu_filemenu[1].name);
utils_copystring(part.name, &mmcmenu_filemenu[1].name); utils_copystring(part.name, &mmcmenu_filemenu[1].name);
*/
mu_copySingle(part.name, mmcmenu_filemenu[1].storage, mmcmenu_filemenu[1].property, &mmcmenu_filemenu[1]);
if ((menu_make(mmcmenu_filemenu, 4, "-- RAW PARTITION --")) < 3) if ((menu_make(mmcmenu_filemenu, 4, "-- RAW PARTITION --")) < 3)
return 0; return 0;
@@ -107,7 +112,7 @@ int handleEntries(short mmcType, menu_entry part){
gfx_clearscreen(); gfx_clearscreen();
if (part.property & isBOOT){ if (part.isNull){
res = emmcDumpBoot("sd:/tegraexplorer/partition_dumps"); res = emmcDumpBoot("sd:/tegraexplorer/partition_dumps");
} }
else { else {
@@ -117,7 +122,7 @@ int handleEntries(short mmcType, menu_entry part){
if (!res){ if (!res){
gfx_printf("\nDone!"); gfx_printf("\nDone!");
btn_wait(); hidWait();
} }
} }
@@ -141,7 +146,7 @@ int makeMmcMenu(short mmcType){
f_mkdir("sd:/tegraexplorer/partition_dumps"); f_mkdir("sd:/tegraexplorer/partition_dumps");
for (int i = 0; i < count; i++){ for (int i = 0; i < count; i++){
if (mmcMenuEntries[i].property & ISMENU || mmcMenuEntries[i].property & ISDIR) if (mmcMenuEntries[i].property & (ISMENU | ISDIR))
continue; continue;
//gfx_printf("Dumping %s...\n", mmcMenuEntries[i].name); //gfx_printf("Dumping %s...\n", mmcMenuEntries[i].name);
@@ -149,14 +154,14 @@ int makeMmcMenu(short mmcType){
} }
gfx_printf("\nDone!"); gfx_printf("\nDone!");
btn_wait(); hidWait();
break; break;
case 2: case 2:
if (!(clipboardhelper & ISDIR) && (clipboardhelper & OPERATIONCOPY)){ if (!(clipboardhelper & ISDIR) && (clipboardhelper & OPERATIONCOPY)){
gfx_clearscreen(); gfx_clearscreen();
if (!mmcFlashFile(clipboard, mmcType)){ if (!mmcFlashFile(clipboard, mmcType)){
gfx_printf("\nDone!"); gfx_printf("\nDone!");
btn_wait(); hidWait();
} }
clipboardhelper = 0; clipboardhelper = 0;
} }

View File

@@ -8,7 +8,6 @@
#include "../common/common.h" #include "../common/common.h"
#include "../../libs/fatfs/ff.h" #include "../../libs/fatfs/ff.h"
#include "../../utils/sprintf.h" #include "../../utils/sprintf.h"
#include "../../utils/btn.h"
#include "../../mem/heap.h" #include "../../mem/heap.h"
#include "../../storage/nx_emmc.h" #include "../../storage/nx_emmc.h"
#include "../common/types.h" #include "../common/types.h"
@@ -23,7 +22,7 @@ int emmcRestorePart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part){
FILINFO fno; FILINFO fno;
u8 *buf; u8 *buf;
u32 lba_curr = part->lba_start; u32 lba_curr = part->lba_start;
u32 bytesWritten = 0; u64 bytesWritten = 0;
u32 totalSectorsDest = part->lba_end - part->lba_start + 1; u32 totalSectorsDest = part->lba_end - part->lba_start + 1;
u64 totalSizeDest = (u64)((u64)totalSectorsDest << 9); u64 totalSizeDest = (u64)((u64)totalSectorsDest << 9);
u64 totalSize; u64 totalSize;
@@ -33,7 +32,7 @@ int emmcRestorePart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part){
gfx_printf("Initializing\r"); gfx_printf("Initializing\r");
buf = calloc(16384, sizeof(u8)); buf = calloc(BUFSIZE, sizeof(u8));
if (!buf){ if (!buf){
gfx_errDisplay("restore_emmc_part", ERR_MEM_ALLOC_FAILED, 1); gfx_errDisplay("restore_emmc_part", ERR_MEM_ALLOC_FAILED, 1);
@@ -57,10 +56,10 @@ int emmcRestorePart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part){
if (totalSize < totalSizeDest){ if (totalSize < totalSizeDest){
SWAPCOLOR(COLOR_ORANGE); SWAPCOLOR(COLOR_ORANGE);
gfx_printf("File is too small for destenation.\nDo you want to flash it anyway?\n\nVol +/- to Cancel\n"); gfx_printf("File is too small for destination.\nDo you want to flash it anyway?\n\nB to Cancel\n");
u8 btnres = gfx_makewaitmenu( u8 btnres = gfx_makewaitmenu(
"Power to Confirm", "A to Confirm",
2 3
); );
RESETCOLOR; RESETCOLOR;
@@ -79,7 +78,7 @@ int emmcRestorePart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part){
} }
while (totalSectors > 0){ while (totalSectors > 0){
num = MIN(totalSectors, 32); num = MIN(totalSectors, 128);
if ((res = f_read(&fp, buf, num * NX_EMMC_BLOCKSIZE, NULL))){ if ((res = f_read(&fp, buf, num * NX_EMMC_BLOCKSIZE, NULL))){
gfx_errDisplay("restore_emmc_part", res, 5); gfx_errDisplay("restore_emmc_part", res, 5);
@@ -93,9 +92,9 @@ int emmcRestorePart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part){
lba_curr += num; lba_curr += num;
totalSectors -= num; totalSectors -= num;
bytesWritten += num * NX_EMMC_BLOCKSIZE; bytesWritten += (u64)(num * NX_EMMC_BLOCKSIZE);
pct = (u64)((u64)(bytesWritten) * 100u) / (u64)(fno.fsize); pct = (u64)(bytesWritten * (u64)100) / (u64)(fno.fsize);
gfx_printf("Progress: %d%%\r", pct); gfx_printf("Progress: %d%%\r", pct);
} }
@@ -210,7 +209,7 @@ emmc_part_t *mmcFindPart(char *path, short mmcType){
//gfx_printf("Path: %s\nFilename: %s", path, filename); //gfx_printf("Path: %s\nFilename: %s", path, filename);
//btn_wait(); //btn_wait();
gfx_errDisplay("mmcFindPart", ERR_NO_DESTENATION, 2); gfx_errDisplay("mmcFindPart", ERR_NO_DESTINATION, 2);
free(path_local); free(path_local);
return NULL; return NULL;
} }

View File

@@ -2,7 +2,6 @@
#include "entrymenu.h" #include "entrymenu.h"
#include "../common/common.h" #include "../common/common.h"
#include "../../libs/fatfs/ff.h" #include "../../libs/fatfs/ff.h"
#include "../../utils/btn.h"
#include "../../gfx/gfx.h" #include "../../gfx/gfx.h"
#include "fsutils.h" #include "fsutils.h"
#include "fsactions.h" #include "fsactions.h"
@@ -15,6 +14,8 @@
#include "../../utils/sprintf.h" #include "../../utils/sprintf.h"
#include "../script/parser.h" #include "../script/parser.h"
#include "../emmc/emmcoperations.h" #include "../emmc/emmcoperations.h"
#include "../../hid/hid.h"
#include "../utils/menuUtils.h"
extern char *currentpath; extern char *currentpath;
extern char *clipboard; extern char *clipboard;
@@ -24,8 +25,8 @@ extern int launch_payload(char *path);
int delfile(const char *path, const char *filename){ int delfile(const char *path, const char *filename){
gfx_clearscreen(); gfx_clearscreen();
SWAPCOLOR(COLOR_ORANGE); SWAPCOLOR(COLOR_ORANGE);
gfx_printf("Are you sure you want to delete:\n%s\n\nPress vol+/- to cancel\n", filename); gfx_printf("Are you sure you want to delete:\n%s\n\nPress B to cancel\n", filename);
if (gfx_makewaitmenu("Press power to delete", 3)){ if (gfx_makewaitmenu("Press A to delete", 2)){
f_unlink(path); f_unlink(path);
fsreader_readfolder(currentpath); fsreader_readfolder(currentpath);
return 0; return 0;
@@ -36,23 +37,27 @@ int delfile(const char *path, const char *filename){
void viewbytes(char *path){ void viewbytes(char *path){
FIL in; FIL in;
u8 print[2048]; u8 *print;
u32 size; u32 size;
QWORD offset = 0; QWORD offset = 0;
int res; int res;
Inputs *input = hidRead();
while (input->buttons & (KEY_POW | KEY_B))
hidRead();
gfx_clearscreen(); gfx_clearscreen();
print = malloc (1024);
if ((res = f_open(&in, path, FA_READ | FA_OPEN_EXISTING))){ if ((res = f_open(&in, path, FA_READ | FA_OPEN_EXISTING))){
gfx_errDisplay("viewbytes", res, 1); gfx_errDisplay("viewbytes", res, 1);
return; return;
} }
msleep(200);
while (1){ while (1){
f_lseek(&in, offset * 16); f_lseek(&in, offset * 16);
if ((res = f_read(&in, &print, 2048 * sizeof(u8), &size))){ if ((res = f_read(&in, print, 1024 * sizeof(u8), &size))){
gfx_errDisplay("viewbytes", res, 2); gfx_errDisplay("viewbytes", res, 2);
return; return;
} }
@@ -60,19 +65,20 @@ void viewbytes(char *path){
gfx_con_setpos(0, 31); gfx_con_setpos(0, 31);
gfx_hexdump(offset * 16, print, size * sizeof(u8)); gfx_hexdump(offset * 16, print, size * sizeof(u8));
res = btn_read(); input = hidRead();
if (!res) if (!(input->buttons))
res = btn_wait(); input = hidWait();
if (res & BTN_VOL_DOWN && 2048 * sizeof(u8) == size) if (input->Ldown && 1024 * sizeof(u8) == size)
offset++; offset++;
if (res & BTN_VOL_UP && offset > 0) if (input->Lup && offset > 0)
offset--; offset--;
if (res & BTN_POWER) if (input->buttons & (KEY_POW | KEY_B))
break; break;
} }
f_close(&in); f_close(&in);
free(print);
} }
void copyfile(const char *src_in, const char *outfolder){ void copyfile(const char *src_in, const char *outfolder){
@@ -115,40 +121,44 @@ void copyfile(const char *src_in, const char *outfolder){
int filemenu(menu_entry file){ int filemenu(menu_entry file){
int temp; int temp;
FILINFO attribs; char *tempchar;
for (int i = 0; i < 3; i++) /*
for (int i = 0; i < 2; i++)
if (fs_menu_file[i].name != NULL) if (fs_menu_file[i].name != NULL)
free(fs_menu_file[i].name); free(fs_menu_file[i].name);
utils_copystring(file.name, &fs_menu_file[0].name); utils_copystring(file.name, &fs_menu_file[0].name);
*/
mu_copySingle(file.name, fs_menu_file[0].storage, fs_menu_file[0].property, &fs_menu_file[0]);
if (fs_menu_file[1].name != NULL)
free(fs_menu_file[1].name);
fs_menu_file[1].name = malloc(16); fs_menu_file[1].name = malloc(16);
fs_menu_file[2].name = malloc(16); sprintf(fs_menu_file[1].name, "\nSize: %d %s", file.storage, gfx_file_size_names[file.size]);
for (temp = 4; temp < 8; temp++) if ((tempchar = fsutil_formatFileAttribs(fsutil_getnextloc(currentpath, file.name))) == NULL)
if ((file.property & (1 << temp))) fs_menu_file[2].isHide = 1;
break;
sprintf(fs_menu_file[1].name, "\nSize: %d %s", file.storage, gfx_file_size_names[temp - 4]);
if (f_stat(fsutil_getnextloc(currentpath, file.name), &attribs))
SETBIT(fs_menu_file[2].property, ISHIDE, 1);
else { else {
SETBIT(fs_menu_file[2].property, ISHIDE, 0); fs_menu_file[2].isHide = 0;
sprintf(fs_menu_file[2].name, "Attribs: %c%c%c%c", mu_copySingle(tempchar, fs_menu_file[2].storage, fs_menu_file[2].property, &fs_menu_file[2]);
(attribs.fattrib & AM_RDO) ? 'R' : '-',
(attribs.fattrib & AM_SYS) ? 'S' : '-',
(attribs.fattrib & AM_HID) ? 'H' : '-',
(attribs.fattrib & AM_ARC) ? 'A' : '-');
} }
SETBIT(fs_menu_file[7].property, ISHIDE, !(strstr(file.name, ".bin") != NULL && file.property & ISKB)); fs_menu_file[6].isHide = !hidConnected();
SETBIT(fs_menu_file[8].property, ISHIDE, !(strstr(file.name, ".te") != NULL)); fs_menu_file[8].isHide = (!(strstr(file.name, ".bin") != NULL && file.size == 1) && strstr(file.name, ".rom") == NULL);
SETBIT(fs_menu_file[10].property, ISHIDE, !(strstr(file.name, ".bis") != NULL)); fs_menu_file[9].isHide = (strstr(file.name, ".te") == NULL);
fs_menu_file[11].isHide = (strstr(file.name, ".bis") == NULL);
temp = menu_make(fs_menu_file, 11, "-- File Menu --"); /*
SETBIT(fs_menu_file[6].property, ISHIDE, !hidConnected());
SETBIT(fs_menu_file[8].property, ISHIDE, !(strstr(file.name, ".bin") != NULL && file.size == 1) && strstr(file.name, ".rom") == NULL);
SETBIT(fs_menu_file[9].property, ISHIDE, strstr(file.name, ".te") == NULL);
SETBIT(fs_menu_file[11].property, ISHIDE, strstr(file.name, ".bis") == NULL);
*/
temp = menu_make(fs_menu_file, 12, "-- File Menu --");
switch (temp){ switch (temp){
case FILE_COPY: case FILE_COPY:
fsreader_writeclipboard(fsutil_getnextloc(currentpath, file.name), OPERATIONCOPY); fsreader_writeclipboard(fsutil_getnextloc(currentpath, file.name), OPERATIONCOPY);
@@ -159,11 +169,39 @@ int filemenu(menu_entry file){
case FILE_DELETE: case FILE_DELETE:
delfile(fsutil_getnextloc(currentpath, file.name), file.name); delfile(fsutil_getnextloc(currentpath, file.name), file.name);
break; break;
case FILE_RENAME:;
char *name, *curPath;
gfx_clearscreen();
gfx_printf("Renaming %s...\n\n", file.name);
name = utils_InputText(file.name, 39);
if (name == NULL)
break;
utils_copystring(fsutil_getnextloc(currentpath, file.name), &curPath);
temp = f_rename(curPath, fsutil_getnextloc(currentpath, name));
free(curPath);
free(name);
if (temp){
gfx_errDisplay("fileMenu", temp, 0);
break;
}
fsreader_readfolder(currentpath);
break;
case FILE_PAYLOAD: case FILE_PAYLOAD:
launch_payload(fsutil_getnextloc(currentpath, file.name)); launch_payload(fsutil_getnextloc(currentpath, file.name));
break; break;
case FILE_SCRIPT: case FILE_SCRIPT:
//ParseScript(fsutil_getnextloc(currentpath, file.name)); //ParseScript(fsutil_getnextloc(currentpath, file.name));
/*
gfx_printf(" %kRelease any buttons if held!", COLOR_RED);
while (hidRead()->buttons);
*/
runScript(fsutil_getnextloc(currentpath, file.name)); runScript(fsutil_getnextloc(currentpath, file.name));
fsreader_readfolder(currentpath); fsreader_readfolder(currentpath);
break; break;
@@ -174,7 +212,7 @@ int filemenu(menu_entry file){
gfx_clearscreen(); gfx_clearscreen();
extract_bis_file(fsutil_getnextloc(currentpath, file.name), currentpath); extract_bis_file(fsutil_getnextloc(currentpath, file.name), currentpath);
fsreader_readfolder(currentpath); fsreader_readfolder(currentpath);
btn_wait(); hidWait();
break; break;
case -1: case -1:
return -1; return -1;

View File

@@ -9,6 +9,9 @@
#include "fsactions.h" #include "fsactions.h"
#include "fsutils.h" #include "fsutils.h"
#include "../../utils/sprintf.h" #include "../../utils/sprintf.h"
#include "../utils/utils.h"
#include "../../hid/hid.h"
#include "../utils/menuUtils.h"
extern char *currentpath; extern char *currentpath;
extern char *clipboard; extern char *clipboard;
@@ -38,18 +41,24 @@ void copyfolder(char *in, char *out){
} }
int foldermenu(){ int foldermenu(){
int res; int res, hidConn;
FILINFO attribs; char *name;
if (fs_menu_folder[0].name != NULL) hidConn = hidConnected();
free(fs_menu_folder[0].name);
fs_menu_folder[0].name = malloc(16);
res = strlen(currentpath); res = strlen(currentpath);
fs_menu_folder[3].isHide = (*(currentpath + res - 1) == '/');
fs_menu_folder[4].isHide = (*(currentpath + res - 1) == '/');
fs_menu_folder[5].isHide = (*(currentpath + res - 1) == '/' || !hidConn);
fs_menu_folder[6].isHide = !hidConn;
/*
SETBIT(fs_menu_folder[3].property, ISHIDE, (*(currentpath + res - 1) == '/')); SETBIT(fs_menu_folder[3].property, ISHIDE, (*(currentpath + res - 1) == '/'));
SETBIT(fs_menu_folder[4].property, ISHIDE, (*(currentpath + res - 1) == '/')); SETBIT(fs_menu_folder[4].property, ISHIDE, (*(currentpath + res - 1) == '/'));
SETBIT(fs_menu_folder[5].property, ISHIDE, (*(currentpath + res - 1) == '/') || !hidConn);
SETBIT(fs_menu_folder[6].property, ISHIDE, !hidConn);
if (f_stat(currentpath, &attribs)) if (f_stat(currentpath, &attribs))
SETBIT(fs_menu_folder[0].property, ISHIDE, 1); SETBIT(fs_menu_folder[0].property, ISHIDE, 1);
@@ -61,8 +70,19 @@ int foldermenu(){
(attribs.fattrib & AM_HID) ? 'H' : '-', (attribs.fattrib & AM_HID) ? 'H' : '-',
(attribs.fattrib & AM_ARC) ? 'A' : '-'); (attribs.fattrib & AM_ARC) ? 'A' : '-');
} }
*/
res = menu_make(fs_menu_folder, 5, currentpath); if ((name = fsutil_formatFileAttribs(currentpath)) == NULL){
fs_menu_folder[0].isHide = 1;
}
else {
fs_menu_folder[0].isHide = 0;
mu_copySingle(name, fs_menu_folder[0].storage, fs_menu_folder[0].property, &fs_menu_folder[0]);
}
res = menu_make(fs_menu_folder, 7, currentpath);
switch (res){ switch (res){
case DIR_EXITFOLDER: case DIR_EXITFOLDER:
@@ -73,8 +93,7 @@ int foldermenu(){
break; break;
case DIR_DELETEFOLDER: case DIR_DELETEFOLDER:
gfx_clearscreen(); gfx_clearscreen();
gfx_printf("Do you want to delete this folder?\nThe entire folder, with all subcontents\n will be deleted!!!\n\nPress vol+/- to cancel\n"); if (gfx_defaultWaitMenu("Do you want to delete this folder?\nThe entire folder, with all subcontents will be deleted!", 2)){
if (gfx_makewaitmenu("Press power to contine...", 3)){
gfx_clearscreen(); gfx_clearscreen();
gfx_printf("\nDeleting folder, please wait...\n"); gfx_printf("\nDeleting folder, please wait...\n");
@@ -84,6 +103,49 @@ int foldermenu(){
fsreader_readfolder(currentpath); fsreader_readfolder(currentpath);
} }
break; break;
case DIR_RENAME:;
char *prevLoc, *dirName;
dirName = strrchr(currentpath, '/') + 1;
gfx_clearscreen();
gfx_printf("Renaming %s...\n\n", dirName);
name = utils_InputText(dirName, 39);
if (name == NULL)
break;
utils_copystring(fsutil_getprevloc(currentpath), &prevLoc);
res = f_rename(currentpath, fsutil_getnextloc(prevLoc, name));
free(prevLoc);
free(name);
if (res){
gfx_errDisplay("folderMenu", res, 1);
break;
}
fsreader_writecurpath(fsutil_getprevloc(currentpath));
fsreader_readfolder(currentpath);
break;
case DIR_CREATE:;
gfx_clearscreen();
gfx_printf("Give a name for your new folder\n\n");
name = utils_InputText("New Folder", 39);
if (name == NULL)
break;
res = f_mkdir(fsutil_getnextloc(currentpath, name));
free(name);
if (res){
gfx_errDisplay("folderMenu", res, 1);
break;
}
fsreader_readfolder(currentpath);
break;
} }
return 0; return 0;

View File

@@ -7,16 +7,17 @@
#include "../gfx/gfxutils.h" #include "../gfx/gfxutils.h"
#include "../utils/utils.h" #include "../utils/utils.h"
#include "../../mem/heap.h" #include "../../mem/heap.h"
#include "../../hid/hid.h"
#include "../../utils/btn.h" #include "../../utils/btn.h"
#include "fsutils.h" #include "fsutils.h"
int fsact_copy(const char *locin, const char *locout, u8 options){ int fsact_copy(const char *locin, const char *locout, u8 options){
FIL in, out; FIL in, out;
FILINFO in_info; FILINFO in_info;
u64 sizeoffile, sizecopied = 0, totalsize; u64 sizeRemaining, toCopy;
UINT temp1, temp2; UINT temp1, temp2;
u8 *buff; u8 *buff, toPrint = options & COPY_MODE_PRINT, toCancel = options & COPY_MODE_CANCEL;
unsigned int x, y, i = 0; u32 x, y, i = 11;
int res; int res;
gfx_con_getpos(&x, &y); gfx_con_getpos(&x, &y);
@@ -41,17 +42,26 @@ int fsact_copy(const char *locin, const char *locout, u8 options){
return 1; return 1;
} }
buff = malloc (BUFSIZE); if (toPrint){
sizeoffile = f_size(&in); SWAPCOLOR(COLOR_GREEN);
totalsize = sizeoffile; gfx_printf("[ ]");
x += 16;
gfx_con_setpos(x, y);
}
while (sizeoffile > 0){ buff = malloc (BUFSIZE);
if ((res = f_read(&in, buff, (sizeoffile > BUFSIZE) ? BUFSIZE : sizeoffile, &temp1))){ sizeRemaining = f_size(&in);
const u64 totalsize = sizeRemaining;
while (sizeRemaining > 0){
toCopy = MIN(sizeRemaining, BUFSIZE);
if ((res = f_read(&in, buff, toCopy, &temp1))){
gfx_errDisplay("copy", res, 5); gfx_errDisplay("copy", res, 5);
return 1; return 1;
} }
if ((res = f_write(&out, buff, (sizeoffile > BUFSIZE) ? BUFSIZE : sizeoffile, &temp2))){ if ((res = f_write(&out, buff, toCopy, &temp2))){
gfx_errDisplay("copy", res, 6); gfx_errDisplay("copy", res, 6);
return 1; return 1;
} }
@@ -61,23 +71,28 @@ int fsact_copy(const char *locin, const char *locout, u8 options){
return 1; return 1;
} }
sizeoffile -= temp1; sizeRemaining -= toCopy;
sizecopied += temp1;
if (options & COPY_MODE_PRINT && 10 > i++){ if (toPrint && (i > 16 || !sizeRemaining)){
gfx_printf("%k[%d%%]%k", COLOR_GREEN, ((sizecopied * 100) / totalsize) ,COLOR_WHITE); gfx_printf("%3d%%", (u32)(((totalsize - sizeRemaining) * 100) / totalsize));
gfx_con_setpos(x, y); gfx_con_setpos(x, y);
}
i = 0; if (toCancel && i > 16){
if (btn_read() & (BTN_VOL_DOWN | BTN_VOL_UP)){
f_unlink(locout);
break;
}
}
if (options & COPY_MODE_CANCEL) if (options){
if (btn_read() & BTN_VOL_DOWN){ if (i++ > 16)
f_unlink(locout); i = 0;
break;
}
} }
} }
RESETCOLOR;
f_close(&in); f_close(&in);
f_close(&out); f_close(&out);
free(buff); free(buff);
@@ -113,7 +128,7 @@ int fsact_del_recursive(char *path){
else { else {
SWAPCOLOR(COLOR_RED); SWAPCOLOR(COLOR_RED);
gfx_printf("\r"); gfx_printf("\r");
gfx_printandclear(fno.fname, 37); gfx_printandclear(fno.fname, 37, 720);
if ((res = f_unlink(fsutil_getnextloc(localpath, fno.fname)))){ if ((res = f_unlink(fsutil_getnextloc(localpath, fno.fname)))){
gfx_errDisplay("del_recursive", res, 2); gfx_errDisplay("del_recursive", res, 2);
@@ -160,7 +175,7 @@ int fsact_copy_recursive(char *path, char *dstpath){
else { else {
SWAPCOLOR(COLOR_GREEN); SWAPCOLOR(COLOR_GREEN);
gfx_printf("\r"); gfx_printf("\r");
gfx_printandclear(fno.fname, 37); gfx_printandclear(fno.fname, 37, 720);
utils_copystring(fsutil_getnextloc(startpath, fno.fname), &temp); utils_copystring(fsutil_getnextloc(startpath, fno.fname), &temp);

View File

@@ -7,7 +7,6 @@
#include "../common/common.h" #include "../common/common.h"
#include "../../libs/fatfs/ff.h" #include "../../libs/fatfs/ff.h"
#include "../../utils/sprintf.h" #include "../../utils/sprintf.h"
#include "../../utils/btn.h"
#include "../../mem/heap.h" #include "../../mem/heap.h"
#include "../../storage/nx_emmc.h" #include "../../storage/nx_emmc.h"
#include "../common/types.h" #include "../common/types.h"

View File

@@ -7,6 +7,7 @@
#include "../common/common.h" #include "../common/common.h"
#include "../../libs/fatfs/ff.h" #include "../../libs/fatfs/ff.h"
#include "entrymenu.h" #include "entrymenu.h"
#include "../utils/menuUtils.h"
extern char *currentpath; extern char *currentpath;
extern char *clipboard; extern char *clipboard;
@@ -35,7 +36,7 @@ void fileexplorer(const char *startpath, int type){
*/ */
while (1){ while (1){
res = menu_make(fsreader_files, fsutil_getfileobjamount(fsreader_files), currentpath); res = menu_make(fsreader_files, mu_countObjects(fsreader_files, 0, 0), currentpath);
switch (res){ switch (res){
case FILEMENU_RETURN: case FILEMENU_RETURN:
if (!strcmp(startpath, currentpath)) if (!strcmp(startpath, currentpath))
@@ -55,7 +56,7 @@ void fileexplorer(const char *startpath, int type){
break; break;
case FILEMENU_CURFOLDER: case FILEMENU_CURFOLDER:
if (foldermenu()) if (foldermenu() < 0)
return; return;
break; break;
case -1: case -1:

View File

@@ -7,6 +7,7 @@
#include "../gfx/gfxutils.h" #include "../gfx/gfxutils.h"
#include "../utils/utils.h" #include "../utils/utils.h"
#include "../../mem/heap.h" #include "../../mem/heap.h"
#include "../utils/menuUtils.h"
menu_entry *fsreader_files = NULL; menu_entry *fsreader_files = NULL;
char *currentpath = NULL; char *currentpath = NULL;
@@ -29,53 +30,16 @@ void fsreader_writeclipboard(const char *in, u8 args){
utils_copystring(in, &clipboard); utils_copystring(in, &clipboard);
} }
void clearfileobjects(menu_entry **menu){
if ((*menu) != NULL){
for (int i = 0; (*menu)[i].name != NULL; i++){
free((*menu)[i].name);
(*menu)[i].name = NULL;
}
free((*menu));
(*menu) = NULL;
}
}
void createfileobjects(int size, menu_entry **menu){
(*menu) = calloc (size + 1, sizeof(menu_entry));
(*menu)[size].name = NULL;
}
void addobject(char* name, int spot, u8 attribs){ void addobject(char* name, int spot, u8 attribs){
u64 size = 0; u8 property = 0;
int sizes = 0;
fsreader_files[spot].property = 0;
if (fsreader_files[spot].name != NULL){
free(fsreader_files[spot].name);
fsreader_files[spot].name = NULL;
}
utils_copystring(name, &(fsreader_files[spot].name));
if (attribs & AM_DIR) if (attribs & AM_DIR)
fsreader_files[spot].property |= (ISDIR); property |= ISDIR;
else { else
size = fsutil_getfilesize(fsutil_getnextloc(currentpath, name)); property |= ISNULL;
while (size > 1024){ mu_copySingle(name, 0, property, &fsreader_files[spot]);
size /= 1024;
sizes++;
}
if (sizes > 3)
sizes = 0;
fsreader_files[spot].property |= (1 << (4 + sizes));
fsreader_files[spot].storage = size;
}
if (attribs & AM_ARC)
fsreader_files[spot].property |= (ISARC);
} }
int fsreader_readfolder(const char *path){ int fsreader_readfolder(const char *path){
@@ -83,14 +47,13 @@ int fsreader_readfolder(const char *path){
FILINFO fno; FILINFO fno;
int folderamount, res; int folderamount, res;
clearfileobjects(&fsreader_files); mu_clearObjects(&fsreader_files);
createfileobjects(fsutil_getfolderentryamount(path) + 3, &fsreader_files); mu_createObjects(fsutil_getfolderentryamount(path) + 3, &fsreader_files);
for (folderamount = 0; folderamount < 3; folderamount++){
utils_copystring(fs_menu_startdir[folderamount].name, &(fsreader_files[folderamount].name));
fsreader_files[folderamount].storage = fs_menu_startdir[folderamount].storage; for (folderamount = 0; folderamount < 3; folderamount++)
fsreader_files[folderamount].property = fs_menu_startdir[folderamount].property; mu_copySingle(fs_menu_startdir[folderamount].name, fs_menu_startdir[folderamount].storage, fs_menu_startdir[folderamount].property, &fsreader_files[folderamount]);
}
if ((res = f_opendir(&dir, path))){ if ((res = f_opendir(&dir, path))){
gfx_errDisplay("readfolder", res, 0); gfx_errDisplay("readfolder", res, 0);

View File

@@ -47,15 +47,6 @@ char *fsutil_getprevloc(char *current){
return ret; return ret;
} }
int fsutil_getfileobjamount(menu_entry *entries){
int amount = 0;
while (entries[amount].name != NULL)
amount++;
return amount;
}
bool fsutil_checkfile(char* path){ bool fsutil_checkfile(char* path){
FRESULT fr; FRESULT fr;
FILINFO fno; FILINFO fno;
@@ -88,3 +79,20 @@ int fsutil_getfolderentryamount(const char *path){
f_closedir(&dir); f_closedir(&dir);
return folderamount; return folderamount;
} }
char *fsutil_formatFileAttribs(char *path){
FILINFO attribs;
char *out;
out = malloc(16);
if (f_stat(path, &attribs))
return NULL;
sprintf(out, "Attribs: %c%c%c%c",
(attribs.fattrib & AM_RDO) ? 'R' : '-',
(attribs.fattrib & AM_SYS) ? 'S' : '-',
(attribs.fattrib & AM_HID) ? 'H' : '-',
(attribs.fattrib & AM_ARC) ? 'A' : '-');
return out;
}

View File

@@ -4,8 +4,8 @@
char *fsutil_getnextloc(const char *current, const char *add); char *fsutil_getnextloc(const char *current, const char *add);
char *fsutil_getprevloc(char *current); char *fsutil_getprevloc(char *current);
int fsutil_getfileobjamount(menu_entry *entries);
bool fsutil_checkfile(char* path); bool fsutil_checkfile(char* path);
u64 fsutil_getfilesize(char *path); u64 fsutil_getfilesize(char *path);
int fsutil_getfolderentryamount(const char *path); int fsutil_getfolderentryamount(const char *path);
int extract_bis_file(char *path, char *outfolder); int extract_bis_file(char *path, char *outfolder);
char *fsutil_formatFileAttribs(char *path);

View File

@@ -8,6 +8,7 @@
#include "../../utils/util.h" #include "../../utils/util.h"
#include "../../mem/heap.h" #include "../../mem/heap.h"
#include "../common/common.h" #include "../common/common.h"
#include "../../hid/hid.h"
int printerrors = true; int printerrors = true;
@@ -19,18 +20,15 @@ void gfx_clearscreen(){
SWAPCOLOR(COLOR_DEFAULT); SWAPCOLOR(COLOR_DEFAULT);
SWAPBGCOLOR(COLOR_WHITE); SWAPBGCOLOR(COLOR_WHITE);
gfx_box(0, 1263, 719, 1279, COLOR_WHITE); gfx_boxGrey(0, 703, 1279, 719, 0xFF);
gfx_con_setpos(0, 1263); gfx_boxGrey(0, 0, 1279, 15, 0xFF);
gfx_printf("Move: Vol+/- | Select: Pow | Battery: %3d%%", battery >> 8);
gfx_box(0, 0, 719, 15, COLOR_WHITE);
gfx_con_setpos(0, 0); gfx_con_setpos(0, 0);
gfx_printf("Tegraexplorer v1.5.0\n"); gfx_printf("Tegraexplorer v2.0.1 | Battery: %3d%%\n", battery >> 8);
RESETCOLOR; RESETCOLOR;
} }
int gfx_message(u32 color, const char* message, ...){ u32 gfx_message(u32 color, const char* message, ...){
va_list ap; va_list ap;
va_start(ap, message); va_start(ap, message);
@@ -40,10 +38,10 @@ int gfx_message(u32 color, const char* message, ...){
gfx_vprintf(message, ap); gfx_vprintf(message, ap);
va_end(ap); va_end(ap);
return btn_wait(); return hidWait()->buttons;
} }
int gfx_errDisplay(char *src_func, int err, int loc){ u32 gfx_errDisplay(const char *src_func, int err, int loc){
if (!printerrors) if (!printerrors)
return 0; return 0;
@@ -54,37 +52,33 @@ int gfx_errDisplay(char *src_func, int err, int loc){
if (err < 15) if (err < 15)
gfx_printf("Desc: %s\n", utils_err_codes[err]); gfx_printf("Desc: %s\n", utils_err_codes[err]);
else if (err >= ERR_SAME_LOC && err <= ERR_NO_DESTENATION) else if (err >= ERR_SAME_LOC && err <= ERR_NO_DESTINATION)
gfx_printf("Desc: %s\n", utils_err_codes_te[err - 50]); gfx_printf("Desc: %s\n", utils_err_codes_te[err - 50]);
if (loc) if (loc)
gfx_printf("Loc: %d\n", loc); gfx_printf("Loc: %d\n", loc);
gfx_printf("\nPress any button to return"); gfx_printf("\nPress any button to return\n");
RESETCOLOR; RESETCOLOR;
while (btn_read() != 0); return hidWait()->buttons;
return btn_wait();
} }
int gfx_makewaitmenu(char *hiddenmessage, int timer){ int gfx_makewaitmenu(const char *hiddenmessage, int timer){
int res;
u32 start = get_tmr_s(); u32 start = get_tmr_s();
Inputs *input = NULL;
while (btn_read() != 0);
while(1){ while(1){
res = btn_read(); input = hidRead();
if (res & BTN_VOL_DOWN || res & BTN_VOL_UP) if (input->buttons & (KEY_VOLM | KEY_VOLP | KEY_B))
return 0; return 0;
if (start + timer > get_tmr_s()) if (start + timer > get_tmr_s())
gfx_printf("\r<Wait %d seconds> ", timer + start - get_tmr_s()); gfx_printf("\r<Wait %d seconds> ", timer + start - get_tmr_s());
else if (res & BTN_POWER) else if (input->a)
return 1; return 1;
else else
@@ -92,7 +86,7 @@ int gfx_makewaitmenu(char *hiddenmessage, int timer){
} }
} }
void gfx_printlength(int size, char *toprint){ void gfx_printlength(int size, const char *toprint){
char *temp; char *temp;
temp = (char*) malloc (size + 1); temp = (char*) malloc (size + 1);
@@ -108,15 +102,20 @@ void gfx_printlength(int size, char *toprint){
free(temp); free(temp);
} }
void gfx_printandclear(char *in, int length){ void gfx_printandclear(const char *in, int length, int endX){
u32 x, y; u32 x, y;
gfx_printlength(length, in); gfx_printlength(length, in);
gfx_con_getpos(&x, &y); gfx_con_getpos(&x, &y);
RESETCOLOR; RESETCOLOR;
/*
for (int i = (703 - x) / 16; i > 0; i--) for (int i = (703 - x) / 16; i > 0; i--)
gfx_printf(" "); gfx_printf(" ");
*/
gfx_boxGrey(x, y, endX, y + 15, 0x1B);
gfx_con_setpos(x, y); gfx_con_setpos(x, y);
@@ -127,8 +126,58 @@ void gfx_printandclear(char *in, int length){
*/ */
} }
void gfx_printfilesize(int size, char *type){ static u32 sideY = 0;
SWAPCOLOR(COLOR_VIOLET); void _gfx_sideSetYAuto(){
gfx_printf("\a%4d\e%s", size, type); u32 getX, getY;
RESETCOLOR; gfx_con_getpos(&getX, &getY);
sideY = getY;
}
void gfx_sideSetY(u32 setY){
sideY = setY;
}
u32 gfx_sideGetY(){
return sideY;
}
void gfx_sideprintf(const char* message, ...){
va_list ap;
va_start(ap, message);
gfx_con_setpos(800, sideY);
gfx_vprintf(message, ap);
_gfx_sideSetYAuto();
va_end(ap);
}
void gfx_sideprintandclear(const char* message, int length){
gfx_con_setpos(800, sideY);
gfx_printandclear(message, length, 1279);
gfx_putc('\n');
_gfx_sideSetYAuto();
}
void gfx_drawScrollBar(int minView, int maxView, int count){
int curScrollCount = 1 + maxView - minView;
if (curScrollCount >= count)
return;
u32 barSize = (703 * (curScrollCount * 1000 / count)) / 1000;
u32 offsetSize = (703 * (minView * 1000 / count)) / 1000;
gfx_boxGrey(740, 16, 755, 702, 0x1B);
if ((16 + barSize + offsetSize) > 702)
gfx_boxGrey(740, 16 + offsetSize, 755, 702, 0x66);
else
gfx_boxGrey(740, 16 + offsetSize, 755, 16 + barSize + offsetSize, 0x66);
}
int gfx_defaultWaitMenu(const char *message, int time){
gfx_clearscreen();
SWAPCOLOR(COLOR_ORANGE);
gfx_printf("\n%s\n\nPress B to return\n", message);
SWAPCOLOR(COLOR_RED);
return gfx_makewaitmenu("Press A to continue", time);
} }

View File

@@ -4,14 +4,20 @@
#define SWAPCOLOR(color) gfx_printf("%k", color) #define SWAPCOLOR(color) gfx_printf("%k", color)
#define SWAPBGCOLOR(color) gfx_printf("%K", color) #define SWAPBGCOLOR(color) gfx_printf("%K", color)
#define SWAPALLCOLOR(fg, bg) gfx_printf("%k%K", fg, bg)
#define RESETCOLOR gfx_printf("%k%K", COLOR_WHITE, COLOR_DEFAULT) #define RESETCOLOR gfx_printf("%k%K", COLOR_WHITE, COLOR_DEFAULT)
void gfx_clearscreen(); void gfx_clearscreen();
int gfx_message(u32 color, const char* message, ...); u32 gfx_message(u32 color, const char* message, ...);
int gfx_errDisplay(char *src_func, int err, int loc); u32 gfx_errDisplay(const char *src_func, int err, int loc);
int gfx_makewaitmenu(char *hiddenmessage, int timer); int gfx_makewaitmenu(const char *hiddenmessage, int timer);
void gfx_printlength(int size, char *toprint); void gfx_printlength(int size, const char *toprint);
void gfx_printandclear(char *in, int length); void gfx_printandclear(const char *in, int length, int endX);
void gfx_printfilesize(int size, char *type); void gfx_sideSetY(u32 setY);
u32 gfx_sideGetY();
void gfx_sideprintf(const char* message, ...);
void gfx_sideprintandclear(const char* message, int length);
void gfx_drawScrollBar(int minView, int maxView, int count);
int gfx_defaultWaitMenu(const char *message, int time);
extern int printerrors; extern int printerrors;

View File

@@ -1,3 +1,4 @@
#include <string.h>
#include "menu.h" #include "menu.h"
#include "gfxutils.h" #include "gfxutils.h"
#include "../common/types.h" #include "../common/types.h"
@@ -6,86 +7,99 @@
#include "../../utils/util.h" #include "../../utils/util.h"
#include "../../mem/minerva.h" #include "../../mem/minerva.h"
#include "../../soc/gpio.h" #include "../../soc/gpio.h"
#include "../../hid/hid.h"
#include "../fs/fsutils.h"
#include "../utils/menuUtils.h"
extern void sd_unmount(); extern void sd_unmount();
extern bool sd_inited; extern bool sd_inited;
void _printentry(menu_entry entry, bool highlighted, bool refresh){ #pragma GCC push_options
int size; #pragma GCC optimize ("O2")
u32 color = (entry.property & ISMENU) ? entry.storage : ((entry.property & ISDIR) ? COLOR_WHITE : COLOR_VIOLET);
/*
if (entry.property & ISMENU)
SWAPCOLOR(entry.storage);
else if (entry.property & ISDIR)
SWAPCOLOR(COLOR_WHITE);
else {
SWAPCOLOR(COLOR_VIOLET);
}
*/
if (!(entry.property & ISMENU && entry.property & ISDIR)){ void _printentry(menu_entry *entry, bool highlighted, bool refresh, const char *path){
for (size = 4; size < 8; size++) u32 color = (entry->isMenu) ? entry->storage : ((entry->isDir) ? COLOR_WHITE : COLOR_VIOLET);
if ((entry.property & (1 << size)))
break;
}
SWAPALLCOLOR((highlighted) ? COLOR_DEFAULT : color, (highlighted) ? color : COLOR_DEFAULT);
/* if (!(entry->isMenu))
if (highlighted){ gfx_printf("%c ", (entry->isDir) ? 30 : 31);
SWAPBGCOLOR(COLOR_WHITE);
if ((entry.property & ISMENU) ? entry.storage == COLOR_WHITE : entry.property & ISDIR)
SWAPCOLOR(COLOR_DEFAULT);
}
else
SWAPBGCOLOR(COLOR_DEFAULT);
*/
SWAPCOLOR((highlighted) ? COLOR_DEFAULT : color);
SWAPBGCOLOR((highlighted) ? color : COLOR_DEFAULT);
if (refresh) if (refresh)
gfx_printandclear(entry.name, 37); gfx_printandclear(entry->name, 37, 720);
else else
gfx_printlength(37, entry.name); gfx_printlength(37, entry->name);
if (entry.property & ISDIR || entry.property & ISMENU) if (entry->property & (ISMENU | ISDIR))
gfx_printf("\n"); gfx_printf("\n");
else { else {
SWAPCOLOR(COLOR_BLUE); if (entry->isNull){
SWAPBGCOLOR(COLOR_DEFAULT); u64 totalSize;
gfx_printf("\a%d\e%s", entry.storage, gfx_file_size_names[size - 4]); u32 sizeType = 0;
totalSize = fsutil_getfilesize(fsutil_getnextloc(path, entry->name));
while (totalSize > 1024){
totalSize /= 1024;
sizeType++;
}
if (sizeType > 3)
sizeType = 3;
entry->size = sizeType;
entry->storage = totalSize;
SETBIT(entry->property, ISNULL, 0);
}
SWAPALLCOLOR(COLOR_BLUE, COLOR_DEFAULT);
gfx_printf("\a%4d", entry->storage);
gfx_con.fntsz = 8;
gfx_printf("\n\e%s\n", gfx_file_size_names[entry->size]);
gfx_con.fntsz = 16;
} }
} }
int menu_make(menu_entry *entries, int amount, char *toptext){
int currentpos = 0, res = 0, offset = 0, delay = 300, minscreen = 0, maxscreen = 59, calculatedamount = 0; bool disableB = false;
u32 scrolltimer, timer; int menu_make(menu_entry *entries, int amount, const char *toptext){
bool refresh = false; int currentpos = 0, offset = 0, delay = 300, minscreen = 0, maxscreen = 39, calculatedamount = 0;
u32 scrolltimer, timer, sideY;
bool refresh = true;
Inputs *input = hidRead();
input->buttons = 0;
gfx_clearscreen(); gfx_clearscreen();
for (int i = 0; i < amount; i++) calculatedamount = mu_countObjects(entries, amount, ISMENU);
if (!(entries[i].property & ISMENU))
calculatedamount++;
gfx_con_setpos(512, 0); gfx_con_setpos(0, 16);
if (calculatedamount){
SWAPCOLOR(COLOR_DEFAULT);
SWAPBGCOLOR(COLOR_WHITE);
gfx_printf("%3d entries\n", calculatedamount);
RESETCOLOR;
}
else
gfx_printf("\n");
SWAPCOLOR(COLOR_GREEN); SWAPCOLOR(COLOR_GREEN);
gfx_printlength(42, toptext); gfx_printlength(42, toptext);
RESETCOLOR; RESETCOLOR;
while (!(res & BTN_POWER)){ gfx_sideSetY(48);
gfx_con_setpos(0, 47);
char *currentfolder = strrchr(toptext, '/');
if (currentfolder != NULL){
if (calculatedamount)
gfx_sideprintf("%d items in current dir\n\n", calculatedamount);
gfx_sideprintf("Current directory:\n");
if (*(currentfolder + 1) != 0)
currentfolder++;
SWAPCOLOR(COLOR_GREEN);
gfx_sideprintandclear(currentfolder, 28);
gfx_sideprintf("\n\n\n");
}
gfx_drawScrollBar(minscreen, maxscreen, amount);
while (!(input->a)){
gfx_con_setpos(0, 48);
timer = get_tmr_ms(); timer = get_tmr_ms();
refresh = false;
if (!currentpos){ if (!currentpos){
while (currentpos < amount && entries[currentpos].property & (ISSKIP | ISHIDE)) while (currentpos < amount && entries[currentpos].property & (ISSKIP | ISHIDE))
@@ -110,58 +124,102 @@ int menu_make(menu_entry *entries, int amount, char *toptext){
refresh = true; refresh = true;
} }
for (int i = 0 + offset; i < amount && i < 60 + offset; i++) if (refresh || currentfolder == NULL || !calculatedamount){
if (!(entries[i].property & ISHIDE)) for (int i = 0 + offset; i < amount && i < 40 + offset; i++)
_printentry(entries[i], (i == currentpos), refresh); if (!(entries[i].isHide))
_printentry(&entries[i], (i == currentpos), refresh, toptext);
}
else {
if (currentpos - minscreen > 0){
gfx_con_setpos(0, 32 + (currentpos - minscreen) * 16);
_printentry(&entries[currentpos - 1], false, false, toptext);
}
else
gfx_con_setpos(0, 48 + (currentpos - minscreen) * 16);
gfx_printf("\n%k%K %s %s\n\nTime taken for screen draw: %dms", COLOR_BLUE, COLOR_DEFAULT, (offset + 60 < amount) ? "v" : " ", (offset > 0) ? "^" : " ", get_tmr_ms() - timer); _printentry(&entries[currentpos], true, false, toptext);
while (btn_read() & BTN_POWER); if (currentpos < amount - 1 && currentpos < maxscreen)
_printentry(&entries[currentpos + 1], false, false, toptext);
}
res = 0; RESETCOLOR;
while (!res){
if (!res){ sideY = gfx_sideGetY();
if (sd_inited && !!gpio_read(GPIO_PORT_Z, GPIO_PIN_1)){ if (!(entries[currentpos].isMenu)){
gfx_errDisplay("menu", ERR_SD_EJECTED, 0); gfx_sideprintf("Current selection:\n");
sd_unmount(); SWAPCOLOR(COLOR_YELLOW);
return -1; gfx_sideprintandclear(entries[currentpos].name, 28);
} RESETCOLOR;
gfx_sideprintf("Type: %s", (entries[currentpos].isDir) ? "Dir " : "File");
gfx_sideSetY(sideY);
}
else
gfx_boxGrey(800, sideY, 1279, sideY + 48, 0x1B);
gfx_con_setpos(0, 703);
SWAPCOLOR(COLOR_DEFAULT);
SWAPBGCOLOR(COLOR_WHITE);
gfx_printf("Time taken for screen draw: %dms ", get_tmr_ms() - timer);
if (refresh)
gfx_drawScrollBar(minscreen, maxscreen, amount);
while (hidRead()->buttons & (KEY_B | KEY_A));
input->buttons = 0;
while (!(input->buttons & (KEY_A | KEY_LDOWN | KEY_LUP | KEY_B | KEY_RUP | KEY_RDOWN))){
if (sd_inited && !!gpio_read(GPIO_PORT_Z, GPIO_PIN_1)){
gfx_errDisplay("menu", ERR_SD_EJECTED, 0);
sd_unmount();
return -1;
} }
res = btn_read(); input = hidRead();
if (!res) if (!(input->buttons & (KEY_A | KEY_LDOWN | KEY_LUP | KEY_B | KEY_RUP | KEY_RDOWN)))
delay = 300; delay = 300;
if (delay < 300){ if (delay < 300){
scrolltimer = get_tmr_ms(); scrolltimer = get_tmr_ms();
while (res){ while (input->buttons & (KEY_A | KEY_LDOWN | KEY_LUP | KEY_B | KEY_RUP | KEY_RDOWN)){
if (scrolltimer + delay <= get_tmr_ms()) if (scrolltimer + delay <= get_tmr_ms())
break; break;
res = btn_read(); input = hidRead();
} }
} }
if (delay > 46 && res) if (delay > 46 && input->buttons & (KEY_A | KEY_LDOWN | KEY_LUP | KEY_B | KEY_RUP | KEY_RDOWN))
delay -= 45; delay -= 45;
if (input->buttons & (KEY_RUP | KEY_RDOWN))
delay = 1;
} }
if (res & BTN_VOL_UP && currentpos >= 1){ if (input->buttons & (KEY_LUP | KEY_RUP) && currentpos >= 1){
currentpos--; currentpos--;
while(entries[currentpos].property & (ISSKIP | ISHIDE) && currentpos >= 1) while(entries[currentpos].property & (ISSKIP | ISHIDE) && currentpos >= 1)
currentpos--; currentpos--;
} }
else if (res & BTN_VOL_DOWN && currentpos < amount - 1){ else if (input->buttons & (KEY_LDOWN | KEY_RDOWN) && currentpos < amount - 1){
currentpos++; currentpos++;
while(entries[currentpos].property & (ISSKIP | ISHIDE) && currentpos < amount - 1) while(entries[currentpos].property & (ISSKIP | ISHIDE) && currentpos < amount - 1)
currentpos++; currentpos++;
} }
else if (input->b && !disableB){
currentpos = 0;
break;
}
refresh = false;
} }
minerva_periodic_training(); minerva_periodic_training();
//return (mode) ? currentpos : entries[currentpos].property; //return (mode) ? currentpos : entries[currentpos].property;
return currentpos; return currentpos;
} }
#pragma GCC pop_options

View File

@@ -1,4 +1,4 @@
#pragma once #pragma once
#include "../common/types.h" #include "../common/types.h"
int menu_make(menu_entry *entries, int amount, char *toptext); int menu_make(menu_entry *entries, int amount, const char *toptext);

View File

@@ -17,12 +17,17 @@
#include "fs/fsmenu.h" #include "fs/fsmenu.h"
#include "emmc/emmcoperations.h" #include "emmc/emmcoperations.h"
#include "emmc/emmcmenu.h" #include "emmc/emmcmenu.h"
#include "../storage/nx_sd.h"
//#include "../hid/joycon.h"
#include "../hid/hid.h"
/*
extern bool sd_mount(); extern bool sd_mount();
extern void sd_unmount(); extern void sd_unmount();
*/
extern int launch_payload(char *path); extern int launch_payload(char *path);
extern bool sd_inited; extern bool sd_inited;
extern bool sd_mounted; extern bool sd_mounted;
extern bool disableB;
int res = 0, meter = 0; int res = 0, meter = 0;
@@ -31,9 +36,7 @@ void MainMenu_SDCard(){
} }
void MainMenu_EMMC(){ void MainMenu_EMMC(){
gfx_clearscreen(); if (gfx_defaultWaitMenu("You're about to enter EMMC\nModifying anything here can result in a BRICK!\n\nPlease only continue if you know what you're doing", 4)){
gfx_printf("You're about to enter EMMC\nModifying anything here\n can result in a BRICK!\n\nPlease only continue\n if you know what you're doing\n\nPress Vol+/- to return\n");
if (gfx_makewaitmenu("Press Power to enter", 4)){
/* /*
connect_mmc(SYSMMC); connect_mmc(SYSMMC);
@@ -86,9 +89,7 @@ void MainMenu_SDFormat(){
res = menu_make(mainmenu_format, 3, "-- Format Menu --"); res = menu_make(mainmenu_format, 3, "-- Format Menu --");
if (res > 0){ if (res > 0){
gfx_clearscreen(); if(gfx_defaultWaitMenu("Are you sure you want to format your sd?\nThis will delete everything on your SD card!\nThis action is irreversible!", 10)){
gfx_printf("Are you sure you want to format your sd?\nThis will delete everything on your SD card\nThis action is irreversible!\n\nPress Vol+/- to cancel\n");
if(gfx_makewaitmenu("Press Power to continue", 10)){
if (format(res)){ if (format(res)){
sd_unmount(); sd_unmount();
} }
@@ -130,6 +131,7 @@ void MainMenu_Exit(){
case SHUTDOWN_AMS: case SHUTDOWN_AMS:
launch_payload("/atmosphere/reboot_payload.bin"); launch_payload("/atmosphere/reboot_payload.bin");
} //todo declock bpmp } //todo declock bpmp
} }
func_void_ptr mainmenu_functions[] = { func_void_ptr mainmenu_functions[] = {
@@ -152,22 +154,31 @@ void RunMenuOption(int option){
void te_main(){ void te_main(){
int setter; int setter;
//gfx_printf("Initing controller\n");
hidInit();
//gfx_printf("Getting biskeys\n");
if (dump_biskeys() == -1){ if (dump_biskeys() == -1){
gfx_errDisplay("dump_biskey", ERR_BISKEY_DUMP_FAILED, 0); gfx_errDisplay("dump_biskey", ERR_BISKEY_DUMP_FAILED, 0);
mainmenu_main[1].property |= ISHIDE; //mainmenu_main[1].property |= ISHIDE;
} }
//gfx_printf("Mounting SD\n");
sd_mount();
//gfx_printf("Loading possible EMU\n");
if (emummc_load_cfg()){ if (emummc_load_cfg()){
mainmenu_main[2].property |= ISHIDE; mainmenu_main[2].property |= ISHIDE;
} }
else
dumpEmuGpt();
//gfx_printf("Dumping gpt\n");
dumpGpt();
//gfx_printf("Disconnecting EMMC\n");
disconnect_mmc(); disconnect_mmc();
//gfx_printf("Entering main menu\n");
while (1){ while (1){
//fillmainmenu();
setter = sd_mounted; setter = sd_mounted;
if (emu_cfg.enabled){ if (emu_cfg.enabled){
@@ -180,7 +191,10 @@ void te_main(){
setter = sd_inited; setter = sd_inited;
SETBIT(mainmenu_main[5].property, ISHIDE, !setter); SETBIT(mainmenu_main[5].property, ISHIDE, !setter);
disableB = true;
res = menu_make(mainmenu_main, 8, "-- Main Menu --") + 1; res = menu_make(mainmenu_main, 8, "-- Main Menu --") + 1;
disableB = false;
RunMenuOption(res); RunMenuOption(res);
} }
} }

View File

@@ -6,7 +6,7 @@
#include "../../utils/types.h" #include "../../utils/types.h"
#include "../../libs/fatfs/ff.h" #include "../../libs/fatfs/ff.h"
#include "../../utils/sprintf.h" #include "../../utils/sprintf.h"
#include "../../utils/btn.h" #include "../../hid/hid.h"
#include "../../gfx/gfx.h" #include "../../gfx/gfx.h"
#include "../../utils/util.h" #include "../../utils/util.h"
#include "../../storage/emummc.h" #include "../../storage/emummc.h"
@@ -30,7 +30,7 @@ extern short currentlyMounted;
int parseIntInput(char *in, int *out){ int parseIntInput(char *in, int *out){
if (in[0] == '@'){ if (in[0] == '@'){
if (str_int_find(argv[0], out)) if (str_int_find(in, out))
return -1; return -1;
} }
else else
@@ -38,10 +38,10 @@ int parseIntInput(char *in, int *out){
return 0; return 0;
} }
/*
int parseJmpInput(char *in, u64 *out){ int parseJmpInput(char *in, u64 *out){
if (in[0] == '?'){ if (in[0] == '?'){
if (str_jmp_find(argv[0], out)) if (str_jmp_find(in, out))
return -1; return -1;
else else
return 0; return 0;
@@ -49,6 +49,7 @@ int parseJmpInput(char *in, u64 *out){
else else
return -1; return -1;
} }
*/
int parseStringInput(char *in, char **out){ int parseStringInput(char *in, char **out){
if (in[0] == '$'){ if (in[0] == '$'){
@@ -63,14 +64,29 @@ int parseStringInput(char *in, char **out){
} }
} }
#pragma GCC push_options
#pragma GCC optimize ("Os")
u32 currentcolor = COLOR_WHITE; u32 currentcolor = COLOR_WHITE;
int part_printf(){ int part_printf(){
char *toprint;
if (parseStringInput(argv[0], &toprint))
return -1;
SWAPCOLOR(currentcolor); SWAPCOLOR(currentcolor);
gfx_printf(toprint); for (int i = 0; i < argc; i++){
if (argv[i][0] == '@'){
int toprintint;
if (parseIntInput(argv[i], &toprintint))
return -1;
gfx_printf("%d", toprintint);
}
else {
char *toprintstring;
if (parseStringInput(argv[i], &toprintstring))
return -1;
gfx_printf(toprintstring);
}
}
gfx_printf("\n"); gfx_printf("\n");
return 0; return 0;
} }
@@ -103,6 +119,29 @@ int part_Wait(){
return 0; return 0;
} }
int part_Check(){
int left, right;
if (parseIntInput(argv[0], &left))
return -1;
if (parseIntInput(argv[2], &right))
return -1;
if (!strcmp(argv[1], "=="))
return (left == right);
else if (!strcmp(argv[1], "!="))
return (left != right);
else if (!strcmp(argv[1], ">="))
return (left >= right);
else if (!strcmp(argv[1], "<="))
return (left <= right);
else if (!strcmp(argv[1], ">"))
return (left > right);
else if (!strcmp(argv[1], "<"))
return (left < right);
else
return -1;
}
int part_if(){ int part_if(){
int condition; int condition;
if (parseIntInput(argv[0], &condition)) if (parseIntInput(argv[0], &condition))
@@ -125,6 +164,19 @@ int part_if(){
*/ */
} }
int part_if_args(){
int condition;
if ((condition = part_Check()) < 0)
return -1;
getfollowingchar('{');
if (!condition)
skipbrackets();
return 0;
}
int part_Math(){ int part_Math(){
int left, right; int left, right;
if (parseIntInput(argv[0], &left)) if (parseIntInput(argv[0], &left))
@@ -145,29 +197,6 @@ int part_Math(){
return -1; return -1;
} }
int part_Check(){
int left, right;
if (parseIntInput(argv[0], &left))
return -1;
if (parseIntInput(argv[2], &right))
return -1;
if (!strcmp(argv[1], "=="))
return (left == right);
else if (!strcmp(argv[1], "!="))
return (left != right);
else if (!strcmp(argv[1], ">="))
return (left >= right);
else if (!strcmp(argv[1], "<="))
return (left <= right);
else if (!strcmp(argv[1], ">"))
return (left > right);
else if (!strcmp(argv[1], "<"))
return (left < right);
else
return -1;
}
int part_SetInt(){ int part_SetInt(){
int out; int out;
parseIntInput(argv[0], &out); parseIntInput(argv[0], &out);
@@ -200,8 +229,8 @@ int part_SetStringIndex(){
} }
int part_goto(){ int part_goto(){
u64 target = 0; int target = 0;
if (parseJmpInput(argv[0], &target)) if (parseIntInput(argv[0], &target))
return -1; return -1;
f_lseek(&scriptin, target); f_lseek(&scriptin, target);
return 0; return 0;
@@ -243,17 +272,21 @@ int part_MountMMC(){
} }
int part_Pause(){ int part_Pause(){
int res; Inputs *input = hidWaitMask(KEY_A | KEY_B | KEY_X | KEY_Y | KEY_POW | KEY_VOLP | KEY_VOLM | KEY_LUP | KEY_LDOWN | KEY_LLEFT | KEY_LRIGHT);
while (btn_read() != 0); str_int_add("@BTN_POWER", input->pow);
str_int_add("@BTN_VOL+", input->volp);
str_int_add("@BTN_VOL-", input->volm);
str_int_add("@BTN_A", input->a);
str_int_add("@BTN_B", input->b);
str_int_add("@BTN_X", input->x);
str_int_add("@BTN_Y", input->y);
str_int_add("@BTN_UP", input->Lup);
str_int_add("@BTN_DOWN", input->Ldown);
str_int_add("@BTN_LEFT", input->Lleft);
str_int_add("@BTN_RIGHT", input->Lright);
res = btn_wait(); return input->buttons;
str_int_add("@BTN_POWER", (res & BTN_POWER));
str_int_add("@BTN_VOL+", (res & BTN_VOL_UP));
str_int_add("@BTN_VOL-", (res & BTN_VOL_DOWN));
return res;
} }
int part_addstrings(){ int part_addstrings(){
@@ -429,10 +462,10 @@ int part_setPrintPos(){
if (parseIntInput(argv[1], &right)) if (parseIntInput(argv[1], &right))
return -1; return -1;
if (left > 42) if (left > 78)
return -1; return -1;
if (right > 78) if (right > 42)
return -1; return -1;
gfx_con_setpos(left * 16, right * 16); gfx_con_setpos(left * 16, right * 16);
@@ -510,12 +543,17 @@ int part_clearscreen(){
return 0; return 0;
} }
int part_getPos(){
return (int)f_tell(&scriptin);
}
str_fnc_struct functions[] = { str_fnc_struct functions[] = {
{"printf", part_printf, 1}, {"printf", part_printf, 255},
{"printInt", part_print_int, 1}, {"printInt", part_print_int, 1},
{"setPrintPos", part_setPrintPos, 2}, {"setPrintPos", part_setPrintPos, 2},
{"clearscreen", part_clearscreen, 0}, {"clearscreen", part_clearscreen, 0},
{"if", part_if, 1}, {"if", part_if, 1},
{"if", part_if_args, 3}, // function overloading
{"math", part_Math, 3}, {"math", part_Math, 3},
{"check", part_Check, 3}, {"check", part_Check, 3},
{"setInt", part_SetInt, 1}, {"setInt", part_SetInt, 1},
@@ -542,22 +580,23 @@ str_fnc_struct functions[] = {
{"mmc_mount", part_MountMMC, 1}, {"mmc_mount", part_MountMMC, 1},
{"mmc_dumpPart", part_mmc_dumpPart, 2}, {"mmc_dumpPart", part_mmc_dumpPart, 2},
{"mmc_restorePart", part_mmc_restorePart, 1}, {"mmc_restorePart", part_mmc_restorePart, 1},
{"getPosition", part_getPos, 0},
{"pause", part_Pause, 0}, {"pause", part_Pause, 0},
{"wait", part_Wait, 1}, {"wait", part_Wait, 1},
{"exit", part_Exit, 0}, {"exit", part_Exit, 0},
{NULL, NULL, 0} {NULL, NULL, 0}
}; };
#pragma GCC pop_options
int run_function(char *func_name, int *out){ int run_function(char *func_name, int *out){
for (u32 i = 0; functions[i].key != NULL; i++){ for (u32 i = 0; functions[i].key != NULL; i++){
if (!strcmp(functions[i].key, func_name)){ if (!strcmp(functions[i].key, func_name)){
if (argc != functions[i].arg_count) if (argc != functions[i].arg_count && functions[i].arg_count != 255)
return -2; continue;
*out = functions[i].value(); *out = functions[i].value();
if (*out < 0) return (*out < 0) ? -1 : 0;
return -1;
return 0;
} }
} }
return -1; return -1;

View File

@@ -56,7 +56,7 @@ u32 splitargs(char* in) {
argv = calloc(count + 1, sizeof(char*)); argv = calloc(count + 1, sizeof(char*));
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
argv[i] = calloc(128, sizeof(char)); argv[i] = calloc(96, sizeof(char));
for (i = 0; i < len && curcount < count; i++) { for (i = 0; i < len && curcount < count; i++) {
@@ -64,13 +64,14 @@ u32 splitargs(char* in) {
curcount++; curcount++;
current = 0; current = 0;
} }
else if (in[i] == '@' || in[i] == '$' || in[i] == '?') { else if (in[i] == '@' || in[i] == '$') {
while (in[i] != ',' && in[i] != ' ' && in[i] != ')' && i < len) { while (strrchr(", )", in[i]) == NULL && i < len) {
argv[curcount][current++] = in[i++]; argv[curcount][current++] = in[i++];
} }
i--; i--;
} }
else if (in[i] >= '0' && in[i] <= '9') //else if ((in[i] >= '0' && in[i] <= '9') || (in[i] >= '<' && in[i] <= '>') || in[i] == '+' || in[i] == '-' || in[i] == '*' || in[i] == '/')
else if (strrchr("0123456789<=>+-*/", in[i]) != NULL)
argv[curcount][current++] = in[i]; argv[curcount][current++] = in[i];
else if (in[i] == '"') { else if (in[i] == '"') {
i++; i++;
@@ -201,6 +202,7 @@ void mainparser(){
getnextvalidchar(); getnextvalidchar();
} }
/*
if (currentchar == '?'){ if (currentchar == '?'){
char *jumpname; char *jumpname;
jumpname = readtilchar(';', ' '); jumpname = readtilchar(';', ' ');
@@ -209,6 +211,7 @@ void mainparser(){
getfollowingchar('\n'); getfollowingchar('\n');
return; return;
} }
*/
functionparser(); functionparser();
@@ -285,9 +288,6 @@ void runScript(char *path){
//add builtin vars //add builtin vars
str_int_add("@EMUMMC", emu_cfg.enabled); str_int_add("@EMUMMC", emu_cfg.enabled);
str_int_add("@RESULT", 0); str_int_add("@RESULT", 0);
str_int_add("@BTN_POWER", 0);
str_int_add("@BTN_VOL+", 0);
str_int_add("@BTN_VOL-", 0);
str_str_add("$CURRENTPATH", currentpath); str_str_add("$CURRENTPATH", currentpath);
//str_int_printall(); //str_int_printall();
@@ -301,7 +301,7 @@ void runScript(char *path){
f_close(&scriptin); f_close(&scriptin);
str_int_clear(); str_int_clear();
str_jmp_clear(); //str_jmp_clear();
str_str_clear(); str_str_clear();
free(path_local); free(path_local);
//btn_wait(); //btn_wait();

Some files were not shown because too many files have changed in this diff Show More